嵌入式:UCOSIII的使用(17.01.24补充)
0、一些移植、系统相关
OS_CFG_APP.H
/* --------------------- MISCELLANEOUS ------------------ */ #define OS_CFG_MSG_POOL_SIZE 100u /* 消息池 大小 */ #define OS_CFG_ISR_STK_SIZE 128u /* Stack size of ISR stack (number of CPU_STK elements) */ #define OS_CFG_TASK_STK_LIMIT_PCT_EMPTY 10u /* Stack limit position in percentage to empty */ /* ---------------------- IDLE TASK --------------------- */ #define OS_CFG_IDLE_TASK_STK_SIZE 128u /* 空闲任务 堆栈空间大小 (一般不做修改) */ /* ------------------ ISR HANDLER TASK ------------------ */ #define OS_CFG_INT_Q_SIZE 10u /* 中断服务队列 大小 */ #define OS_CFG_INT_Q_TASK_STK_SIZE 128u /* 中断服务队列 堆栈空间大小(一般不做修改) */ /* ------------------- STATISTIC TASK ------------------- */ #define OS_CFG_STAT_TASK_PRIO (OS_CFG_PRIO_MAX-2u) /* 统计任务 优先级 (一般不做修改) */ #define OS_CFG_STAT_TASK_RATE_HZ 10u /* 统计任务频率 (1 to 10 Hz) */ #define OS_CFG_STAT_TASK_STK_SIZE 128u /* 统计任务 堆栈空间大小 (一般不做修改) */ /* ------------------------ TICKS ----------------------- */ #define OS_CFG_TICK_RATE_HZ 200u /* 时钟节拍频率 200HZ = 5ms (10 to 1000 Hz) */ #define OS_CFG_TICK_TASK_PRIO 1u /* 时钟节拍优先级,一般设置一个相对较高的优先级 */ #define OS_CFG_TICK_TASK_STK_SIZE 128u /* 时钟节拍堆栈空间大小 (一般不做修改) */ #define OS_CFG_TICK_WHEEL_SIZE 17u /* Number of 'spokes' in tick wheel; SHOULD be prime */ /* ----------------------- TIMERS ----------------------- */ #define OS_CFG_TMR_TASK_PRIO 2u /* 软件定时器优先级 */ #define OS_CFG_TMR_TASK_RATE_HZ 100u /* 软件定时器频率 100HZ = 10ms,不能小于心跳时钟节拍 */ #define OS_CFG_TMR_TASK_STK_SIZE 128u /* 软件定时器堆栈空间大小 (一般不做修改) */ #define OS_CFG_TMR_WHEEL_SIZE 17u /* Number of 'spokes' in timer wheel; SHOULD be prime */
OS_CFG.H:功能性裁剪
OS_APP_HOOKS.C:钩子函数
OS_CPU_A.ASM:PendSV中断、任务切换
OS_CPU_C.C: OSTaskStkInit函数,任务创建时,对堆栈初始化,寄存器地址要参照手册
1、框架写法(个人习惯相关)
1-1、main 函数里创建一个开始任务
int main(void) { OS_ERR err; CPU_SR_ALLOC(); 初始化外设 OSInit(&err); //初始化UCOSIII OS_CRITICAL_ENTER(); //进入临界区 OSTaskCreate(); //创建开始任务 OS_CRITICAL_EXIT(); //退出临界区 OSStart(&err); //开启UCOSIII while(1); }
1-2、开始任务里,创建我们要运行的多个任务
void start_task(void *p_arg) { OS_ERR err; CPU_SR_ALLOC(); p_arg = p_arg; CPU_Init(); #if OS_CFG_STAT_TASK_EN > 0u //统计任务 OSStatTaskCPUUsageInit(&err); #endif #ifdef CPU_CFG_INT_DIS_MEAS_EN //测量中断关闭时间 CPU_IntDisMeasMaxCurReset(); #endif #if OS_CFG_SCHED_ROUND_ROBIN_EN //时间片轮转 OSSchedRoundRobinCfg(DEF_ENABLED,1,&err); //时间片长度为1个系统时钟节拍,既1*5=5ms #endif OS_CRITICAL_ENTER(); //进入临界区 OSTaskCreate(); //创建任务 1 OSTaskCreate(); //创建任务 2 OSTaskCreate(); //创建任务 3 OS_CRITICAL_EXIT(); //进入临界区 OSTaskDel((OS_TCB*)0,&err); //删除start_task任务自身 }
2、任务创建、挂起、删除
2-1、任务创建
//==================任务创建宏定义,便于修改================== #define START_TASK_PRIO 3 //任务优先级 #define START_STK_SIZE 128 //任务堆栈大小 OS_TCB StartTaskTCB; //任务控制块 CPU_STK START_TASK_STK[START_STK_SIZE]; //任务堆栈 void start_task(void *p_arg); //任务函数 //==================任务创建函数================== OSTaskCreate((OS_TCB * )&StartTaskTCB, //任务 控制块 (CPU_CHAR * )"start task", //任务 名字 (OS_TASK_PTR )start_task, //任务 函数 (void * )0, //任务 任务函数的参数 (OS_PRIO )START_TASK_PRIO, //任务 优先级 (CPU_STK * )&START_TASK_STK[0], //任务 堆栈基地址 (CPU_STK_SIZE)START_STK_SIZE/10, //任务 堆栈深度限位 (CPU_STK_SIZE)START_STK_SIZE, //任务 堆栈大小 (OS_MSG_QTY )0, //任务 内部消息队列能够接收的最大消息数目,为0时禁止接收消息 (OS_TICK )0, //任务 使用时间片轮转,时间片长度,为0时为默认长度, (void *)0, //任务 用户补充的存储区 (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务 选项 (OS_ERR *)&err); //任务 创建成功与否
2-2、任务挂起
OSTaskSuspend((OS_TCB*)&Task1TaskTCB,&err); //挂起开始任务
2-3、任务解挂
OSTaskResume((OS_TCB*)&Task1TaskTCB,&err); //任务解挂
2-4、任务删除
OSTaskDel((OS_TCB*)0,&err); //删除start_task任务自身
3、时间片轮转
3-1、两个任务优先级相等
#define Task0_Task_Prio 4 //优先级4 #define Task0_Stk_Size 128 OS_TCB Task0TaskTCB; CPU_STK Task0_Task_Stk[Task0_Stk_Size]; void Task0Task(void *p_arg); #define Task1_Task_Prio 4 //优先级4 #define Task1_Stk_Size 128 OS_TCB Task1TaskTCB; CPU_STK Task1_Task_Stk[Task1_Stk_Size]; void Task1Task(void *p_arg);
3-2、使能轮转调度,调用API,设置单位时间
#if OS_CFG_SCHED_ROUND_ROBIN_EN //使用时间片轮转 OSSchedRoundRobinCfg(DEF_ENABLED,1,&err); //时间片长度为1个系统时钟节拍,既1*5=5ms #endif
3-3、创建任务时,设置任务的时间片大小
OSTaskCreate((OS_TCB * )&Task1TaskTCB, (CPU_CHAR * )"Task1 task", (OS_TASK_PTR )Task1Task, (void * )0, (OS_PRIO )Task1_Task_Prio, (CPU_STK * )&Task1_Task_Stk[0], (CPU_STK_SIZE)Task1_Stk_Size/10, (CPU_STK_SIZE)Task1_Stk_Size, (OS_MSG_QTY )0, (OS_TICK )2, //时间片长度为2*5=10ms (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err);
4、钩子函数。函数指针,UCOS不希望我们去修改他的文件,弄了钩子函数,比如 App_OS_IdleTaskHook ,在空闲时运行这个函数,功能自己填写。
4-1、使能钩子函数功能,并设置所有函数指针
#if OS_CFG_APP_HOOKS_EN > 0u //使能钩子函数 App_OS_SetAllHooks(); #endif
4-2、在 os_app_hooks.c 里的 App_OS_*Hook,里面填写你要的功能。
void App_OS_IdleTaskHook (void) { static int num ; num++; //计算运行了多少次空闲任务 }
5、软件定时器
5-1、软件定时器创建
//==============定时器结构体、函数声明============== OS_TMR Timer0; void timer0CallBack(void *p_tmr, void *p_arg); //==============定时器创建============== //创建定时器0任务 OSTmrCreate ( (OS_TMR *)&Timer0, //定时器 结构体 (CPU_CHAR *)"time0", //定时器 名字 (OS_TICK )10, //定时器 初次延时节拍 10*10 = 100ms (OS_TICK )100, //定时器 以后延时节拍 100*10 = 1000ms = 1s (OS_OPT )OS_OPT_TMR_PERIODIC, //定时器 选项 : 单次 或 周期。 (OS_TMR_CALLBACK_PTR )timer0CallBack, //定时器 回调函数,伪中断服务函数 (void *)0, //定时器 中断服务函数的参数 (OS_ERR *)&err); //定时器 创建成功与否
5-2、定时器“中断服务函数”,回调函数
void timer0CallBack(void *p_tmr, void *p_arg) { //do something }
6、信号量
6-1、信号量创建
OSSemCreate ( (OS_SEM *)&mySem, //信号量 结构体 (CPU_CHAR *)"semtest", //信号量 名字 (OS_SEM_CTR )1, //信号量 初始值, (OS_ERR *)&err); //信号量 创建成功是否
6-2、信号量等待
OSSemPend ((OS_SEM *)&mySem, //信号量 结构体 (OS_TICK )0, //信号量 等待超时时间 (OS_OPT )OS_OPT_PEND_BLOCKING, //信号量 阻塞 或 不阻塞 (CPU_TS *)0, //信号量 时间戳 (OS_ERR *)&err); //信号量 等待错误
6-3、信号量发送
OSSemPost ((OS_SEM *)&mySem, //信号量 结构体 (OS_OPT )OS_OPT_POST_1, //信号量 给就绪最高优先级 (OS_ERR *)&err); //信号量 等待错误
用途: 1、访问共享资源。
2、中断发送信号,让处理在任务。
7、任务内建信号量
7-1、等待自身的信号量
OSTaskSemPend ( (OS_TICK )0, //内建信号量 超时时间 (OS_OPT )OS_OPT_PEND_BLOCKING, //内建信号量 阻塞 或 不阻塞 (CPU_TS *)0, //内建信号量 时间戳 (OS_ERR *)&err); //内建信号量 等待错误
7-2、其他任务,给等待内建信号量的任务发送信号量
OSTaskSemPost ( (OS_TCB *)&Task0TaskTCB, //内建信号量 等待的任务 (OS_OPT )OS_OPT_POST_NONE, //内建信号量 调度 或 不调度 (OS_ERR *)&err); //内建信号量 等待错误
8、互斥信号量
8-1、互斥信号量创建
OSMutexCreate ( (OS_MUTEX *)&myMutex, //互斥信号量 结构体 (CPU_CHAR *)"Mutextest", //互斥信号量 名字 (OS_ERR *)err); //互斥信号量 创建错误
8-2、互斥信号量等待
OSMutexPend ( (OS_MUTEX *)&myMutex, //互斥信号量 结构体 (OS_TICK )0, //互斥信号量 等待超时时间 (OS_OPT )OS_OPT_PEND_BLOCKING, //互斥信号量 阻塞 或 不阻塞 (CPU_TS *)0, //互斥信号量 时间戳 (OS_ERR *)&err); //互斥信号量 等待错误
8-3、互斥信号量发送
OSMutexPost ( (OS_MUTEX *)&myMutex, //互斥信号量 结构体 (OS_OPT )OS_OPT_POST_NONE, //互斥信号量 调度 或 不调度 (OS_ERR *)&err); //互斥信号量 发送错误
用途:防止优先级反转,如:2个任务共享一个资源,而,两者的优先级,中间隔着多个优先级(任务)。高优先级 等待 低优先级 释放,而,低优先级 此时又被 中等优先级 打断,变成 高优先级 要等 中等优先级。
用互斥信号的话,此时 低优先级 ,会暂时提高到共享资源的 高优先级 级别。不会被中等优先级打算。处理完,降回 低优先级 ,高优先级接着访问。再 中等优先级。
发现:1、高优先级 等待时, 低优先级用OSSched(); 此时达到预计效果,不会被 中等优先级抢占。
2、高优先级 等待时,低优先级用OSTimeDlyHMSM();延时指令,此时,会被中等优先级抢占。
9、消息队列
9-1、消息队列创建
//================消息队列宏定义================ OS_Q my_MSG_Q; #define my_MSG_QTY (OS_MSG_QTY)5 //================消息队列创建================ OSQCreate ( (OS_Q *)&my_MSG_Q, //消息队列 结构体 (CPU_CHAR *)"MSG_Q_Test", //消息队列 名字 (OS_MSG_QTY )my_MSG_QTY, //消息队列 大小 (OS_ERR *)&err); //消息队列 创建错误
9-2、消息发送
u8 *MSG = (u8 *)"testtet"; OSQPost ( (OS_Q *)&my_MSG_Q, //消息队列 结构体 (void *)MSG, //消息队列 发送的消息 (OS_MSG_SIZE )8, //消息队列 发送的消息大小 (OS_OPT )OS_OPT_POST_FIFO, //消息队列 发送方式,普通FIFO,紧急LIFO,及发送给所有等待该消息、发送调度与否 (OS_ERR *)&err); //消息队列 发送错误
9-3、消息接收
u8 *MSG; u8 Q_size; MSG = OSQPend ( (OS_Q *)&my_MSG_Q, //消息队列 结构体 (OS_TICK )0, //消息队列 等待超时 (OS_OPT )OS_OPT_PEND_BLOCKING, //消息队列 阻塞 或 不阻塞 (OS_MSG_SIZE *)&Q_size, //消息队列 收到的大小 (CPU_TS *)0, //消息队列 时间戳 (OS_ERR *)&err); //消息队列 接收错误
10、任务内建消息队列
10-1、内建消息队列发送
u8 *MSG = (u8 *)"testtet"; OSTaskQPost ( (OS_TCB *)&MSG_Q_TaskTCB, //内建消息队列 接收的任务 (void *)MSG, //内建消息队列 发送的消息 (OS_MSG_SIZE )8, //内建消息队列 发送的消息大小 (OS_OPT )OS_OPT_POST_FIFO, //内建消息队列 发送方式,普通FIFO,紧急LIFO,及发送给所有等待该消息、发送调度与否 (OS_ERR *)&err); //内建消息队列 发送错误
10-2、内建消息队列接收
u8 *MSG; u8 Q_size; MSG = OSTaskQPend ( (OS_TICK )0, //内建消息队列 等待超时 (OS_OPT )OS_OPT_PEND_BLOCKING, //内建消息队列 阻塞 或 不阻塞 (OS_MSG_SIZE *)&Q_size, //内建消息队列 收到的大小 (CPU_TS *)0, //内建消息队列 时间戳 (OS_ERR *)&err); //内建消息队列 接收错误
11、标记位组
11-1、标记位组创建
OS_FLAG_GRP my_FLAG; #define FLAG_INIT 0x00 #define FLAG_BIT0 0x01 #define FLAG_BIT1 0x02 OSFlagCreate ( (OS_FLAG_GRP *)&my_FLAG, //标记位组 结构体 (CPU_CHAR *)"Flag test", //标记位组 名字 (OS_FLAGS )FLAG_INIT, //标记位组 标记初始值 (OS_ERR *)&err); //标记位组 创建成功与否
11-2、标记位组发送
OSFlagPost ((OS_FLAG_GRP *)&my_FLAG, //标记位组 结构体 (OS_FLAGS )FLAG_BIT0, //标记位组 bit0 (OS_OPT )OS_OPT_POST_FLAG_SET, //标记位组 置1 (OS_ERR *)&err); //标记位组 bit0 置 1 成功与否
11-3、标记为组等待
OS_FLAGS index; index = OSFlagPend ((OS_FLAG_GRP *)&my_FLAG, //标记位组 结构体 (OS_FLAGS )FLAG_BIT0 | FLAG_BIT1, //标记位组 等待的BIT位 (OS_TICK )0, //标记位组 等待超时时间 (OS_OPT )OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_BLOCKING, //标记位组 任意1个Bit置1,接收后清0,阻塞 (CPU_TS *)0, //标记位组 时间戳 (OS_ERR *)&err); //标记位组 等待错误
12、多个内核对象
12-1、多个内核对象 创建
//=================多个内核对象 结构体================= OS_SEM my_Sem1; OS_SEM my_Sem2; OS_Q my_Q1; #define my_Q1_SIZE 5 //=================多个内核对象 创建================= OSSemCreate ( (OS_SEM *)&my_Sem1, (CPU_CHAR *)"sem1 test", (OS_SEM_CTR )0, (OS_ERR *)&err); OSSemCreate ( (OS_SEM *)&my_Sem2, (CPU_CHAR *)"sem2 test", (OS_SEM_CTR )0, (OS_ERR *)&err); OSQCreate ( (OS_Q *)&my_Q1, (CPU_CHAR *)"my_Q1", (OS_MSG_QTY )my_Q1_SIZE, (OS_ERR *)&err);
12-2、等待多个内核对象
//===============多个内核对象 宏定义=============== #define MY_OBJ_NUM 3 //多个内核对象 等待数量 //===============多个内核对象 等待=============== OS_PEND_DATA my_OBJ_data[MY_OBJ_NUM]; //多个内核对象 数组 my_OBJ_data[0].PendObjPtr = (OS_PEND_OBJ *)&my_Sem1; //多个内核对象 对象0 my_OBJ_data[1].PendObjPtr = (OS_PEND_OBJ *)&my_Sem2; //多个内核对象 对象1 my_OBJ_data[2].PendObjPtr = (OS_PEND_OBJ *)&my_Q1; //多个内核对象 对象2 my_return_data = OSPendMulti ( (OS_PEND_DATA *)my_OBJ_data, //多个内核对象 对象数组 (OS_OBJ_QTY )MY_OBJ_NUM, //多个内核对象 对象数量 (OS_TICK )0, //多个内核对象 等待超时时间 (OS_OPT )OS_OPT_PEND_BLOCKING, //多个内核对象 阻塞 或 不阻塞 (OS_ERR *)&err); //多个内核对象 等待错误
12-3、多个内核对象 发送
任意对象 post ,都会结束等待
13、内存管理
13-1、内存创建
//==================内存 宏定义================== OS_MEM IN_MEM; #define IN_MEM_Block 5 //必须大于2 #define IN_MEM_Zone 25 * 4 //必须大于4,且为4的倍数,存放下一块的地址内容,4字节 CPU_INT08U IN_MEM_DATA[IN_MEM_Block][IN_MEM_Zone]; //==================内存 创建================== OSMemCreate ( (OS_MEM *)&IN_MEM, //内存 结构体 (CPU_CHAR *)"IN_MEM", //内存 名字 (void *)&IN_MEM_DATA[0][0], //内存 基地址 (OS_MEM_QTY )IN_MEM_Block, //内存 几个块,一维数组 (OS_MEM_SIZE )IN_MEM_Zone, //内存 每个块大小,二维数组 (OS_ERR *)&error); //内存 创建成功与否
13-2、内存申请
u8 *p; p = OSMemGet ( (OS_MEM *)&IN_MEM, //内存 结构体 (OS_ERR *)&err); //内存 申请成功与否
13-3、内存释放
OSMemPut ( (OS_MEM *)&IN_MEM, //内存 结构体 (void *)p, //内存 要释放的地址 (OS_ERR *)&err); //内存 释放成功与否
备注:内存有申请,必释放,如果申请后,不释放,再申请,那之前申请的地址就找不到了,因为你的指针地址变了。
所以,如果要多次申请的话,1、还要弄个指针数组,2、或者普通数组来存放当前申请的地址,3、或者知道UCOS的内存管理机制,直接去内存数组里找到地址。
暂时就这样,以后再检查修改,手酸。
================================================ 17.01.24 补充================================================
1、中断处理
void xxx_Handler(void) //某中断服务函数 { OSIntEnter(); //进入中断 //中断处理 OSIntExit(); //触发任务切换软中断 }
2、临界段处理
OS_CRITICAL_ENTER(); //进入临界区 //不想被打断的时序任务、功能 OS_CRITICAL_EXIT(); //退出临界区
3、引起调度函数
3-1、延时
OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时1s,严格按照 60分60秒1000毫秒,进位。