嵌入式开发交流网论坛
标题:
UCOS任务调度实现原理-1
[打印本页]
作者:
劫_Zed
时间:
2018-9-15 12:37
标题:
UCOS任务调度实现原理-1
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)
这个函数是
stm
32
固件库中的函数,具体代码大家可以看一下,它可以返回系统的硬件频率。
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
中的值恢复,然后返回。
0x0
3
小结
为了大家更加清楚的了解
ucos
工作机制,这里对源码进行了详细分析,对于一些简单的地方就没有进行解释,比如变量定义。还有些调用库函数的语句也没有解释,这是
stm
32
部分的相关知识,为了尽量把多的空间放在
ucos
上所以就不再进行详细讲解,大家可以到网上查看这些代码的具体意思。
知识传播是一种美德
让更多人少走弯路
才能有更多人携手前进
欢迎扫码一起分享经验
[attach]10699[/attach]
如有任何疑问请后台回复
或添加
作者
Waiting_B_H
欢迎光临 嵌入式开发交流网论坛 (http://www.dianzixuexi.com/bbs/)
Powered by Discuz! X3.2