填坑-关于SysTick定时器

开发 前端
本文主要介绍关于SysTick定时器的相关知识,希望对你有帮助。

[[390601]]

本文主要来填坑,更正之前文章的错误。也进一步加深了我对SysTick定时器的理解,希望对你有帮助。

01坑的由来

在之前的推文中《STM32延时的四种方法》介绍了使用查询定时器精确延时,使用的就是systick定时器,具体代码如下

  1. void delay_us(uint32_t nus) 
  2.   uint32_t temp
  3.   SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000000/8*nus; 
  4.   SysTick->VAL=0X00;//清空计数器 
  5.   SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源 
  6.   do 
  7.   { 
  8.     temp=SysTick->CTRL;//读取当前倒计数值 
  9.   }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达 
  10.   SysTick->CTRL=0x00; //关闭计数器 
  11.   SysTick->VAL =0X00; //清空计数器 
  12. void delay_ms(uint16_t nms) 
  13.   uint32_t temp
  14.   SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000/8*nms; 
  15.   SysTick->VAL=0X00;//清空计数器 
  16.   SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源 
  17.   do 
  18.   { 
  19.     temp=SysTick->CTRL;//读取当前倒计数值 
  20.   }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达 
  21.   SysTick->CTRL=0x00; //关闭计数器 
  22.   SysTick->VAL =0X00; //清空计数器 

对于《STM32延时的四种方法》文中所说的内容如下

也就是下面代码中/8的原因。

  1. SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000/8*nms; 

我对此深信不疑,并在STM32F207参考手册(RM0033)上找到“证据”。

上图①处直接是8分频,而不像②出的1/2/4/8分频。所以我确信是SYSTICK的时钟固定为HCLK时钟的1/8。

我在学习RTThread的时候,看到配置SysTick定制器代码如下

我心里一堆问号,STM32官方手册,明明写了SYSTICK的时钟固定为HCLK时钟的1/8。我使用示波器测量,RTThread的配置是没有问题,可以正常延时的。

02填坑

这个坑其实很简单,在《STM32延时的四种方法》也提到了,只是自己没有注意这个细节。

位2置1,表示时钟频率为AHB,也就是默认的120000000Hz。

位2清0,表示时钟频率为AHB/8,也就是120000000/8Hz。

RTThread配置为内部时钟

之前的文章配置为外部时钟源


这个细节我没有留意,导致我看RTThread代码时有点懵逼。在这里我更正《STM32延时的四种方法》中的错误描述

准确的描述是:

SYSTICK的时钟可以为HCLK时钟的1分频或8分频,在这里我们选用外部时钟源120M,所以SYSTICK的时钟为(120/8)M。

特此更正。

关于这点,STM32的标准外设库提供的SysTick_Config函数,也是使用内部时钟的

  1. /** \brief  System Tick Configuration 
  2.  
  3.     This function initialises the system tick timer and its interrupt and start the system tick timer. 
  4.     Counter is in free running mode to generate periodical interrupts. 
  5.  
  6.     \param [in]  ticks  Number of ticks between two interrupts 
  7.     \return          0  Function succeeded 
  8.     \return          1  Function failed 
  9.  */ 
  10. static __INLINE uint32_t SysTick_Config(uint32_t ticks) 
  11.   if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */ 
  12.  
  13.   SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */ 
  14.   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */ 
  15.   SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */ 
  16.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
  17.                    SysTick_CTRL_TICKINT_Msk   | 
  18.                    SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */ 
  19.   return (0);                                                  /* Function successful */ 

调用方法,产生1ms中断调用方法

  1. SysTick_Config(SystemCoreClock / 1000); 

关于时钟源的选择,除了操作寄存器外,还有库函数可以选择。

  1. /** 
  2.   * @brief  Configures the SysTick clock source. 
  3.   * @param  SysTick_CLKSource: specifies the SysTick clock source. 
  4.   *   This parameter can be one of the following values
  5.   *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source. 
  6.   *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source. 
  7.   * @retval None 
  8.   */ 
  9. void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) 
  10.   /* Check the parameters */ 
  11.   assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource)); 
  12.   if (SysTick_CLKSource == SysTick_CLKSource_HCLK) 
  13.   { 
  14.     SysTick->CTRL |= SysTick_CLKSource_HCLK; 
  15.   } 
  16.   else 
  17.   { 
  18.     SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8; 
  19.   } 

除上外,我找到了其他证据来说明,SYSTICK的时钟可以为HCLK时钟的1分频或8分频。

在STM32CubeMx配置软件中,可以选择1分频或8分频。

03修改代码验证

把《STM32延时的四种方法》文中涉及的代码修改成1分频的。

  1. void delay_ms(uint16_t nms) 
  2.   uint32_t temp
  3.   SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000*nms-1; 
  4.   SysTick->VAL=0X00;//清空计数器 
  5.   SysTick->CTRL=0X01; 
  6.   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); 
  7.   do 
  8.   { 
  9.     temp=SysTick->CTRL;//读取当前倒计数值 
  10.   }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达 
  11.   SysTick->CTRL=0x00; //关闭计数器 
  12.   SysTick->VAL =0X00; //清空计数器 

然后调用

  1. GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄灭LED灯                      
  2. delay_ms(500);//延时500ms 
  3. GPIO_ResetBits(GPIOE,GPIO_Pin_4);//点亮LED灯                      
  4. delay_ms(500);//延时500ms 

就踩到另一个坑,延时不准。

原因是:此时SYSTICK时钟频率是120MHz的24位的倒计数定时器,也就是说一个周期,最多定时139.810125ms。不能延时500ms。

这里再更正之前的一个错误,如下图

这个计数器的值,我们减去了1,这样才更准确。需要减1的具体原因在定时器讲解的文章中讲解过了,不明白的同学请看《STM32基础定时器讲解》。

04总结

总结:STM32官方手册并不一定是准确的,要亲自做实验,自己动手验证。这是个老生常谈的问题,大家都知道,关键还在于实践。

 

责任编辑:姜华 来源: 知晓编程
相关推荐

2022-09-26 08:26:38

软件定时器函数

2010-07-28 15:56:22

FlexTimer定时

2009-11-11 10:14:10

linux定时器操作系统

2023-01-10 13:53:21

Linux定时器

2022-11-02 11:40:16

Flowable定时器流程

2009-04-12 08:51:50

Symbian诺基亚移动OS

2013-07-29 10:10:40

TCP协议TCP定时器TCP

2011-02-23 10:20:45

2023-08-02 09:26:03

软件定时器鸿蒙

2009-06-18 11:07:17

Spring fram

2017-03-06 14:08:38

JavaScript单线程setTimeout

2021-04-18 12:12:29

systemd定时器系统运维

2023-02-28 18:09:53

Javascript定时器

2021-06-28 06:00:11

systemd定时器系统运维

2014-12-09 16:30:18

TCP定时器

2023-12-11 09:50:35

Linux定时器

2021-08-03 14:33:53

cron定时器Linux命令

2021-08-26 06:29:47

STM32DWT数据观察点触发

2021-07-27 16:01:29

高并发定时器高性能

2021-08-11 10:10:26

Linux定时器数组
点赞
收藏

51CTO技术栈公众号