【转】嵌入式:UCOSIII的使用
0赞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的内存管理机制,直接去内存数组里找到地址。