1. 程式人生 > >STM32下SysTick的一個容易發生的錯誤,時鐘頻率設定

STM32下SysTick的一個容易發生的錯誤,時鐘頻率設定

今天同事測試我之前寫的一個小程式,發生了奇怪的錯誤,先是Uart通訊接收操作,出現了接收資料不全的問題:2個位元組的應答幀,在實際執行中只能收到1個位元組,導致程式死迴圈。檢查後發現,是接收部分程式碼留的延時太短,造成了晶片誤以為通訊已結束,但實際應答幀尚未傳輸完畢。(此處接收程式碼的工作模式是:當Uart接收到1個位元組後,即開始一個定長的延時,該延時長度與通訊波特率相關,當正常通訊還在繼續時,則應在延時結束前收到下一個位元組資料,如延時結束仍未收到下一個位元組資料,說明當前一幀資料已完成,可開始對已接收資料進行處理)

發現了問題後,進行相應的針對性操作,對延時長度進行了增加,即解決了此問題。但仍然覺得疑惑,因此段程式是已經通過測試的,執行正常,不應突然出現這種奇怪的錯誤,因此懷疑晶片自身的延時程式存在問題。

而後此程式繼續出現的錯誤證實了之前的懷疑:新出現的錯誤是顯示部分程式的延時明顯不夠,因此可以斷定是延時部分出了問題。此程式的延時功能由滴答定時器的1ms延時函式來實現,對該函式進行排查,果然發現了問題根源。

stm32的滴答定時器設定主要有以下暫存器:


其中SysTick->CTRL暫存器包含了對滴答定時器的時鐘頻率來源設定和分頻設定。前述小程式中,採用的是STM32F107晶片,外部時鐘,工作頻率為72MHz,在此程式中,為了讓滴答定時器的工作壓力稍減,使用了8分頻的時鐘設定,計數(72000000/8000)=9000,時長為1ms。程式碼如下:

void SystemTick_Configuration(void)
{
    RCC_ClocksTypeDef RCC_Clocks;

    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    RCC_GetClocksFreq(&RCC_Clocks);
    // SystTick configuration: an interrupt every 1 ms
    if(SysTick_Config(RCC_Clocks.SYSCLK_Frequency / 8000))
    {
        while(1) FEED_WWDG;
    }
}
此程式在我的電腦編譯下是正常工作的,但在同事電腦編譯下出了問題,滴答定時器的延時明顯縮短,原因在於core_cm3.h檔案。此檔案位置在C:\Keil\ARM\CMSIS\Include資料夾下,此檔案中的SysTick_Config函式包含以下操作:
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */

  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  |= SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

此處對滴答定時器的時鐘來源進行了操作,使其恢復了最高頻率(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、修改檔案呼叫指向,不呼叫工程外的相關標頭檔案,防止出現移植時,不同電腦間,工程外檔案的不同導致的錯誤。