你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于使用Stm32延时与计时方法

[复制链接]
攻城狮Melo 发布时间:2023-3-17 19:22
一.延时的3种方法
首先,先了解一下什么延时。顾名思义,延时即是延长一段时间。

1.循环延时
这是最简单的延时方法,让单片机做一些无关紧要的工作来打发时间,这里通过循环的方式实现。但是,这种方法想到做到精准延时是需要经过不断测试的。
  1. void delay_ms(u16 time)

  2. {   
  3.    u16 i=0;  
  4.    while(time--)
  5.    {
  6.       i=12000;  //自己定义
  7.       while(i--) ;   
  8.    }
  9. }
复制代码

2.定时器中断延时与非中断延时
在实际应用中,我们常采用的是定时器延时。定时器延时分为中断延时与非中断延时。两种方法在延时效果上是一样的,只是实现的过程不一样。

中断延时通过在中断中的计数值的不断递减来达到精确延时,而非中断则通过在循环里不停查询寄存器数值来达到精确延时。前者因为中断的存在,不利于在其他中断中调用延时函数。在很多延时教程中,都喜欢推荐非中断式的延时。不过对于非特殊情况,两者的效果是一样的。反而非中断延时需要操作寄存器,反而更难理解。


三.定时器中断式计时与延时
首先,需要用CubeMX配置一个定时器(以TIM4为例),配置如下:

20200711152339345.png

步骤:

    1. 打开TIM4,将分频系数设置为71(我使用的是STM32F103C8,高速外部晶振为72MHz,分频后所得频率即为1MHz,换句话说定时器每次计数的时间间隔为1us)。分频系数的需要视自己选择的芯片而定。

   2. 重转载值设定为最大值65535,同时打开中断。定时器每次计数的时间间隔是1us,而计数到65536将会溢出产生中断,所以每一次中断的时间间隔为65535us。

   3. 已知每次中断的时间间隔(65535us),同时记录下中断的次数(TimerCnt),再加上定时器当前计数值(CNT),便能得到系统的绝对时间了。即:

SystemTimer=TimerCnt*65535+CNT
以上就是利用定时器计时的原理,他能够记录你的单片机从开机后每一刻的绝对时间。下面给出实现的代码:
  1. volatile uint32_t TimerCnt; //定时器中断的次数(设为全局变量)

  2. void delay_Init() //定时器初始化
  3. {
  4.         HAL_TIM_Base_Start_IT(&htim4); //使能定时器中断
  5.         HAL_TIM_Base_Start(&htim4);  //启动定时器
  6. }

  7. uint32_t Get_SystemTimer(void)//获取系统时间的函数
  8. {
  9.         return htim4.Instance->CNT + SystemTimerCnt * 0xffff;
  10.         //系统时间=定时器当前计数值+65535*定时器中断次数
  11. }


  12. //CubeMX生成的TIM4中断服务函数,在stm32f1xxit.c中
  13. void TIM4_IRQHandler(void)  
  14. {
  15.   /* USER CODE BEGIN TIM4_IRQn 0 */
  16.   /* USER CODE END TIM4_IRQn 0 */
  17.   HAL_TIM_IRQHandler(&htim4);
  18.   /* USER CODE BEGIN TIM4_IRQn 1 */
  19.         TimerCnt++;  //每中断一次TimerCnt计数值+1
  20.   /* USER CODE END TIM4_IRQn 1 */
  21. }
复制代码

下面是我测试时的效果,Stm32从定时器初始化后开始不停得计时,计时精度还是挺高的。

20200711175307347.gif

计时记录的是单片机开机后的绝对时间,那么以此为时间轴,延时也就很容易完成了。只要记录下你延时开始的时间,然后在你预定的延时时间里用循环来阻塞就可以了。在上述的基础上加上如下代码;
  1. //微秒延时
  2. void delay_us(uint32_t delay_time)
  3. {
  4.         uint32_t temp = delay_time  + Get_SystemTimer();
  5.         while(temp >= Get_SystemTimer());
  6. }

  7. //毫秒延时
  8. void delay_ms(uint32_t delay_time)
  9. {
  10.                 uint32_t temp = delay_time * 1000 + Get_SystemTimer();
  11.                 while(temp >= Get_SystemTimer());
  12. }
复制代码

二.定时器非中断式延时
以系统滴答计时器为例(代码来自网络,亲测有效)
  1. //微秒延时
  2. void delay_us(uint32_t nus)
  3. {
  4. uint32_t temp;
  5. SysTick->LOAD = 9*nus;
  6. SysTick->VAL=0X00;//清空计数器
  7. SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
  8. do
  9. {
  10.   temp=SysTick->CTRL;//读取当前倒计数值
  11. }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
  12.      SysTick->CTRL=0x00; //关闭计数器
  13.     SysTick->VAL =0X00; //清空计数器
  14. }

  15. //毫秒延时
  16. void delay_ms(uint16_t nms)
  17. {
  18. uint32_t temp;
  19. SysTick->LOAD = 9000*nms;
  20. SysTick->VAL=0X00;//清空计数器
  21. SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
  22. do
  23. {
  24.   temp=SysTick->CTRL;//读取当前倒计数值
  25. }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
  26.     SysTick->CTRL=0x00; //关闭计数器
  27.     SysTick->VAL =0X00; //清空计数器
  28. }
复制代码

四.代码例程
已经把我写好代码上传到CSDN上,已经调试好,亲测有效。
————————————————
版权声明:冬瓜~
如有侵权请联系删除


收藏 评论0 发布时间:2023-3-17 19:22

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版