当前位置:   article > 正文

基于STM32+SysTick系统滴答定时器精准延时(附源码)_使用滴答定时器作为延时函数,使得定时器都有了作用

使用滴答定时器作为延时函数,使得定时器都有了作用

前言

       本次我们认识一下基于Cortex M3架构的系统滴答定时器(systick),以及如何使用系统滴答定时器实现精准的 ms 和 μs 延时,大部分是自己收集和整理,如有侵权请联系我删除。

交流群:717237739

如果觉得有用点赞关注收藏三连,多谢支持

本博客内容原创,创作不易,转载请注明

1.认识系统滴答定时器

delay 延时的编程思想:
        CM3 内核的处理器,内部 包含了一个 SysTick 定时器, SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从 RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及状 态寄存器中的使能位清除,就永不停息。

SysTick定时器被捆绑在NVIC中,是一个简单的定时器,对于CM3、CM4内核芯片,都有Systick定时器。Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。

Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。

系统滴答定时器有4个寄存器:

CTRLSysTick控制及状态寄存器(地址:0xE000_E010)
LOADSysTick重装载数值寄存器(地址:0xE000_E014)
VALSysTick当前数值寄存器(地址:0xE000_E018)
CALIBSysTick校准数值寄存器(地址:0xE000_E01C)
SysTick控制及状态寄存器(地址:0xE000_E010)
SysTick重装载数值寄存器(地址:0xE000_E014)

 SysTick当前数值寄存器(地址:0xE000_E018)

 SysTick校准数值寄存器(地址:0xE000_E01C)- - - 不常用

2.系统滴答定时器的使用流程

 1)时钟源的选择:

        在使用系统滴答定时器的时候,我们首先需要对时钟源进行选择,通过对SysTick控制及状态寄存器(地址:0xE000_E010)第【2】位来控制选择时钟源。

当寄存器的CLKSOURCE这个位:

为1的时候选择内部时钟源,时钟频率为72M不分频。

为0的时候选择外部时钟源,时钟频率为72M/8=9M。

选择外部时钟和内部时钟的区别?

        外部时钟相对来说精准度更高,稳定性更好,内部时钟使用的时RC振荡器,稳定性较差,相信了解过时钟树方面的知识应该能清楚。

2)系统滴答定时器的计时说明

计数时间的计算,通常我们计时时间为1S = 72M = 72 000 000。

如果我们选择了外部时钟源,经过8分频之后时钟频率为 9M,相当于1 S = 9 M;
所以 1s = 9 000 000  1ms = 9000     1μs = 9;计数9次为1微秒。

因为系统滴答定时器为24位的定时器,正常来说8位的范围在 0 -255之间
所以 24 位的 范围为  256*256*256 = 16 777 215
16 777 215 / 9 = 1864135μs = 1864.135ms = 1.864s
所以这个系统滴答定时器的最大延时为 1.864s


3)系统滴答定时器中断优先级设置

通过系统异常优先级寄存器来设置系统滴答定时器的优先级
在设置优先级之前得确定优先级分组,几位是抢占式优先级,几位是子优先级。

这个时候有人就有疑问了,为什么要开中断,开不开中断的差别在哪里?

1. 其实就是排队和插队的区别

2. 如果不进行中断配置,那么在函数的执行过程中,就是只能排队执行,就是轮到你才能执行。

3. 如果对定时器进行了中断配置,那么优先级高的中断会打断掉延时,但是如果没有其他中断,那么它的优先级是最高的,可以插队执行。

3.程序执行代码过程(附源码)

1)初始化延时函数,配置选择时钟源为外部时钟源,预分频为8

这里的 fac_us=SystemCoreClock/8 000 000;                //为系统时钟的1/8  
表示fac_us = 9;  计数9次为1微秒

  1. #include "delay.h"
  2. static u8 fac_us=0; //us延时倍乘数
  3. static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数
  4. //初始化延迟函数
  5. //SYSTICK的时钟固定为HCLK时钟的1/8
  6. //SYSCLK:系统时钟
  7. void delay_init()
  8. {
  9. SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
  10. fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
  11. fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
  12. }

2)不进中断的延时函数源码

宏定义的代码:

μs延时函数代码:

  1. //延时nus
  2. //nus为要延时的us数.
  3. void delay_us(u32 nus)
  4. {
  5. u32 temp;
  6. SysTick->LOAD=nus*fac_us; //时间加载
  7. SysTick->VAL=0x00; //清空计数器
  8. SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数 1<<0
  9. //SysTick->CTRL|= 0x01 ;
  10. //do while 判断就是systick使能(bit0)位为1且(bit16)位为1的时候等待结束
  11. //(temp&0x01)说明已经开始开始使能CTRL寄存器并且开始计数了,这个时候为真:1
  12. //!(temp&(1<<16))位&是为了判断里面第16位是否为1,为1则temp&(1<<16)为真,
  13. // 再取反为假,逻辑与&&判断while里面为假:0,则程序结束,表明计数结束
  14. do
  15. {
  16. temp=SysTick->CTRL;
  17. }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
  18. SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
  19. SysTick->VAL =0X00; //清空计数器
  20. }

ms延时函数代码:

  1. //延时nms
  2. //注意nms的范围
  3. //SysTick->LOAD为24位寄存器,所以,最大延时为:
  4. //nms<=0xffffff*8*1000/SYSCLK
  5. //SYSCLK单位为Hz,nms单位为ms
  6. //72M条件下,nms<=1864
  7. void delay_ms(u16 nms)
  8. {
  9. u32 temp;
  10. SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
  11. SysTick->VAL =0x00; //清空计数器
  12. SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
  13. do
  14. {
  15. temp=SysTick->CTRL;
  16. }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
  17. SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
  18. SysTick->VAL =0X00; //清空计数器
  19. }

通过以上对系统滴答定时器的代码配置,我们就可以在日常使用的时候能够精准使用延时。不占用定时器的资源,直接和cpu响应。

3)进中断的延时函数代码(基于基于Cortex M4)- - - 时钟为168M

        可以直接复制使用,不过如果移植为M3架构的芯片,就是需要找到对应的时钟宏定义,把时钟频率改为你当前芯片默认时钟频率就能正常使用了。

  1. #include "delay.h"
  2. #include "stdio.h"
  3. u32 delayTime ;
  4. //延时初始化
  5. void delay_Init(void)
  6. {
  7. //1us进一次中断
  8. if(SysTick_Config(SystemCoreClock/1000000) == 1)
  9. printf("系统滴答初始化失败\r\n");
  10. SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭系统滴答定时器
  11. }
  12. void SysTick_Handler(void)
  13. {
  14. if(delayTime > 0 )
  15. delayTime--;
  16. }
  17. void delay_us(u32 us)
  18. {
  19. delayTime = us;
  20. SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//开启系统滴答定时器
  21. while(delayTime);
  22. SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭系统滴答定时器
  23. }
  24. void delay_ms(u32 ms)
  25. {
  26. delayTime = ms * 1000;
  27. SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//开启系统滴答定时器
  28. while(delayTime);
  29. SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭系统滴答定时器
  30. }

4)代码使用实例


总结 :

        系统滴答定时器的代码并不是很多,知识相对来说也比较少,主要就是看时钟源的选择,和中断的使用,然后就是驱动响应的寄存器位来控制定时器的开启和关闭,等待计数为0就代表计数时间到了。

交流群:717237739

如果觉得有用点赞关注收藏三连,多谢支持

本博客内容原创,创作不易,转载请注明

  点赞收藏关注双击博主,不定期分享单片机知识,互相学习交流。
   

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/285170
推荐阅读
相关标签
  

闽ICP备14008679号