昨天在设置 STM32F103 的系统时钟的时候,按照官方文档的方法进行设置,虽然系统时钟有效,但是原本设定为1s后执行的任务却延迟了九秒左右。百思不得其解,可以确定硬件是没有问题的。

以下是系统时钟的设置代码:

void clock_init(){
  if (SysTick_Config(SystemCoreClock/CLOCK_SECOND)){ 
       while (1);
  }
}

SysTick_Config() 是系统时钟的设置函数,代码如下:

/**
 * @brief  Initialize and start the SysTick counter and its interrupt.
 *
 * @param   ticks   number of ticks between two interrupts
 * @return  1 = failed, 0 = successful
 *
 * Initialise the system tick timer and its interrupt and start the
 * system tick timer / counter in free running mode to generate 
 * periodical interrupts.
 */
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 */
}

参数 ticks 是两个中断之间所需要的CPU ticks。我所使用的板子是STM32F103,CPU频率为72MHz。可以通过宏 SystemCoreClock 进行访问。上面宏 CLOCK_SECOND 设置为1000。也就是说,通过上面的配置,系统每1ms进行中断函数一次,精度为1ms。
以下是中断处理函数代码:

void SysTick_Handler(void)
{

  current_clock++;
  if(etimer_pending() && etimer_next_expiration_time() <= current_clock) {
    etimer_request_poll();
  }
  if (--second_countdown == 0) {
    current_seconds++;
    second_countdown = CLOCK_SECOND;
  }
}

主要的作用是 current_clock 计数的递增和检查定时器有没有过期。但是任务却没有像预期一样在设定的时间后运行,而是延迟了近9秒。已经可以确定板子的CPU频率确实为72MHz,但是实际上板子的频率却为8M。

解决方法:
STM32F103内部是8M的震荡,通过倍频后可以达到72M。我所使用的固件库是3.5的版本,通过查看文件system_stm32f103x.c文件,可以发现下面宏定义:

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif

其中STM32F10X_MD_VL之类的宏需要用户自己定义,而这里设置了SYSCLK_FREQ_72MHz为72000000。也就是说固件库在默认硬件已经接了8M晶振时,103的板子可以跑到72M。

#ifdef SYSCLK_FREQ_HSE
  static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
  static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
  static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
  static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
  static void SetSysClockTo56(void);  
#elif defined SYSCLK_FREQ_72MHz
  static void SetSysClockTo72(void);
#endif

上面是声明时钟设置的代码,可以看到这里出现了SetSysClockTo72 函数,把系统时钟设置为72M。而这个函数会被函数 SystemInit() 调用。
所以现在问题已经明确了,你的程序是初始化的时候需要调用 SystemInit() 函数进行系统时钟的初始化。试了一下,问题完美解决。

总结:
系统时钟没有初始化,需要在用户程序中手动调用,这个大坑。


sumas
18 声望9 粉丝

放飞自我很多年。


引用和评论

0 条评论