找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1184|回复: 1
打印 上一主题 下一主题
收起左侧

UCOSIII任务调度原理

[复制链接]
跳转到指定楼层
楼主
ID:907990 发表于 2021-4-18 20:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本文主要讲解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个参数,再多的话建议采用指针或者堆栈。

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:192176 发表于 2021-12-2 10:17 | 只看该作者
后面还有吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

Powered by 单片机教程网

快速回复 返回顶部 返回列表