所谓时钟节拍,就是CPU以固定的频率产生中断,可以看做是系统的心跳。内核利用这个时钟节拍来管理各个任务的一些时间管理比如延时,定时,超时检测,时间轮片调度等。时钟节拍的频率一般10Hz--1000Hz。频率太高内核负担加重,频率太低实时性就差。这个频率在μC/OS-III源码OS_CFG_APP.c中可以自定义,在STM32平台的具体实现如下:

1.配置滴答定时器

void  OS_CPU_SysTickInit (CPU_INT32U  cnts)
{
CPU_INT32U prio; CPU_REG_NVIC_ST_RELOAD = cnts - 1u; /* Set SysTick handler prio. */
prio = CPU_REG_NVIC_SHPRI3;
prio &= DEF_BIT_FIELD(24, 0);
prio |= DEF_BIT_MASK(OS_CPU_CFG_SYSTICK_PRIO, 24); CPU_REG_NVIC_SHPRI3 = prio; /* Enable timer. */
CPU_REG_NVIC_ST_CTRL |= CPU_REG_NVIC_ST_CTRL_CLKSOURCE |
CPU_REG_NVIC_ST_CTRL_ENABLE;
/* Enable timer interrupt. */
CPU_REG_NVIC_ST_CTRL |= CPU_REG_NVIC_ST_CTRL_TICKINT;
}

void OS_CPU_SysTickInit (CPU_INT32U cnts)

2.定时器中断

void  OS_CPU_SysTickHandler (void)
{
CPU_SR_ALLOC(); CPU_CRITICAL_ENTER();
OSIntNestingCtr++; /* Tell uC/OS-III that we are starting an ISR */
CPU_CRITICAL_EXIT(); OSTimeTick(); /* Call uC/OS-III's OSTimeTick() */ OSIntExit(); /* Tell uC/OS-III that we are leaving the ISR */
}

void OS_CPU_SysTickHandler (void)

这就是一个滴答定时器的中断函数,函数内主要做了中断嵌套级变量OSIntNestingCtr加1的操作,和调用了OSTimeTick()这个函数

void  OSTimeTick (void)
{
OS_ERR err;
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
CPU_TS ts;
#endif OSTimeTickHook(); /* Call user definable hook */ #if OS_CFG_ISR_POST_DEFERRED_EN > 0u ts = OS_TS_GET(); /* Get timestamp */
OS_IntQPost((OS_OBJ_TYPE) OS_OBJ_TYPE_TICK, /* Post to ISR queue */
(void *)&OSRdyList[OSPrioCur],
(void *) 0,
(OS_MSG_SIZE) 0u,
(OS_FLAGS ) 0u,
(OS_OPT ) 0u,
(CPU_TS ) ts,
(OS_ERR *)&err); #else (void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB, /* Signal tick task */
(OS_OPT ) OS_OPT_POST_NONE,
(OS_ERR *)&err); #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
#endif #if OS_CFG_TMR_EN > 0u
OSTmrUpdateCtr--;
if (OSTmrUpdateCtr == (OS_CTR)0u) {
OSTmrUpdateCtr = OSTmrUpdateCnt;
OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB, /* Signal timer task */
(OS_OPT ) OS_OPT_POST_NONE,
(OS_ERR *)&err);
}
#endif #endif
}

void OSTimeTick (void)

注意 其中的信号发布函数指向了任务控制块OSTickTaskTCB,每次到达滴答定时器中断时都会发布一个信号量给这个任务控制块,从而使这个任务就可以执行下去,任务详情见代码

void  OS_TickTask (void  *p_arg)
{
OS_ERR err;
CPU_TS ts; p_arg = p_arg; /* Prevent compiler warning */ while (DEF_ON) {
(void)OSTaskSemPend((OS_TICK )0,
(OS_OPT )OS_OPT_PEND_BLOCKING,
(CPU_TS *)&ts,
(OS_ERR *)&err); /* Wait for signal from tick interrupt */
if (err == OS_ERR_NONE) {
if (OSRunning == OS_STATE_OS_RUNNING) {
OS_TickListUpdate(); /* Update all tasks waiting for time */
}
}
}
}

void OS_TickTask (void *p_arg)

任务中请求信号,如果请求到就执行OS_TickListUpdate(),这个函数主要是用到了哈希算法(求余)来对加入的时间列表的任务检查看是否到时,对于延时到时且符合就绪条件的任务加入就绪任务列表里下次任务调度时就会按照该有的优先级进行任务调度。不满足就绪条件的按情况修改任务状态。

void  OS_TickListUpdate (void)
{
CPU_BOOLEAN done;
OS_TICK_SPOKE *p_spoke;
OS_TCB *p_tcb;
OS_TCB *p_tcb_next;
OS_TICK_SPOKE_IX spoke;
CPU_TS ts_start;
CPU_TS ts_end;
CPU_SR_ALLOC(); OS_CRITICAL_ENTER();
ts_start = OS_TS_GET();
OSTickCtr++; /* Keep track of the number of ticks */
spoke = (OS_TICK_SPOKE_IX)(OSTickCtr % OSCfg_TickWheelSize);
p_spoke = &OSCfg_TickWheel[spoke];
p_tcb = p_spoke->FirstPtr;
done = DEF_FALSE;
while (done == DEF_FALSE) {
if (p_tcb != (OS_TCB *)0) {
p_tcb_next = p_tcb->TickNextPtr; /* Point to next TCB to update */
switch (p_tcb->TaskState) {
case OS_TASK_STATE_RDY:
case OS_TASK_STATE_PEND:
case OS_TASK_STATE_SUSPENDED:
case OS_TASK_STATE_PEND_SUSPENDED:
break; case OS_TASK_STATE_DLY:
p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */
- OSTickCtr;
if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */
p_tcb->TaskState = OS_TASK_STATE_RDY;
OS_TaskRdy(p_tcb); /* Make task ready to run */
} else {
done = DEF_TRUE; /* Don't find a match, we're done! */
}
break; case OS_TASK_STATE_PEND_TIMEOUT:
p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */
- OSTickCtr;
if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */
#if (OS_MSG_EN > 0u)
p_tcb->MsgPtr = (void *)0;
p_tcb->MsgSize = (OS_MSG_SIZE)0u;
#endif
p_tcb->TS = OS_TS_GET();
OS_PendListRemove(p_tcb); /* Remove from wait list */
OS_TaskRdy(p_tcb);
p_tcb->TaskState = OS_TASK_STATE_RDY;
p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT; /* Indicate pend timed out */
p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
} else {
done = DEF_TRUE; /* Don't find a match, we're done! */
}
break; case OS_TASK_STATE_DLY_SUSPENDED:
p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */
- OSTickCtr;
if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */
p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
OS_TickListRemove(p_tcb); /* Remove from current wheel spoke */
} else {
done = DEF_TRUE; /* Don't find a match, we're done! */
}
break; case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
p_tcb->TickRemain = p_tcb->TickCtrMatch /* Compute time remaining of current TCB */
- OSTickCtr;
if (OSTickCtr == p_tcb->TickCtrMatch) { /* Process each TCB that expires */
#if (OS_MSG_EN > 0u)
p_tcb->MsgPtr = (void *)0;
p_tcb->MsgSize = (OS_MSG_SIZE)0u;
#endif
p_tcb->TS = OS_TS_GET();
OS_PendListRemove(p_tcb); /* Remove from wait list */
OS_TickListRemove(p_tcb); /* Remove from current wheel spoke */
p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
p_tcb->PendStatus = OS_STATUS_PEND_TIMEOUT; /* Indicate pend timed out */
p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
} else {
done = DEF_TRUE; /* Don't find a match, we're done! */
}
break; default:
break;
}
p_tcb = p_tcb_next;
} else {
done = DEF_TRUE;
}
}
ts_end = OS_TS_GET() - ts_start; /* Measure execution time of tick task */
if (OSTickTaskTimeMax < ts_end) {
OSTickTaskTimeMax = ts_end;
}
OS_CRITICAL_EXIT();
}

void OS_TickListUpdate (void)

整个时钟节拍相关的大致流程如下:

μC/OS-III---I笔记2---实钟节拍的更多相关文章

  1. uc/os iii移植到STM32F4---IAR开发环境

    也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...

  2. 基于μC/OS—III的CC1120驱动程序设计

    基于μC/OS—III的CC1120驱动程序设计 时间:2014-01-21 来源:电子设计工程 作者:张绍游,张贻雄,石江宏 关键字:CC1120   嵌入式操作系统   STM32F103ZE   ...

  3. OS考研复习笔记——操作系统的定义、目标、作用和发展的主要动力

    计算机系统由硬件和软件两部分组成.操作系统(OS,Operating System)是配置在计算机硬件上的第一层软件,是对硬件系统的首次补充. 硬件:计算机物理设备,即各种处理机存储器.输入/输出设备 ...

  4. os模块常用方法笔记

    os模块是程序和系统文件之间的交互接口,可以实现对文件的创建.删除等功能,以下对os模块的功能做一个笔记,方便以后学习和查找. import os os.getcwd() #获取当前工作目录,即当前p ...

  5. STM32F40G-EVAL_UC/OS III

    micrum官网下载uc/os程序包: 包含文件cotex_M4.h:

  6. golang os包使用笔记

    zhangsan os.Stidn 标准输入 os.Stdout 标准输出 os.Stderr 标准错误输出

  7. python os模块使用笔记(更新)

    import os 添加os模块 walk方法: os.walk(path) path是string形式的目标目录 生成一个某目录下递归树形目录迭代器,方便递归访问子目录,访问目录就能够轻松访问子文件 ...

  8. os模块。笔记

    os 模块提供了很多允许你的程序与操作系统直接交互的功能 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目录名:os.listdir()  ...

  9. python os库学习笔记

    os.getcwd(): 获取当前目录 os.name: 获取当前使用的操作系统 eg: print os.name os.remove(): 删除指定文件 eg: os.remove('test.t ...

  10. Python3 os.path() 模块笔记

    os.path 模块主要用于获取文件的属性. 以下是 os.path 模块的几种常用方法: 方法 说明 os.path.abspath(path) 返回绝对路径 os.path.basename(pa ...

随机推荐

  1. Mysql简要概述

    Mysql学习笔记 Mysql简介: ​ Mysql是一个轻量级关系型数据库管理系统,由瑞典Mysql AB公司开发,目前属于Oracle公司.目前Mysql被广泛地应用在Internet上的中小型网 ...

  2. CSS响应式布局学习笔记(多种方法解决响应式问题)

    在做web开发的工作中,会遇到需要我给页面根据设计的要求,进行响应式布局,这里跟大家分享下我对于响应式布局的解决方法: 我主要利用的是CSS3 媒体查询,即media queries,可以针对不同的媒 ...

  3. CoeMonkey少儿编程第4章 变量

    点击这里,现在就开启CodeMonkey的趣味编程之旅. 目标 了解什么是变量 了解变量的命名规则 掌握如何使用变量 变量 什么是变量?顾名思义,变量就是可以变化的量. 和变量相对的是常量,即不可变化 ...

  4. JavaScript中的构造函数和原型!

    JavaScript中的原型! 原型的内容是涉及到JavaScript中的构造函数的 每一个构造函数都有一个原型对象!prototype 他的作用是 共享方法!还可以扩展内置对象[对原来的内置对象进行 ...

  5. linux通过ntpd同步服务器时间,

    ntpd得rpm包下载地址:https://pkgs.org/download/ntp 比如我得服务器版本是centos7 x86的,那选择我点击的这一个: 下拉到最下面就有安装包下载了,我选择的是二 ...

  6. logging philosophy 日志哲学

    Go kit - Frequently asked questions https://gokit.io/faq/ Logging - Why is package log so different? ...

  7. Any race is a bug. When there is a race, the compiler is free to do whatever it wants.

    https://mp.weixin.qq.com/s/pVJiFdDDKVx707eKL19bjA 谈谈 Golang 中的 Data Race 原创 ms2008 poslua 2019-05-13 ...

  8. super 多重继承 super() function with multilevel inheritance

    Python | super() function with multilevel inheritance - GeeksforGeeks https://www.geeksforgeeks.org/ ...

  9. 为什么要使用 do while(0)?

    两点 避免宏定义的花括号对代码的完整性造成影响 可以在指定的代码块中(do{})使用break提前跳出,避免goto.

  10. eclipse 断点调试方法

    1 Debug视图 1.1 线程堆栈视图 线程堆栈视图表示当前线程的堆栈,从中可以看出在运行哪些代码,并且整个调用过程,以及代码行号.分别介绍一下这几个按钮的含义.从左至右分别为: 1.表示当前实现继 ...