usosiii时钟节拍

在APP组里的os_cfg_app.h文件可以设置系统时钟SysTick的时钟节拍频率(还可以设置它的任务优先级,任务栈大小,时间片数组大小),一般使用1000Hz,也就是节拍周期为1ms。

#define  OS_CFG_TICK_RATE_HZ            1000u               /* Tick rate in Hertz (10 to 1000 Hz)                     */
#define  OS_CFG_TICK_TASK_PRIO            10u               /* Priority                                               */
#define  OS_CFG_TICK_TASK_STK_SIZE       128u               /* Stack size (number of CPU_STK elements)                */
#define  OS_CFG_TICK_WHEEL_SIZE           17u               /* Number of ‘spokes‘ in tick  wheel; SHOULD be prime     */

下面我们看看它的配置步骤的关键代码,BSP_CPU_ClkFreq()函数内部其实调用的rcc的库函数来获取参考频率的,OS_CPU_SysTickInit()直接配置SysTick(源码中是把控制寄存器或其它寄存器定义成相关变量(在cpu.h文件里定义),再操作;详情go to definition/reference of ‘something“)。

    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.确定系统定时器参考频率       */
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        /* Determine nbr SysTick increments                     */
    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).              */

蒜了,不要偷懒,还是把代码贴一下,这段代码在os_cpu_c.c文件里,英文注释已经说明它干了什么,如果不清楚某个变量或参数,查找定义就OK了。

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;
}

还记得之前移植的时候,将启动文件里的系统定时器中断和异常处理中断向量进行改名,改为OS_CPU_SysTickHandler的这个函数的就在上一段代码的上部,上面这个函数是表明特定时间中断一次,来处理系统事务,也就是中断的时候,干了些什么,其实仔细一看就是调用了OSTimeTick()。

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             */
}

那下面我们就看看这个位于os_time.c文件里的OSTimeTick()干了些什么?

也就是说上面的函数会发送信号量给OS_TickTask(),它接收到信号量之后就会进入就绪态,准备运行。

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                      */
            }
        }
    }
}

又可以看到OS_TickListUpdate的作用是更新所有任务的等待时间;也就是说,任务的执行,就是由前面说的系统时钟节拍按固定周期产生中断,以推送信号量给时基任务,时基任务再调用节拍列表更新函数,来更新所有任务的等待时间(然而这个函数又依据一些算法来实现的,太长了就不贴了)。

不急,接着往下看。。。

上一篇已经说过怎么新建任务了,那我们就直接来看app.c

*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/

#include <includes.h>

/*
*********************************************************************************************************
*                                            LOCAL DEFINES
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                                 TCB
*********************************************************************************************************
*/

static  OS_TCB   AppTaskStartTCB;

static  OS_TCB   AppTaskTestTCB;

/*
*********************************************************************************************************
*                                                STACKS
*********************************************************************************************************
*/

static  CPU_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];

static  CPU_STK  AppTaskTestStk [ APP_TASK_TEST_STK_SIZE ];

/*
*********************************************************************************************************
*                                         FUNCTION PROTOTYPES
*********************************************************************************************************
*/

static  void  AppTaskStart  (void *p_arg);

static  void  AppTaskTest   ( void * p_arg );

int  main (void)
{
    OS_ERR  err;

    OSInit(&err);                                                           //初始化 uC/OS-III

      /* 创建起始任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                            //任务控制块地址
                 (CPU_CHAR   *)"App Task Start",                            //任务名称
                 (OS_TASK_PTR ) AppTaskStart,                               //任务函数
                 (void       *) 0,                                          //传递给任务函数(形参p_arg)的实参
                 (OS_PRIO     ) APP_TASK_START_PRIO,                        //任务的优先级
                 (CPU_STK    *)&AppTaskStartStk[0],                         //任务堆栈的基地址
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,               //任务堆栈空间剩下1/10时限制其增长
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,                    //任务堆栈空间(单位:sizeof(CPU_STK))
                 (OS_MSG_QTY  ) 5u,                                         //任务可接收的最大消息数
                 (OS_TICK     ) 0u,                                         //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                 (void       *) 0,                                          //任务扩展(0表不扩展)
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), //任务选项
                 (OS_ERR     *)&err);                                       //返回错误类型

    OSStart(&err);                                                          //启动多任务管理(交由uC/OS-III控制)

}

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;

   (void)p_arg;

    BSP_Init();                                                 //板级初始化
    CPU_Init();                                                 //初始化 CPU 组件(时间戳、关中断时间测量和主机名)

    cpu_clk_freq = BSP_CPU_ClkFreq();                           //获取 CPU 内核时钟频率(SysTick 工作时钟)
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        //根据用户设定的时钟节拍频率计算 SysTick 定时器的计数值
    OS_CPU_SysTickInit(cnts);                                   //调用 SysTick 初始化函数,设置定时器计数值和启动定时器

    Mem_Init();                                                 //初始化内存管理组件(堆内存池和内存池表)

#if OS_CFG_STAT_TASK_EN > 0u                                    //如果使能(默认使能)了统计任务
    OSStatTaskCPUUsageInit(&err);                               //计算没有应用任务(只有空闲任务)运行时 CPU 的(最大)
#endif                                                          //容量(决定 OS_Stat_IdleCtrMax 的值,为后面计算 CPU
                                                                //使用率使用)。
    CPU_IntDisMeasMaxCurReset();                                //复位(清零)当前最大关中断时间

        /* 创建测试任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskTestTCB,                             //任务控制块地址
                 (CPU_CHAR   *)"App Task Test",                             //任务名称
                 (OS_TASK_PTR ) AppTaskTest,                                //任务函数
                 (void       *) 0,                                          //传递给任务函数(形参p_arg)的实参
                 (OS_PRIO     ) APP_TASK_TEST_PRIO,                         //任务的优先级
                 (CPU_STK    *)&AppTaskTestStk[0],                          //任务堆栈的基地址
                 (CPU_STK_SIZE) APP_TASK_TEST_STK_SIZE / 10,                //任务堆栈空间剩下1/10时限制其增长
                 (CPU_STK_SIZE) APP_TASK_TEST_STK_SIZE,                     //任务堆栈空间(单位:sizeof(CPU_STK))
                 (OS_MSG_QTY  ) 5u,                                         //任务可接收的最大消息数
                 (OS_TICK     ) 0u,                                         //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                 (void       *) 0,                                          //任务扩展(0表不扩展)
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), //任务选项
                 (OS_ERR     *)&err);                                       //返回错误类型

        OSTaskDel ( & AppTaskStartTCB, & err );                     //删除起始任务本身,该任务不再运行

}

/*
*********************************************************************************************************
*                                          TEST TASK
*********************************************************************************************************
*/

static  void  AppTaskTest ( void * p_arg )
{
    OS_ERR           err;
    CPU_INT32U       cpu_clk_freq;
    CPU_TS           ts_start;
    CPU_TS           ts_end;
    CPU_SR_ALLOC();                                       //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变
                                                        //量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR)
                                                        //,开中断时将该值还原。
 (void)p_arg;

  cpu_clk_freq = BSP_CPU_ClkFreq();                     //获取CPU时钟,时间戳是以该时钟计数

    while (DEF_TRUE) {                                    //任务体,通常都写成一个死循环
        ts_start = OS_TS_GET();                             //获取延时前时间戳

        OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );         //延时1000个时钟节拍(1s)

        ts_end = OS_TS_GET() - ts_start;                    //获取延时后的时间戳(以CPU时钟进行计数的一个计数值),并计算延时时间

        OS_CRITICAL_ENTER();                                //进入临界段,不希望下面串口打印遭到中断

        printf ( "\r\n延时1000个时钟节拍(1s),通过时间戳测得延时 %07d us,即 %04d ms。",
                  ts_end / ( cpu_clk_freq / 1000000 ),     //将延时时间折算成 us
                  ts_end / ( cpu_clk_freq / 1000 ) );      //将延时时间折算成 ms 

        OS_CRITICAL_EXIT();                                //进入临界段,不希望下面串口打印遭到中断

    }

}

主要就是通过延时1000个时钟节拍,来通过时间戳来计算延时的时间,具体直接看代码及注释就是了,下面是运行结果(由于这是软件延时,所以会有一点点小误差,但已经很精准了),那么就先到这里了。。。

原文地址:https://www.cnblogs.com/lzd626/p/9449039.html

时间: 2024-07-30 04:57:32

usosiii时钟节拍的相关文章

FreeRTOS 系统时钟节拍和时间管理

FreeRTOS 的时钟节拍任何操作系统都需要提供一个时钟节拍,以供系统处理诸如延时. 超时等与时间相关的事件.时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳. 中断之间的时间间隔取决于不同的应用,一般是 1ms – 100ms.时钟的节拍中断使得内核可以将任务延迟若干个时钟节拍,以及当任务等待事件发生时,提供等待超时等依据.时钟节拍率越快,系统的额外开销就越大.对于 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407 以及 F429,教程

22、操作系统的任务和时钟节拍

1. 任务,通常指交派的工作,担负的责任.在现代计算机中,“任务”也是其基本工作单位的专业术语. 在设计一个较为复杂的应用程序时,也通常把一个大型的任务分解成多个小任务,然后在计算机中通过运行小任务,最终完成大任务的目的.由于这种方法可以使系统并发的运行多个任务,从而提高处理器的利用率,加快程序的执行速度. 2.多任务系统 (1)简单的说就是用一个处理器,并发(不是同时)的运行多个程序的计算机管理系统 (2)并发:由同一个处理器轮换地 运行多个程序.或者说是由多个 程序轮班地占用处理器这个资源.

【转】FPGA中的建立时间和保持时间的关系以及影响时钟的因素

时钟是整个电路最重要.最特殊的信号,系统内大部分器件的动作都是在时钟的跳变沿上进行, 这就要求时钟信号时延差要非常小, 否则就可能造成时序逻辑状态出错:因而明确FPGA设计中决定系统时钟的因素,尽量较小时钟的延时对保证设计的稳定性有非常重要的意义. 1.1 建立时间与保持时间 建立时间(Tsu:set up time)是指在时钟沿到来之前数据从不稳定到稳定所需的时间,如果建立的时间不满足要求那么数据将不能在这个时钟上升沿被稳定的打入触发器:保持时间(Th:hold time)是指数据稳定后保持的

【转】OAL之系统时钟

1. 系统时钟与内核的关系 WinCE 5.0采用基于时间片的抢占式多任务的实时内核,而且每个线程可以根据需要自行设定线程时间片的大小(参考CeSetThreadQuantum函数),默认为100ms,这个默认值dwDefaultThreadQuantum也可以在OEMInit()时自行设定.在内核源文件中,与单词Quantum有关的变量名一般是指时间片,WinCE内核定义了几个与时钟有关的全局变量,他们也是内核与OAL接口的一部分: 1) dwReschedTime,这个变量在内核的调度程序中

mini2440裸机试炼之—RTC闹钟中断,节拍中断

环境搭建 硬件环境:J-link v8.mini2440.J-link转接板.串口转USB线 软件环境:windows7(32位).开发板uboot(NandFlash).J-link驱动(J-Link ARM V4.10i).SecureCRT.ADS1.2 其中ADS里的AXD设置:加载JlinkRDI.dll+Options->Configure Interface...,在Session File一页中选择"Run Configuration Script",将该name

影响FPGA设计中时钟因素的探讨【转】

Crazy Bingo Learn to walk first before you want to run- 影响FPGA设计中时钟因素的探讨 http://www.fpga.com.cn/advance/skill/speed.htm http://www.fpga.com.cn/advance/skill/design_skill3.htm 时钟是整个电路最重要.最特殊的信号,系统内大部分器件的动作都是在时钟的跳变沿上进行, 这就要求时钟信号时延差要非常小, 否则就可能造成时序逻辑状态出错

RT-thread内核之系统时钟

一.系统时钟 rt-thread的系统时钟模块采用全局变量rt_tick作为系统时钟节拍,该变量在系统时钟中断函数中不断加1.而系统时钟中断源和中断间隔一般由MCU硬件定时器(如stm32的嘀嗒定时器)决定,rt_tick初始值为0,每次MCU产生硬件定时中断后,在中断函数中不断加1,即rt_tick变量值与MCU硬件定时器定时中断间隔的乘积为系统真正运行时间(例如rt_tick=10,stm32嘀嗒定时器每隔1ms产生中断,则系统上电运行时间为10ms). 在bsp/stm32f40x/dri

MINIX3 内核时钟分析

4.1 内核时钟概要 先想想为什么 OS 需要时钟?时钟是异步的一个非常重要的标志,设想一下,如 果我们的应用程序需要在多少秒后将触发某个程序或者进程,我们该怎么做到? 就需要一个时钟的鼎力相助才能完成这个项工作.我的意思非常明确,就是说内 核时钟就是一个非常重要的部件,它可以完成分时系统的调度功能,同时它也能 为应用程序提供一个非常方便的异步处理问题的功能 现在我们简要的来看下时钟芯片的构造基本原理,如果需要了解详细的时钟芯 片,可以参考 intel 时钟芯片的详细编程资料. 一般时钟芯片就是

UCOS时钟与中断:

1时钟的中断处理函数:OSTICKISR() //其调用ostimetick(), 2ucosii时钟节拍10~100HZ,且在OSSTART之后开启时钟节拍.每个时钟节拍后,时钟中断函数将计时器加1,同时遍历所有延时的任务函数块将其延时减一,并使延时到的任务进入就绪. 3任务延时:UCOSII规定:处空闲任务外的任何任务都要调用一次延时函数,以进行一次任务调度,让出CPU使用权. 4获得和设置系统时间:在OSSTART之后启动每个时钟节拍增一通过函数好可获得和重置改在.时间. 中断与屏蔽中断: