历史上的今天
返回首页

历史上的今天

今天是:2025年04月25日(星期五)

正在发生

2019年04月25日 | UCOSIII任务堆栈、控制块及就绪表

2019-04-25 来源:eefocus

一、UCOSIII任务堆栈


1、任务堆栈的创建


堆栈是在RAM中按照“先进先出(FIFO)”的原则组织的一块连续的存储空间。为了满足任务切换和响应中断时保存CPU寄存器中的内容及任务调用其它函数时的需要,每个任务都应该有自己的堆栈。


如何创建?


#define START_STK_SIZE           512  //堆栈大小


CPU_STK START_TASK_STK[START_STK_SIZE];   //定义一个数组来作为任务堆栈


可查看main.c的29行,跳转可知堆栈大小:


CPU_STK为CPU_INT32U类型,也就是unsigned int类型,为4字节的,那么任务堆栈START_TASK_STK的大小就为:512 X 4=2048字节!


2、任务堆栈的初始化


任务如何才能切换回上一个任务并且还能接着从上次被中断的地方开始运行?


恢复现场即可,现场就是CPU的内部各个寄存器。因此在创建一个新任务时,必须把系统启动这个任务时所需的CPU各个寄存器初始值事先存放在任务堆栈中。这样当任务获得CPU使用权时,就把任务堆栈的内容复制到CPU的各个寄存器,从而可以任务顺利地启动并运行。


把任务初始数据存放到任务堆栈的工作就叫做任务堆栈的初始化,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来编写任务堆栈初始化函数。


可查看UCOSIII_PORT中的os_cpu_c.c中227行


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,    //任务堆栈基地址 一般0

                    CPU_STK_SIZE   stk_limit,   //任务堆栈栈深 一般堆栈大小/10

                    CPU_STK_SIZE   stk_size,    //任务堆栈大小            前面创建的

                    OS_MSG_QTY   q_size,

                    OS_TICK        time_quanta,

                    void           *p_ext,      //用户补充的存储区

                    OS_OPT        opt,

                    OS_ERR        *p_err)      //存放该函数错误时的返回值

可查看main.c中79行的任务开始函数


4、堆栈增长方式


函数OSTaskCreate()中的参数p_stk_base如何确定?


根据堆栈的增长方式,堆栈有两种增长方式:


向上增长:堆栈的增长方向从低地址向高地址增长。


向下增长:堆栈的增长方向从高地址向低地址增长。


函数OSTaskCreate()中的参数p_stk_base是任务堆栈基地址,那么如果CPU的堆栈是向上增长的话那么基地址就&START_TASK_STK[0],如果CPU堆栈是向下增长的话基地址就是&START_TASK_STK[START_STK_SIZE-1]STM32的堆栈是向下增长的!


二、UCOSIII任务控制块


1、任务控制块结构


任务控制块是用来记录与任务相关的信息的数据结构,每个任务都要有自己的任务控制块。任务控制块由用户自行创建,如下代码为创建一个任务控制块:


OS_TCB StartTaskTCB;  //创建一个任务控制块


OS_TCB为一个结构体,描述了任务控制块,任务控制块中的成员变量用户不能直接访问,更不可能改变他们。


OS_TCB为一个结构体,其中有些成员采用了条件编译的方式来确定


struct os_tcb

 

{

 

    CPU_STK             *StkPtr;  //指向当前任务堆栈栈顶                         

 

    void                *ExtPtr; //指向用户可定义的数据取                           

 

    CPU_STK             *StkLimitPtr;//可指向任务堆栈中的某个位置

 

    OS_TCB              *NextPtr; //NexPtr和PrevPtr用于在任务就绪表建立OS_TCB

 

    OS_TCB              *Prev

 

    ……                              //此处省略N个成员变量

 

 #if OS_CFG_DBG_EN > 0u

 

    OS_TCB              *DbgPrevPtr;//下面三个成员变量用于调试

 

    OS_TCB              *DbgNextPtr;

 

    CPU_CHAR            *DbgNamePtr;

 

 #endif

 

}

可查看main.c中26行进行跳转,里面有很多的成员变量


2、任务控制块初始化


函数OSTaskCreate()在创建任务的时候会对任务的任务控制块进行初始化。


函数OS_TaskInitTCB()用与初始化任务控制块。用户不需要自行初始化任务控制块。


可查看os_task.c中341行


三、UCOSIII任务就绪表


1、优先级:


UCOSIII中任务优先级数由宏OS_CFG_PRIO_MAX来配置,UCOSIII中数值越小,优先级越高,最低可用优先级就是OS_CFG_PRIO_MAX-1。


可查看UCOSIII_CONFIG中os_cfg.c中47行


2、就绪表


    UCOSIII中就绪表由2部分组成:


    1、优先级位映射表OSPrioTbl[]:用来记录哪个优先级下有任务就绪。


    2、就绪任务列表OSRdyList[]:用来记录每一个优先级下所有就绪的任务。


OSPrioTbl[]在os_prio.c中有定义:


CPU_DATA   OSPrioTbl[OS_PRIO_TBL_SIZE]; //UCOSIII_CORE中os_prio.c中41行


跳转可知:


在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。


2.1、如何找到已经就绪了的最高优先级的任务?


函数OS_PrioGetHighest()用于找到就绪了的最高优先级的任务:源码在UCOSIII_CORE中os_prio.c中85行


OS_PRIO  OS_PrioGetHighest (void)

 

{

 

    CPU_DATA  *p_tbl;

 

    OS_PRIO    prio;

 

    prio  = (OS_PRIO)0;

 

    p_tbl = &OSPrioTbl[0];//从OSProTb[0]开始扫描映射表,一直遇到非零项

 

while (*p_tbl == (CPU_DATA)0) {

 

//当数组OSProTb[]中某个元素为0时,就继续扫描下一个素组元素,prio加DEF_INT_CPU_NBR_BITS位

 

       prio += DEF_INT_CPU_NBR_BITS;

 

       p_tbl++;// p_tbl加一,继续寻找OSProTb[]中下一个元素

 

}

 

//一旦找到一个非0项,再加上该项的前导0数量就找到了最高优先级任务了

 

    prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); //计算前导0:计算0的个数

 

    return (prio);

2.2就绪任务列表


通过上一步我们已经知道了哪个优先级的任务已经就绪了,但是UCOSIII支持时间片轮转调度,同一个优先级下可以有多个任务,因此我们还需要在确定是优先级下的哪个任务就绪了


struct  os_rdy_list {

 

    OS_TCB           *HeadPtr    //用于创建链表,指向链表头

 

    OS_TCB           *TailPtr;   //用于创建链表,指向链表尾

 

    OS_OBJ_QTY       NbrEntries; //此优先级下的任务数量

 

};     //全局变量查找:在os.h中1184行  

     

同一优先级下如果有多个任务的话,最先运行的永远是HeadPtr所指向的任务!达到左右任务轮询执行。


UCOSIII内部使用的几个函数:

推荐阅读

史海拾趣

海芯科技(AVIA)公司的发展小趣事

随着公司业务的不断拓展和市场份额的逐步扩大,海芯科技开始注重品牌建设和市场推广。公司积极参加各类行业展会和交流活动,与业内同行和客户进行深入交流和合作。同时,公司还加大了对品牌形象的宣传力度,通过广告、宣传册等多种方式提升品牌知名度和美誉度。这些举措不仅提升了公司的市场影响力,也为公司的长期发展奠定了坚实的基础。

ACP Optoelectronic Technology Co Ltd公司的发展小趣事

为了进一步提升技术实力和市场份额,ACP Optoelectronic Technology Co Ltd积极寻求与其他企业的战略合作。公司先后与多家知名电子企业签订了技术合作协议,共同开发新产品,共享市场资源。这些合作不仅提升了ACP Optoelectronic Technology Co Ltd的技术水平,也为其带来了更多的商业机会,推动了公司的快速发展。

Anachip公司的发展小趣事

品质一直是Anachip公司非常重视的一环。为了确保产品的稳定性和可靠性,公司建立了严格的品质管理体系,从原材料采购到生产过程的每一个环节都进行严格控制。同时,公司还加大了品牌建设的力度,通过广告宣传、赞助活动等方式提升品牌知名度。这些举措不仅提升了公司的市场竞争力,也赢得了客户的信任和忠诚。

Hoffman_Enclosures__Inc.公司的发展小趣事

Hoffman在追求企业发展的同时,也积极履行社会责任,致力于实现可持续发展。公司注重环保和节能,不断推出绿色、低碳的产品和技术。同时,Hoffman还积极参与公益事业,通过捐款、志愿服务等多种方式回馈社会。这些举措不仅提升了公司的社会形象,也促进了企业与社会的和谐共生。

以上五个故事展示了Hoffman Enclosures, Inc.在电子行业中的发展历程和关键节点,每个故事都体现了公司在技术创新、市场拓展、产品定制、标准制定以及社会责任等方面的努力和成就。

Chip Quik公司的发展小趣事

随着市场的反馈和技术的不断进步,Chip Quik公司对初始产品进行了多次优化。公司不断改进焊接材料的性能,提高焊接速度和稳定性,同时降低操作难度。这些改进使得Chip Quik的产品在电子维修领域获得了更广泛的应用,公司也逐渐扩大了市场份额。

泰科天润(GPT)公司的发展小趣事

在不断发展壮大的过程中,Chip Quik公司始终注重品牌建设和持续创新。公司加大了对研发部门的投入,不断推出新技术和新产品,以满足市场的不断变化。同时,公司还通过加强品牌宣传和推广,提高了品牌知名度和美誉度,为公司的长远发展奠定了坚实的基础。

这些故事虽然基于假设和一般性的行业趋势,但它们可以反映出一家电子行业中类似公司可能经历的发展路径和挑战。希望这些故事能够为您了解Chip Quik公司或其他电子行业公司的发展提供一定的参考。

问答坊 | AI 解惑

synopsys电路模拟工具manual

介绍nanosim和hspice两个工具的语法等的手册。英文版。…

查看全部问答>

tsb41

嘿嘿,这个压缩包怎么打不开呢,麻烦大家帮帮忙…

查看全部问答>

刚毕业新人请教...

最近公司入库一批芯片,其中有IDT7202芯片 我个人觉得有些旧 芯片上面打字为:IDT7202                             LA15SO      & ...…

查看全部问答>

who 有格州电子杯的竞赛题啊

本帖最后由 paulhyde 于 2014-9-15 09:30 编辑 who 有格州电子杯的竞赛题啊,因为可以从中窥出NEC的出题意图,可以拿来练练手!  …

查看全部问答>

求教:请给一个晶体管的详细结构图解

本帖最后由 paulhyde 于 2014-9-15 08:58 编辑 因为我正在学习计算机接口技术要学逻辑电路,请高手给发一个典型的晶体管构成讲解上来,要详细一些的,感激不尽!、  …

查看全部问答>

全自动多用途应急灯

当夜晚来临时,你正在灯下工作学习时,突然停电了,周围一片漆黑,你一定会不知所措。只能在黑暗中摸索着寻找蜡烛、手电,非常不方便。还有一些特殊的场所如:宾馆、饭店或地下室人员流动密集,受建筑物结构的限制,在白天也需要人工照明,如果突然 ...…

查看全部问答>

在交流固态继电器输出串一个整流二极管可用来控制直流电机

原先一直担心这种接法不能用:交流固态继电器(非增强型)是双向可控硅输出的,串上一个二极管后输出原理上是输出脉动的直流(半波),原理上相当与单向可控硅输出的方式,因为没实际做实验,所以老感觉有什么地方不踏实,今天我用电灯炮做负载,用 ...…

查看全部问答>

protel生成的pdf原理图查找不准确

各位,用protel生成了一个pdf格式的原理图,然后在pdf里面,我想去查引脚之间相连的情况,比如输入R1,但找到的却不是R1,而是SI03,SIO1,2,1,之类的,我用全字匹配去查,也是查到SIO3,SIO1,这样一来我看原理图就很不方便了,有没有哪位也碰到 ...…

查看全部问答>

CPropertySheet 能嵌入到FormView中呢?(evc下)

我在vc中添加如下代码就可以实现嵌入式到FormView中~~         CPropertySheet *m_sheet1=new CPropertySheet;         CPropertyPage *m_page1 = new CPropertyPage;         m_p ...…

查看全部问答>

寻求14位A/D转换的单片机

寻求带14位A/D转换的单片机,请大家推荐,谢谢 要求价位合理。…

查看全部问答>