昨天在设置 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() 函数进行系统时钟的初始化。试了一下,问题完美解决。总结:
系统时钟没有初始化,需要在用户程序中手动调用,这个大坑。