1、stm8s003的时钟
复位后,默认使用内部高速时钟HSI(16MHz)的8分频,也就是2MHz.
代码开始运行,也就是运行到main函数,我们就可以修改时钟源为外部晶振。
2、切换时钟流程分析,参考官方应用手册
9.2.2,介绍了主时钟切换的流程,分为自动切换和手动切换,这里只看自动切换。
1)开启切换时钟源使能;
2)选择目标时钟源,也就是外部晶振,这一步是写到CLK_SWR,S代表选择,并不是真正的切换时钟源;
此时SWBSY硬件置位,虽然外部晶振开启,但是旧的时钟源仍然运行;
3)等待外部晶振稳定;
4)第四步是自动硬件自动切换的,在SWBSY硬件清零之后,刚才CLK_SWR的值被硬件写入CLK_CMSR,系统切换到外部晶振;
再补充一个流程图,可以看得更清楚:
3、代码
我使用的是库函数,调用CLK_ClockSwitchConfig一句话就行。
这个函数内部我也进去看了,步骤都有,等待稳定的超时是0x491(十进制1169)个时钟周期,并且可以选择是否关掉旧的时钟;
clk_return_status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
if (clk_return_status != SUCCESS){ //SUCCESS or ERROR
//开启失败的一些操作
}
4、CLK_ClockSwitchConfig最后一个参数,是否关闭旧的时钟
疑问,如果外部晶振开启失败了,又关闭了旧的时钟,会不会不能往下运行?
验证:把外部晶振取下,模拟开启失败的情况。
现象:不管是关闭旧时钟CLK_CURRENTCLOCKSTATE_DISABLE,还是不关闭旧时钟CLK_CURRENTCLOCKSTATE_ENABLE,程序都能继续往下执行,并且时钟频率为旧的时钟频率。
注:如果在开启外部晶振前,把内部时钟的分频调成1(16MHz),那么外部晶振开启失败后时钟频率还是16MHz;
设置这个用处就是,可以先把内部时钟频率调成和外部一样的,比如分频2调成8MHz,这样即使外部晶振没有起振,程序也不会有较大的影响(可以留一个信息让自己知道外部晶振是没有成功开启的);
验证代码如下:
void main(void)
{
u8 i;
ErrorStatus clk_return_status;
/* Initialize I/Os in Output Mode */
GPIO_Init(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
//默认8分频,内部2MHz,翻转10次,慢速
for(i=0;i<10;i++){
/* Toggles LEDs */
GPIO_WriteReverse(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS);
Delay(0xffff);
}
GPIO_WriteHigh(LED_GPIO_PORT,LED_GPIO_PINS);
//2分频,内部8MHz
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV2);
for(i=0;i<10;i++){
/* Toggles LEDs */
GPIO_WriteReverse(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS);
Delay(0xffff);
}
GPIO_WriteHigh(LED_GPIO_PORT,LED_GPIO_PINS);
//开启外部8MHz晶振
clk_return_status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
if (clk_return_status != SUCCESS){ //SUCCESS or ERROR
//开启失败,常亮一会提示
GPIO_WriteLow(LED_GPIO_PORT,LED_GPIO_PINS);
for(i=0;i<30;i++){
Delay(0xffff);
}
}
while (1){
GPIO_WriteReverse(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS);
Delay(0xffff);
}
}