uCOSii的任务延时和软件定时器

uCOSii的任务延时和软件定时器

1、心跳节拍

    操作系统的心跳节拍称为一个Tick。uCOSii中有一个专用的心跳节拍函数:OSTimeTick(),每调用一次,系统时间计数器OSTime计数器就会加1次。为了能调用这个心跳节拍函数,我们使用CPU的滴答时钟(SysTick)。

2、STM32在OS下的滴答时钟配置

#include "delay.h"

#define SYSTEM_SUPPORT_OS       1   //1表示支持OS,0表示不支持OS

     

#if SYSTEM_SUPPORT_OS

#include "includes.h"  //includes.h包含了ucos使用到的所有头文件     

#endif

static u8  fac_us=0;//us延时倍乘数            

static u16 fac_ms=0;//ms延时倍乘数,在ucos下,代表每个节拍的ms数

#if SYSTEM_SUPPORT_OS

//如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了

//当delay_us()和delay_ms()需要支持OS的时候,需要定义3个宏和3个函数。

//首先3个宏定义:

//RTOS_Running:用于表示OS当前是否正在运行,以决定是否可以使用相关函数

//RTOS_TicksPerSecond:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始化滴答时钟(SysTick)

//RTOS_InterruptNesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行

//然后是3个函数:

//RTOS_SchedLock()用于锁定OS任务调度,禁止调度

//RTOS_SchedUnlock()用于解锁OS任务调度,重新开启调度

//RTOS_TimeDelay()用于OS延时,可以引起任务调度.

//支持UCOSII

#ifdef OS_CRITICAL_METHOD

//OS_CRITICAL_METHOD定义了,说明要支持UCOSII

#define RTOS_Running        OSRunning   //0表示OS不运行;1表示OS在运行

#define RTOS_TicksPerSecond OS_TICKS_PER_SEC  //OS时钟节拍,即每秒调度次数

#define RTOS_InterruptNesting   OSIntNesting    //中断嵌套级别,即中断嵌套次数

#endif

//支持UCOSIII

#ifdef CPU_CFG_CRITICAL_METHOD

//CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII 

#define RTOS_Running        OSRunning   //0表示OS不运行;1表示OS在运行

#define RTOS_TicksPerSecond OSCfg_TickRate_Hz  //OS时钟节拍,即每秒调度次数

#define RTOS_InterruptNesting   OSIntNestingCtr    //中断嵌套级别,即中断嵌套次数

#endif

//函数功能:us级延时时,关闭任务调度(防止打断us级延迟)

void RTOS_SchedLock(void)

{

#ifdef CPU_CFG_CRITICAL_METHOD  //当前操作系统使用的是UCOSIII

    OS_ERR err;

    OSSchedLock(&err); //UCOSIII的方式,禁止调度,防止打断us延时

#else   //当前操作系统使用的是UCOSII

    OSSchedLock();    //UCOSII的方式,禁止调度,防止打断us延时

#endif

}

//函数功能:us级延时时,恢复任务调度

void RTOS_SchedUnlock(void)

{  

#ifdef CPU_CFG_CRITICAL_METHOD //当前操作系统使用的是UCOSIII

    OS_ERR err;

    OSSchedUnlock(&err);  //UCOSIII的方式,恢复调度

#else   //当前操作系统使用的是UCOSII

    OSSchedUnlock();       //UCOSII的方式,恢复调度

#endif

}

//函数功能:调用OS自带的延时函数延时

//ticks:延时的节拍数

void RTOS_TimeDelay(u32 ticks)

{

#ifdef CPU_CFG_CRITICAL_METHOD //当前操作系统使用的是UCOSIII

    OS_ERR err;

    OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err); //UCOSIII延时ticks个节拍

#else  //当前操作系统使用的是UCOSII

    OSTimeDly(ticks); //UCOSII延时ticks个节拍

#endif

}

//函数功能:CPU的滴答时钟(SysTick)中断服务函数

void SysTick_Handler(void)

{  

    if(RTOS_Running==1)//OS开始跑了,才执行正常的调度处理

    {

        OSIntEnter();

        //进入中断时,用OSIntNesting来统计中断嵌套次数

        //告知uCOSii系统,当前中断服务程序正在执行;

        OSTimeTick();//调用ucos的心跳节拍函数              

        OSIntExit();

        //退出中断时,用OSIntNesting来统计中断嵌套次数

        //告知uCOSii系统,当前的中断已经处理完成,触发任务切换软中断

    }

}

#endif

              

//函数功能:CPU的滴答时钟(SysTick)初始化

//当使用OS的时候,此函数会初始化OS的时钟节拍

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init(void)

{

#if SYSTEM_SUPPORT_OS //如果需要支持OS.

    u32 reload;

#endif

    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

    //选择外部时钟HCLK/8

    fac_us=SystemCoreClock/8000000; //为系统时钟的1/8  

#if SYSTEM_SUPPORT_OS               //如果需要支持OS.

    reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K    

    reload*=1000000/RTOS_TicksPerSecond;

    //根据RTOS_TicksPerSecond设定溢出时间

    //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右  

    fac_ms=1000/RTOS_TicksPerSecond; //代表OS可以延时的最小单位

    SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   //开启SYSTICK中断

    SysTick->LOAD=reload; //每1/RTOS_TicksPerSecond秒中断一次 

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启CPU的滴答时钟(SysTick)  

#else

    fac_ms=(u16)fac_us*1000;//不支持OS,代表每个ms需要的systick时钟数   

#endif

}                                  

#if SYSTEM_SUPPORT_OS  //如果需要支持OS.

//函数功能:延时nus

//nus为要延时的us数.                                              

void delay_us(u32 nus)

{      

    u32 ticks;

    u32 told,tnow,tcnt=0;

    u32 reload=SysTick->LOAD; //LOAD的值             

    ticks=nus*fac_us;         //需要的节拍数             

    tcnt=0;

    RTOS_SchedLock();//阻止OS调度,防止打断us延时

    told=SysTick->VAL;  //刚进入时的计数器值

    while(1)

    {

        tnow=SysTick->VAL; 

        if(tnow!=told)

        {      

            if(tnow

            //这里注意一下SYSTICK是一个递减的计数器就可以了.

            else tcnt+=reload-tnow+told;       

            told=tnow;

            if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.

        } 

    };

    RTOS_SchedUnlock();//恢复OS调度                                       

}

//函数功能:延时nms

//nms:要延时的ms数

void delay_ms(u16 nms)

{  

    if(RTOS_Running&&RTOS_InterruptNesting==0)     

    {//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)      

        if(nms>=fac_ms) //延时的时间大于OS的最小时间周期

        {

            RTOS_TimeDelay(nms/fac_ms); //OS延时

        }

        nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时   

    }

    delay_us((u32)(nms*1000));//普通方式延时 

}

#else //不用OS时

//函数功能:延时nus

//nus为要延时的us数.                                              

void delay_us(u32 nus)

{      

    u32 temp;            

    SysTick->LOAD=nus*fac_us;                   //时间加载           

    SysTick->VAL=0x00;                          //清空计数器

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;    //开始倒数   

    do

    {

        temp=SysTick->CTRL;

    }while((temp&0x01)&&!(temp&(1<<16)));       //等待时间到达  

    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    //关闭计数器

    SysTick->VAL =0X00;                          //清空计数器  

}

//函数功能:延时nms

//注意nms的范围

//SysTick->LOAD为24位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK单位为Hz,nms单位为ms

//对72M条件下,nms<=1864

void delay_ms(u16 nms)

{                

    u32 temp;         

    SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)

    SysTick->VAL =0x00;                         //清空计数器

    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;    //开始倒数 

    do

    {

        temp=SysTick->CTRL;

    }while((temp&0x01)&&!(temp&(1<<16)));       //等待时间到达  

    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    //关闭计数器

    SysTick->VAL =0X00;                         //清空计数器            

}

#endif

3、uCOSii任务延时

在使用OSTimeDlyHMSM()和OSTimeDly()之前,先要在os_cfg.h文件中设置好OS_TICKS_PER_SEC,如下:

#define OS_TICKS_PER_SEC  1000u  /*设置OSTimeDlyHMSM()函数中每秒的节拍数*/

#define OS_TIME_DLY_HMSM_EN  1u   /*按时分秒延时函数OSTimeDlyHMSM()*/

#define OS_TIME_DLY_RESUME_EN 1u /*让正在延时期的任务结束延时OSTimeDlyResume()*/

#define OS_TIME_GET_SET_EN  1u   /*使能"系统时间函数OSTimeGet()和OSTimeSet()"*/

#define OS_TIME_TICK_HOOK_EN 1u

/*OSTaskTimeHook()在每个时钟节拍都会被OSTaskTick()调用*/

举例:

const char TEST1_TASK_rn_REG[]="\r\n";

const char TEST1_TASK_REG[]="TEST1_TASK";

//TEST1_TASK任务

void TEST1_TASK(void *pdata)

{

    u32 time;

    (void)pdata;

    while(1)

    {

       printf("%s",TEST1_TASK_rn_REG);

        printf("%s",TEST1_TASK_REG);

//     OSTimeDlyHMSM(0,0,0,500);//当前任务延时0.5秒

       OSTimeDly(500);

    //当前任务延时500个节拍

    //当OS_TICKS_PER_SEC=1000时,这里就是0.5秒

       OSTimeDlyResume(TEST2_TASK_PRIORITY);

       //唤醒一个“因OSTimeDly()或OSTimeDlyHMSM()而挂起的任务”

       time=OSTimeGet();//读取OSTime的值

       printf("%s",TEST1_TASK_rn_REG);

       printf("time=%u",time);

       OSTimeSet(0);//设置OSTime=0

    }

}

const char TEST2_TASK_rn_REG[]="\r\n";

const char TEST2_TASK_REG[]="TEST2_TASK";

//TEST2_TASK任务

void TEST2_TASK(void *pdata)

{

    (void)pdata;

    while(1)

    {

       printf("%s",TEST2_TASK_rn_REG);

        printf("%s",TEST2_TASK_REG);

       OSTimeDlyHMSM(0,0,5,0);//当前任务延时5秒,合计5000个节拍

    }

}

测试结果:

uCOSii的任务延时和软件定时器_第1张图片

4、uCOSii软件定时器

在使用“软件定时器”之前,先要在os_cfg.h文件中设置好OS_TMR_CFG_TICKS_PER_SEC,如下:

#define OS_MAX_TASKS              5u

/*设置"我的任务总数",uCOSii至少有两个任务,分别是"空闲任务"和"统计任务"*/

/*5表示用户可以用其中的3个任务,加上"空闲任务"和"统计任务"就是5个任务*/

#define OS_TMR_EN           1u   /*使能软件定时器的程序功能*/

#define OS_TMR_CFG_MAX  16u      /*可创建的软件定时器最多为16个*/

#define OS_TMR_CFG_NAME_EN  1u   /*使能软件定时器名称*/

#define OS_TMR_CFG_WHEEL_SIZE     8u   /*Size of timer wheel (#Spokes) */

#define OS_TMR_CFG_TICKS_PER_SEC 1000u  /*设置软件定时器的时钟源频率为1000Hz*/

#define OS_TASK_TMR_PRIO      4  /*软件定时器任务优先级为4*/

举例:

#include "TEST1_TASK.h"

#include "stdio.h"

 //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()

#include "My_Task_Priority.h"

OS_TMR   *MySoftTimer1;//软件定时器1

void TEST1_TASK(void *pdata);

const char TEST1_TASK_rn_REG[]="\r\n";

const char MySoftTimer1_TASK_REG[]="MySoftTimer1_TASK";

//函数功能:MySoftTimer1软件定时器的回调函数

void MySoftTimer1_Callback(OS_TMR *ptmr,void *p_arg)

{

    printf("%s",TEST1_TASK_rn_REG);

    printf("%s",MySoftTimer1_TASK_REG);

}

//TEST1_TASK任务

void TEST1_TASK(void *pdata)

{

    u8 err;

    (void)pdata;

//#define OS_TMR_CFG_TICKS_PER_SEC 1000u

    MySoftTimer1=OSTmrCreate( 0,\

                              1000,\

                              OS_TMR_OPT_PERIODIC,\

                             (OS_TMR_CALLBACK)MySoftTimer1_Callback,\

                              0,\

                              (u8*)"tmr1",\

                             &err);

    //1000ms执行一次,自动重

    OSTmrStart(MySoftTimer1,&err);//启动软件定时器MySoftTimer1

    while(1)

    {

        OSTimeDlyHMSM(0,0,0,10);//当前任务延时0.01秒,合计10个节拍

    }

}

你可能感兴趣的:(产品研发,uCOSii,实时操作系统,单片机,任务延时,软件定时器)