SYSTEM文件夹下的delay文件夹学习小结

SYSTEM文件夹

1、STM32商家提供的一个底层核心驱动函数,可以方便初学者快速构建自己的工程。

2、SYSTEM文件夹下包含了delay、sys、usart三个子文件夹,分别包含了delay.c、sys.c、usart.c及其头文件。通过这三个c文件可以构建最基本的框架。

delay文件夹

1、delay文件夹内包含了delay.c和delay.h两个文件,用来实现系统的延时功能。

2、Cortex-M3内核的处理器内部包含了一个SysTick定时器(24位的倒计数定时器),利用SysTick来实现延时,既不占用中断,也不占用系统定时器。

3、delay函数采用时钟摘取法,只抓取SysTick计数器的变化,并不需要修改SysTick的任何状态,完全不影响SysTick作为μC/OS时钟节拍的功能。

delay_init函数

1、该函数用来初始化fac_us和fac_ms两个重要参数;同时使用了条件编译来选择不同的初始化过程,如果不适用OS,则只是设置一下SysTick的时钟源以及确定fac_us和fac_ms的值,如果使用OS,则进行一些不同的配置。

2、SysTick是MDK定义了的一个结构体,里面包含CTRL、LOAD、VAL、CALLB这4个寄存器。

delay_us函数

1、该函数用来延时指定的μs,其参数nus为要延时的微秒数。该函数具有使用OS和不使用OS两个版本。

2、不使用OS的时候:

//延时nus
//nus为要延时的us数.                                               
void delay_us(u32 nus)
{        
    u32 temp;             
    SysTick->LOAD=nus*fac_us;                 //时间加载               
    SysTick->VAL=0x00;                        //清空计数器
    SysTick->CTRL=0x01 ;                      //开始倒数      
    do
    {
        temp=SysTick->CTRL;
    }while((temp&0x01)&&!(temp&(1<<16)));    //等待时间到达   
    SysTick->CTRL=0x00;                       //关闭计数器
    SysTick->VAL =0X00;                       //清空计数器     
}

①先把要延时的μs数换算成SysTick的时钟数

②写入LOAD寄存器

③清空当前寄存器VAL的内容,再开启倒数功能,等倒数结束即延时了nus

④最后关闭SysTick,清空VAL的值,实现一次延时nus的操作

⑤“temp&0x01”这一句用来判断systick定时器是否还处于开启状态,防止systick被意外关闭导致的死循环。

3、使用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;                         //需要的节拍数 
    delay_osschedlock();                    //阻止OS调度,防止打断us延时
    told=SysTick->VAL;                        //刚进入时的计数器值
    while(1)
    {
        tnow=SysTick->VAL;    
        if(tnow!=told)
        {        
            if(tnow<told)tcnt+=told-tnow;    //这里注意一下SYSTICK是一个递减的计数器就可以了.
            else tcnt+=reload-tnow+told;        
            told=tnow;
            if(tcnt>=ticks)break;            //时间超过/等于要延迟的时间,则退出.
        }  
    };
    delay_osschedunlock();                    //恢复OS调度                                        
}

①时钟摘取法。ticks是延时nus需要等待的SysTick计数次数(也就是延时时间)

②told用于记录最近一次的SysTick➡VAL值,tnow是当前的SysTick➡VAL值。对比累加实现SysTick计数次数的统计,统计值存放在tcnt里面

③对比tcnt和ticks来判断延时是否到达,从而达到不修改SysTick实现nus的延时,使得可以和OS共用一个SysTick。

delay_ms函数

改函数用来延时指定的ms,其参数nms为要延时的毫秒数。同样有使用OS和不使用OS

首先使用OS:

//延时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=0x01 ;                      //开始倒数  
    do
    {
        temp=SysTick->CTRL;
    }while((temp&0x01)&&!(temp&(1<<16)));    //等待时间到达   
    SysTick->CTRL=0x00;                       //关闭计数器
    SysTick->VAL =0X00;                       //清空计数器              
} 

①LOAD是24bit的寄存器,延时ms数不能太长,否则会延时不准。

②最大延迟ms公式:nms≤0xfffff*8*1000/SYSCLK。

③SYSCLK单位为Hz,nms的单位为ms。

④如果时钟为72MHz,那么nms的最大值为1864ms。

⑤超过值可以通过多次调用delay_ms实现,否则会导致延时不准确。

使用OS:

//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{    
    if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)        
    {         
        if(nms>=fac_ms)                        //延时的时间大于OS的最少时间周期 
        { 
               delay_ostimedly(nms/fac_ms);    //OS延时
        }
        nms%=fac_ms;                        //OS已经无法提供这么小的延时了,采用普通方式延时    
    }
    delay_us((u32)(nms*1000));                //普通方式延时  
}

①delay_osrunning是OS正在运行的标志;

delay_osintnestng是OS中断嵌套次数;

②必须delay_osrunning为真,且delay_osintnesting为0的时候,才可以调用OS自带的延时函数进行延时。

③delay_ostimedly函数是利用OS自带的延时函数实现任务级延时的,其参数代表延时的时钟节拍数

(假设delay_ostickspersec=200,那么delay_ostimedly(1)就代表延时5ms)

猜你喜欢

转载自www.cnblogs.com/youwei666/p/11782866.html