单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:3891|回复:0
打印上一主题下一主题

UCOS任务调度实现原理

[复制链接]
跳转到指定楼层
楼主
ID:604224发表于 2021-1-17 17:15|只看该作者回帖奖励
0x00摘要
本文主要讲解ucos如何实现任务的调度,调度过程中主要涉及到的函数和知识点。
0x01引言
ucos是一种嵌入式实时多任务操作系统,其高度可靠性、鲁棒性和安全性,得到美国宇航局的认证。已经广泛使用在从照相机到航空电子产品的各种应用中。为了更好的了解UCOS的任务调度原理,本文从代码进行分析。
0x02原理
0x02-1
UCOS能实现任务调度是采用中断来实现,对于STM32其使用了SysTick定时器,用它来产生系统的时基,维持系统的“心跳”。对于SysTick定时器的初始化是在main函数中OS_CPU_SysTickInit()完成,它的代码如下:
void OS_CPU_SysTickInit (void)
{
   INT32U  cnts;
   cnts =OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC;
   OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);
   OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC |OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
   OS_CPU_CM3_NVIC_ST_CTRL  |=OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
}
这个函数主要是完成了SysTick计时器的初始化,首先利用OS_CPU_SysTickClkFreq()获取系统的频率,根据OS_TICKS_PER_SEC,也就是每秒钟的心跳数(中断次数),得到定时器需要设定的每次中断的计时数,最后调用相关的寄存器设置宏来初始化定时器。这些宏的具体定义大家可以通过源码直接查看(关注公众号,回复ucos即可获取,在keil下编译后在指定变量上右击查看定义即可)。
OS_CPU_SysTickClkFreq()函数主要获取硬件频率,代码如下:
INT32U OS_CPU_SysTickClkFreq (void)
{
   INT32U  freq;
   freq =BSP_CPU_ClkFreq();
   return(freq);
}
这里调用了BSP_CPU_ClkFreq()来获取频率,其代码为:
CPU_INT32U BSP_CPU_ClkFreq (void)
{
   RCC_ClocksTypeDef  rcc_clocks;
   RCC_GetClocksFreq(&rcc_clocks);
   return((CPU_INT32U)rcc_clocks.HCLK_Frequency);
}
RCC_GetClocksFreq(&rcc_clocks)这个函数是stm32固件库中的函数,具体代码大家可以看一下,它可以返回系统的硬件频率。
0x02-2
设定好定时器后,stm32便可以产生定时中断了,中断调用中断函数OS_CPU_SysTickHandler ()来实现任务的调度。其在verter.s中设定,这部分涉及到stm32硬件相关知识暂不讲解。代码如下
void OS_CPU_SysTickHandler (void)
{
   OS_CPU_SR  cpu_sr;
   OS_ENTER_CRITICAL();
   OSIntNesting++;
   OS_EXIT_CRITICAL();
   OSTimeTick();
   OSIntExit();
}
这里首先定义了一个OS_CPU_SR变量,用于接受PRIMASK中断屏蔽寄存器的值。然后调用OS_ENTER_CRITICAL()进入临界段,所谓临界段就是系统不希望被其他中断打扰(NMI和硬fault除外,具体功能大家查一下手册),然后将OSIntNesting(表示中断嵌套的层数)加1,执行完之后便退出临界段,临界段所处的时间越短越好,太长时间将会影响到其他中断的响应,对实时性不利,同样其他不希望被中断打扰一切操作都可以用这两个函数来进行控制。接着便调用OSTimeTick()和OSIntExit()完成这次任务调度,这两个函数下次讲解。
先看一下OS_ENTER_CRITICAL(),代码如下
#define OS_ENTER_CRITICAL()  {cpu_sr =OS_CPU_SR_Save();}
这是一个宏定义,调用了OS_CPU_SR_Save(),其是一个汇编程序,如下
OS_CPU_SR_Save
   MRS     R0, PRIMASK
   CPSID   I
   BX     LR
这里将PRIMASK存入R0,然后关闭总中断,跳回原来函数,这样就进入了临界段,不会有其他中断打扰。PRIMASK在手册中解释为这个寄存器只有一个位,置1后,将关闭所有可屏蔽中断的异常,只剩NMI和硬fault,默认值为0。
R0是什么,就是调用函数传进来的第一个参数,也就是cpu_sr。在汇编中R0~R3会依次接受传进来的不多于4个参数,再多的话建议采用指针或者堆栈。
OS_EXIT_CRITICAL(),代码如下
#define OS_EXIT_CRITICAL()  {OS_CPU_SR_Restore(cpu_sr);}
也是一个宏定义,和上述一样,OS_CPU_SR_Restore(cpu_sr)是一个汇编程序:
OS_CPU_SR_Restore
   MSR     PRIMASK, R0
   BX     LR
将cpu_sr中的值恢复,然后返回。
0x03小结
为了大家更加清楚的了解ucos工作机制,这里对源码进行了详细分析,对于一些简单的地方就没有进行解释,比如变量定义。还有些调用库函数的语句也没有解释,这是stm32部分的相关知识,为了尽量把多的空间放在ucos上所以就不再进行详细讲解,大家可以到网上查看这些代码的具体意思。

评分

黑币 +50
收起理由
+ 50
共享资料的黑币奖励!

查看全部评分

手机版|小黑屋|51黑电子论坛|51黑电子论坛6群QQ管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网