STM32下SysTick的一个容易发生的错误,时钟频率设置

今天同事测试我之前写的一个小程序,发生了奇怪的错误,先是Uart通讯接收操作,出现了接收数据不全的问题:2个字节的应答帧,在实际运行中只能收到1个字节,导致程序死循环。检查后发现,是接收部分代码留的延时太短,造成了芯片误以为通讯已结束,但实际应答帧尚未传输完毕。(此处接收代码的工作模式是:当Uart接收到1个字节后,即开始一个定长的延时,该延时长度与通讯波特率相关,当正常通讯还在继续时,则应在延时结束前收到下一个字节数据,如延时结束仍未收到下一个字节数据,说明当前一帧数据已完成,可开始对已接收数据进行处理)

发现了问题后,进行相应的针对性操作,对延时长度进行了增加,即解决了此问题。但仍然觉得疑惑,因此段程序是已经通过测试的,运行正常,不应突然出现这种奇怪的错误,因此怀疑芯片自身的延时程序存在问题。

而后此程序继续出现的错误证实了之前的怀疑:新出现的错误是显示部分程序的延时明显不够,因此可以断定是延时部分出了问题。此程序的延时功能由滴答定时器的1ms延时函数来实现,对该函数进行排查,果然发现了问题根源。

stm32的滴答定时器设置主要有以下寄存器:

其中SysTick->CTRL寄存器包含了对滴答定时器的时钟频率来源设置和分频设置。前述小程序中,采用的是STM32F107芯片,外部时钟,工作频率为72MHz,在此程序中,为了让滴答定时器的工作压力稍减,使用了8分频的时钟设置,计数(72000000/8000)=9000,时长为1ms。代码如下:

 
  1. void SystemTick_Configuration(void)

  2. {

  3. RCC_ClocksTypeDef RCC_Clocks;

  4.  
  5. SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

  6. RCC_GetClocksFreq(&RCC_Clocks);

  7. // SystTick configuration: an interrupt every 1 ms

  8. if(SysTick_Config(RCC_Clocks.SYSCLK_Frequency / 8000))

  9. {

  10. while(1) FEED_WWDG;

  11. }

  12. }

此程序在我的电脑编译下是正常工作的,但在同事电脑编译下出了问题,滴答定时器的延时明显缩短,原因在于core_cm3.h文件。此文件位置在C:\Keil\ARM\CMSIS\Include文件夹下,此文件中的SysTick_Config函数包含以下操作:

 
  1. static __INLINE uint32_t SysTick_Config(uint32_t ticks)

  2. {

  3. if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */

  4.  
  5. SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */

  6. NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */

  7. SysTick->VAL = 0; /* Load the SysTick Counter Value */

  8. SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk |

  9. SysTick_CTRL_TICKINT_Msk |

  10. SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */

  11. return (0); /* Function successful */

  12. }


此处对滴答定时器的时钟来源进行了操作,使其恢复了最高频率(72MHz),不分频:

<pre name="code" class="cpp">SysTick->CTRL  |= SysTick_CTRL_CLKSOURCE_Msk |
 

在我的电脑上,因为对core_cm3.h文件做了以下修改,屏蔽了其对滴答定时器时钟的操作,所以可以正常运行:

SysTick->CTRL  |= //SysTick_CTRL_CLKSOURCE_Msk |

但在同事的电脑上没有做此操作,从而导致了1ms延时实际只有0.125ms,于是出现了前述的种种错误。

解决办法:

1、使用滴答定时器时,不再考虑减轻芯片负担,直接采用原始频率,可以保证不会出现此问题。

2、修改文件调用指向,不调用工程外的相关头文件,防止出现移植时,不同电脑间,工程外文件的不同导致的错误。

猜你喜欢

转载自blog.csdn.net/qinrenzhi/article/details/81809915