ToB企服应用市场:ToB评测及商务社交产业平台

标题: STM32的delay函数详解以及带不带操作体系的区别(基于HAL库) [打印本页]

作者: 梦见你的名字    时间: 2024-10-21 13:30
标题: STM32的delay函数详解以及带不带操作体系的区别(基于HAL库)
我们从接触的第一个跑马灯项目开始,就用到了delay函数,初学者只知道调用一下delay_ms,delay_us就可以进行体系延时。那么对于这个函数,你相识多少呢?下面让我们根据代码分析一下这个函数实现的过程。
首先,delay函数分为裸机版本和操作体系版本,如果你在操作体系的项目下面运行裸机版本的delay函数,那么步伐不会按你所想的方式运行,以是在操作体系下面我们应该修改delay函数为兼容体系的,下面我们以ucos体系为例,说说这两个版本的区别。
1.delay_init函数


第一个我们来分析初始化函数delay_init,宏定义SYSTEM_SUPPORT_OS为1的时间是支持操作体系,为0的时间是裸机步伐,SysTick 是 MDK 定义了的一个结构体(在 core_m4.h 里面),里面包罗 CTRL、LOAD、VAL、CALIB 4 个寄存器。

SysTick->CTRL 的各位定义:

SysTick-> LOAD 的定义:

SysTick-> VAL 的定义:

SysTick-> CALIB的话我们现在不用到,不做描述。
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);这行代码的意思就是SysTick的时钟选择为体系内核时钟,SysTick的时钟来源于HCLK,和体系时钟同样为180Mhz,SysTick-> VAL每减小1就过去了1/180us,fac_us=SYSCLK,这里我们传入的SYSCLK为180,意思就是延时1us需要180个 SysTick 时钟周期。
在不使用操作体系的时间,只要给fac_us写入周期数就可以了,但是在使用操作体系的时间,fac_us不被写入SysTick->LOAD 实现延时,fac_ms=1000/delay_ostickspersec; 代表操作体系可以延时的最少毫秒(当delay_ostickspersec=1000的时间,表示操作体系最少可以延迟1毫秒)

2.delay_us  函数

2.1带操作体系的delay_us函数

  1. //延时nus
  2. //nus:要延时的us数.       
  3. //nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)                                                                              
  4. void delay_us(u32 nus)
  5. {               
  6.         u32 ticks;
  7.         u32 told,tnow,tcnt=0;
  8.         u32 reload=SysTick->LOAD;                                //LOAD的值                     
  9.         ticks=nus*fac_us;                                                 //需要的节拍数
  10.         delay_osschedlock();                                        //阻止OS调度,防止打断us延时
  11.         told=SysTick->VAL;                                        //刚进入时的计数器值
  12.         while(1)
  13.         {
  14.                 tnow=SysTick->VAL;       
  15.                 if(tnow!=told)
  16.                 {            
  17.                         if(tnow<told)tcnt+=told-tnow;        //这里注意一下SYSTICK是一个递减的计数器就可以了.
  18.                         else tcnt+=reload-tnow+told;            
  19.                         told=tnow;
  20.                         if(tcnt>=ticks)break;                        //时间超过/等于要延迟的时间,则退出.
  21.                 }  
  22.         };
  23.         delay_osschedunlock();                                        //恢复OS调度                                                                                            
复制代码
 此函数想对于不带操作体系的delay_us函数,多一个delay_osschedlock(); 来阻止OS调理,防止打断us延时,然后在延时函数结束之前,调用delay_osschedunlock();恢复OS调理。
2.2不带操作体系的delay_us函数


这里利用了时钟摘取法,ticks 是延时 nus 需要等待的 SysTick 计数次数,told 用于记录最近一次的 SysTick->VAL 值,然后 tnow 则是当前的SysTick->VAL 值,通过他们的对比累加,实现 SysTick 计数次数的统计,统计值存放在 tcnt 里面,通过对比 tcnt 和 ticks,来判定延时是否完成,实现 nus 的延时。
3. delay_ms 

3.1带操作体系的delay_ms函数

  1. //延时nms
  2. //nms:要延时的ms数
  3. //nms:0~65535
  4. void delay_ms(u16 nms)
  5. {       
  6.         if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)            
  7.         {                 
  8.                 if(nms>=fac_ms)                                                //延时的时间大于OS的最少时间周期
  9.                 {
  10.                            delay_ostimedly(nms/fac_ms);        //OS延时
  11.                 }
  12.                 nms%=fac_ms;                                                //OS已经无法提供这么小的延时了,采用普通方式延时   
  13.         }
  14.         delay_us((u32)(nms*1000));                                //普通方式延时
  15. }
复制代码
带操作体系的delay_ms函数,会判定需要延时的时间是否大于之前在init里面设置的最小时间周期fac_ms,如果大于fac_ms,就会进行nms/fac_ms次时间延时,并且这段时间操作体系进行正常的任务调理,最后计算nms%=fac_ms,如果存在余数表示最后差nms没有延时完成,以是又用delay_us补上剩余没有延时的时间,此时不进行任务调理。
3.2不带操作体系的delay_ms函数


这个没什么好说的,就是调用了n次delay_us实现。

4.总结

在裸机步伐中,delay_ms函数与delay_us函数正常使用即可,在操作体系中,使用delay_ms函数的时间,如果设置的延时时间大于操作体系设置的最小的调理时间,就会进行正常的任务调理拉起当前任务,执行下一个已停当的任务,直到剩余延时时间小于操作体系设置的最小的调理时间,就进行delay_us函数,留意的是,只要是delay_us函数被调用的时间,体系不会进行任务调理

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4