James Bryant

【转】嵌入式:UCOSIII的使用

0
阅读(1917)

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 函数里创建一个开始任务

intmain(void)

{

OS_ERR err;

CPU_SR_ALLOC();

初始化外设

OSInit(&err);//初始化UCOSIII

OS_CRITICAL_ENTER();   //进入临界区

OSTaskCreate();      //创建开始任务

OS_CRITICAL_EXIT();    //退出临界区

OSStart(&err);      //开启UCOSIII

while(1);

}

1-2、开始任务里,创建我们要运行的多个任务

voidstart_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];     //任务堆栈

voidstart_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];

voidTask0Task(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];

voidTask1Task(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,里面填写你要的功能。

voidApp_OS_IdleTaskHook (void)

{

staticintnum ;

num++;//计算运行了多少次空闲任务

}

5、软件定时器

5-1、软件定时器创建

//==============定时器结构体、函数声明==============

OS_TMR Timer0;

voidtimer0CallBack(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、定时器“中断服务函数”,回调函数

voidtimer0CallBack(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的内存管理机制,直接去内存数组里找到地址。

Baidu
map