淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 《手把手教你学STM32-UCOS》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 开源电子网 公众平台:“正点原子” 官方网站:www.alientek.com 联系电话:13922348612 ddddd ALIENTEK 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 《手把手教你学STM32-UCOS》 UCOSIII任务管理(中) 适用平台 STM32F1xx 开发板 (正点原子) STM32F4xx 开发板 (正点原子) ddddd 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 目录 UCOSIII任务堆栈 1 UCOSIII任务控制块 2 UCOSIII任务就绪表 3 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
UCOSIII任务管理 参考资料: 战舰/精英/Mini STM32/STM32F4开发板 《STM32F4 UCOS开发手册》-第五章 UCOSIII任务管理 《STM32F1 UCOS开发手册》-第五章 UCOSIII任务管理 www.themegallery.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 1、UCOSIII任务堆栈 1.1、任务堆栈的创建: 任务堆栈是任务的重要部分,堆栈是在RAM中按照“先进先出(FIFO)”的原则组织的一块连续的存储空间。为了满足任务切换和响应中断时保存CPU寄存器中的内容及任务调用其它函数时的需要,每个任务都应该有自己的堆栈。 任务堆栈创建很简单: #define START_STK_SIZE 512 //堆栈大小 CPU_STK START_TASK_STK[START_STK_SIZE]; //定义一个数组来作为任务堆栈 任务堆栈的大小是多少呢? CPU_STK为CPU_INT32U类型,也就是unsigned int类型,为4字节的,那么任务堆栈START_TASK_STK的大小就为:512 X 4=2048字节! 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 1、UCOSIII任务堆栈 1.2、任务堆栈初始化: 任务如何才能切换回上一个任务并且还能接着从上次被中断的地方开始运行?恢复现场即可,现场就是CPU的内部各个寄存器。因此在创建一个新任务时,必须把系统启动这个任务时所需的CPU各个寄存器初始值事先存放在任务堆栈中。这样当任务获得CPU使用权时,就把任务堆栈的内容复制到CPU的各个寄存器,从而可以任务顺利地启动并运行。 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 1、UCOSIII任务堆栈 1.2、任务堆栈初始化: 把任务初始数据存放到任务堆栈的工作就叫做任务堆栈的初始化,UCOSIII提供了完成堆栈初始化的函数:OSTaskStkInit()。 CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task, void *p_arg, CPU_STK *p_stk_base, CPU_STK *p_stk_limit, CPU_STK_SIZE stk_size, OS_OPT opt) 用户一般不会直接操作堆栈初始化函数,任务堆栈初始化函数由任务创建函数OSTaskCreate()调用。不同的CPU对于的寄存器和对堆栈的操作方式不同,因此在移植UCOSIII的时候需要用户根据各自所选的CPU来编写任务堆栈初始化函数。 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
1、UCOSIII任务堆栈 1.3、怎么使用创建的任务堆栈? 前面我们创建了一个任务堆栈,怎么使用这个任务堆栈? 作为任务创建函数OSTaskCreate()的参数,函数OSTaskCreate()如下: void OSTaskCreate (OS_TCB *p_tcb, CPU_CHAR *p_name, OS_TASK_PTR p_task, void *p_arg, OS_PRIO prio, CPU_STK *p_stk_base, //任务堆栈基地址 CPU_STK_SIZE stk_limit, //任务堆栈栈深 CPU_STK_SIZE stk_size, //任务堆栈大小 OS_MSG_QTY q_size, OS_TICK time_quanta, void *p_ext, OS_OPT opt, OS_ERR *p_err)
1、UCOSIII任务堆栈 1.4、堆栈增长方式: 函数OSTaskCreate()中的参数p_stk_base如何确定? 根据堆栈的增长方式,堆栈有两种增长方式: 向上增长:堆栈的增长方向从低地址向高地址增长。 向下增长:堆栈的增长方向从高地址向低地址增长。 函数OSTaskCreate()中的参数p_stk_base是任务堆栈基地址,那么如果CPU的堆栈是向上增长的话那么基地址就&START_TASK_STK[0],如果CPU堆栈是向下增长的话基地址就是&START_TASK_STK[START_STK_SIZE-1]STM32的堆栈是向下增长的!
2、UCOSIII任务控制块 2.1、任务控制块结构: 任务控制块是用来记录与任务相关的信息的数据结构,每个任务都要有自己的任务控制块。任务控制块由用户自行创建,如下代码为创建一个任务控制块: OS_TCB StartTaskTCB; //创建一个任务控制块 OS_TCB为一个结构体,描述了任务控制块,任务控制块中的成员变量用户不能直接访问,更不可能改变他们。 OS_TCB为一个结构体,其中有些成员采用了条件编译的方式来确定
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 2、UCOSIII任务控制块 struct os_tcb { CPU_STK *StkPtr; void *ExtPtr; CPU_STK *StkLimitPtr OS_TCB *NextPtr; OS_TCB *Prev …… //此处省略N个成员变量 #if OS_CFG_DBG_EN > 0u OS_TCB *DbgPrevPtr; OS_TCB *DbgNextPtr; CPU_CHAR *DbgNamePtr; #endif } 2.2、任务控制块初始化: 函数OSTaskCreate()在创建任务的时候会对任务的任务控制块进行初始化。 函数OS_TaskInitTCB()用与初始化任务控制块。用户不需要自行初始化任务控制块。 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 3、UCOSIII任务就绪表 3.1、优先级: UCOSIII中任务优先级数由宏OS_CFG_PRIO_MAX来配置,UCOSIII中数值越小,优先级越高,最低可用优先级就是OS_CFG_PRIO_MAX-1。 3.2、就绪表: UCOSIII中就绪表由2部分组成: 1、优先级位映射表OSPrioTbl[]:用来记录哪个优先级下有任务就绪。 2、就绪任务列表OSRdyList[]:用来记录每一个优先级下所有就绪的任务。 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 3、UCOSIII任务就绪表 OSPrioTbl[]在os_prio.c中有定义: CPU_DATA OSPrioTbl[OS_PRIO_TBL_SIZE]; 在STM32中CPU_DATA为unsigned int,有4个字节,32位。因此表OSPrioTbl每个参数有32位,其中每个位对应一个优先级。 OS_PRIO_TBL_SIZE=((OS_CFG_PRIO_MAX - 1u) / DEF_INT_CPU_NBR_BITS)+ 1) OS_CFG_PRIO_MAX由用户自行定义,默认为64。 DEF_INT_CPU_NBR_BITS= CPU_CFG_DATA_SIZE * DEF_OCTET_NBR_BITS CPU_CFG_DATA_SIZE=CPU_WORD_SIZE_32=4。 DEF_OCTET_NBR_BITS=8。 所以,当系统有64个优先级的时候: OS_PRIO_TBL_SIZE=((64-1)/(4*8)+1)=2。 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 3、UCOSIII任务就绪表 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 3、UCOSIII任务就绪表 如何找到已经就绪了的最高优先级的任务? 函数OS_PrioGetHighest()用于找到就绪了的最高优先级的任务 OS_PRIO OS_PrioGetHighest (void) { CPU_DATA *p_tbl; OS_PRIO prio; prio = (OS_PRIO)0; p_tbl = &OSPrioTbl[0]; while (*p_tbl == (CPU_DATA)0) { prio += DEF_INT_CPU_NBR_BITS; p_tbl++; } prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); return (prio); 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 3、UCOSIII任务就绪表 就绪任务列表: 通过上一步我们已经知道了哪个优先级的任务已经就绪了,但是UCOSIII支持时间片轮转调度,同一个优先级下可以有多个任务,因此我们还需要在确定是优先级下的哪个任务就绪了 struct os_rdy_list { OS_TCB *HeadPtr //用于创建链表,指向链表头 OS_TCB *TailPtr; //用于创建链表,指向链表尾 OS_OBJ_QTY NbrEntries; //此优先级下的任务数量 }; 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 3、UCOSIII任务就绪表 同一优先级下如果有多个 任务的话最先运行的永远是 HeadPtr所指向的任务! 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com
淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 谢谢您对“正点原子”团队的支持 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com 淘宝店铺:http://eboard.taobao.com 技术论坛:www.openedv.com