reset clock control 复位和时钟控制器
一、stm32时钟树
stm32时钟树:由时钟源到外设的结构框图。
基本时钟源(图中绿色箭头指出):
(1)HSI高速内部时钟,RC振荡器,8MHz。
(2)HSE高速外部时钟,石英/陶瓷谐振器,8MHz。
(3)LSI低速内部时钟,RC振荡器,40kHz。
(4)LSE低速外部时钟,RTC石英晶振,32.768kHz。
注:内部指的是片上外设,外部指的是芯片外部。
(5)除了上述基本时钟源,还有num3中的PLL锁相环倍频时钟源,它是将HSI和HSE倍频后输出。
二、PLLCLK - PLL时钟(num4)
时钟来源:(1)HSI/2 (2)HSE
三、SYSCLK - 系统时钟(num5)
时钟来源:(1)HSI (2)PLLCLK (3)HSE
SYSCLK经过分频后,得到AHB总线时钟HCLK;
HCLK再分频得到APB1总线时钟PCLK1和APB2总线时钟PCLK2;
PCLK2分频后得到ADCCLK最大14MHz。
四、RTCCLK(灰色框中)
时钟来源:(1)HSE/128 (2)LSE (3)LSI
五、系统时钟配置
系统时钟有三个来源,PLLCLK、HSE、HSI。
正常情况下,时钟配置是在system_stm32f10x.c中完成,这里的的时钟配置是直接控制寄存器完成的。
在 stm32f10x_rcc.c中定义了关于时钟配置的库函数,此时未用。
打开system_stm32f10x.c,找到void SystemInit (void),再找到 SetSysClock()并查看定义,
定义中可知是通过在system_stm32f10x.c中宏定义SYSCLK_FREQ_72MHz选择系统时钟配置函数SetSysClockTo72(),
即72MHz的系统时钟就是在此函数中配置的,函数如下:(HSE(不分频)->PLLCLK(9倍频)->72MHz系统时钟)
1 static void SetSysClockTo72(void) 2 { 3 __IO uint32_t StartUpCounter = 0, HSEStatus = 0; 4 5 /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ 6 /* 使能 HSE */ 7 RCC->CR |= ((uint32_t)RCC_CR_HSEON); 8 9 /* 等待HSE就绪并做超时处理 */ 10 do 11 { 12 HSEStatus = RCC->CR & RCC_CR_HSERDY; 13 StartUpCounter++; 14 } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); 15 16 if ((RCC->CR & RCC_CR_HSERDY) != RESET) 17 { 18 HSEStatus = (uint32_t)0x01; 19 } 20 else 21 { 22 HSEStatus = (uint32_t)0x00; 23 } 24 25 // 如果HSE启动成功,程序则继续往下执行 26 if (HSEStatus == (uint32_t)0x01) 27 { 28 /* 使能预取指 */ 29 FLASH->ACR |= FLASH_ACR_PRFTBE; 30 31 /* Flash 2 wait state */ 32 FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); 33 FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; 34 35 36 /* HCLK = SYSCLK = 72M */ 37 RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; 38 39 /* PCLK2 = HCLK = 72M */ 40 RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; 41 42 /* PCLK1 = HCLK = 36M*/ 43 RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; 44 45 /* 锁相环配置: PLLCLK = HSE * 9 = 72 MHz */ 46 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | 47 RCC_CFGR_PLLMULL)); 48 RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); 49 50 /* 使能 PLL */ 51 RCC->CR |= RCC_CR_PLLON; 52 53 /* 等待PLL稳定 */ 54 while((RCC->CR & RCC_CR_PLLRDY) == 0) 55 { 56 } 57 /* 选择PLLCLK作为系统时钟*/ 58 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); 59 RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; 60 61 /* 等待PLLCLK切换为系统时钟 */ 62 while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) 63 { 64 } 65 } 66 else 67 { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */ 68 } 69 }
这里再以库函数形式中重新配置系统时钟和MCO:
user中新建RCC文件夹,新建bsp_rccclkconfig.c和bsp_rccclkconfig.h文件,同时对main函数做补充。(GPIO&KEY例程继续写的)
bsp_rccclkconfig.h
1 #ifndef __BSP_RCCCLKCONFIG_H 2 #define __BSP_RCCCLKCONFIG_H 3 4 #include "stm32f10x.h" 5 6 void HSE_SetSysClk( uint32_t RCC_PLLMul_x ); 7 void MCO_GPIO_Config(); 8 void HSI_SetSysClk( uint32_t RCC_PLLMul_x ); 9 #endif /*__BSP_RCCCLKCONFIG_H */
bsp_rccclkconfig.c
1 #include "bsp_rccclkconfig.h" 2 3 void HSE_SetSysClk( uint32_t RCC_PLLMul_x ) 4 { 5 ErrorStatus HSEStatus; 6 7 //把RCC寄存器复位成复位值 8 RCC_DeInit(); 9 10 // 使能 HSE 11 RCC_HSEConfig(RCC_HSE_ON); 12 13 HSEStatus = RCC_WaitForHSEStartUp(); 14 15 if( HSEStatus == SUCCESS ) 16 { 17 // 使能预取址 18 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); 19 FLASH_SetLatency(FLASH_Latency_2); 20 21 RCC_HCLKConfig(RCC_SYSCLK_Div1); 22 RCC_PCLK1Config(RCC_HCLK_Div2); 23 RCC_PCLK2Config(RCC_HCLK_Div1); 24 25 // 配置 PLLCLK = HSE * RCC_PLLMul_x 26 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x); 27 28 // 使能PLL 29 RCC_PLLCmd(ENABLE); 30 31 // 等待PLL稳定 32 while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET ); 33 34 // 选择系统时钟 35 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 36 37 while( RCC_GetSYSCLKSource() != 0x08 ); 38 } 39 else 40 { 41 /* 如果HSE启动失败,用户可以在这里添加错误的处理代码 */ 42 } 43 } 44 45 void HSI_SetSysClk( uint32_t RCC_PLLMul_x ) 46 { 47 __IO uint32_t HSIStatus = 0; 48 49 // 把RCC寄存器复位成复位值 50 RCC_DeInit(); 51 52 // 使能 HSI 53 RCC_HSICmd(ENABLE); 54 55 HSIStatus = RCC->CR & RCC_CR_HSIRDY; 56 57 if( HSIStatus == RCC_CR_HSIRDY ) 58 { 59 // 使能预取址 60 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); 61 FLASH_SetLatency(FLASH_Latency_2); 62 63 RCC_HCLKConfig(RCC_SYSCLK_Div1); 64 RCC_PCLK1Config(RCC_HCLK_Div2); 65 RCC_PCLK2Config(RCC_HCLK_Div1); 66 67 // 配置 PLLCLK = HSI * RCC_PLLMul_x 68 RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x); 69 70 // 使能PLL 71 RCC_PLLCmd(ENABLE); 72 73 // 等待PLL稳定 74 while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET ); 75 76 // 选择系统时钟 77 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 78 79 while( RCC_GetSYSCLKSource() != 0x08 ); 80 } 81 else 82 { 83 /* 如果HSI启动失败,用户可以在这里添加处理错误的代码 */ 84 } 85 } 86 87 void MCO_GPIO_Config()//MCO时钟输出GPIO配置,PA8 88 { 89 GPIO_InitTypeDef GPIO_InitStruct; 90 91 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 92 93 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; 94 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; 95 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 96 97 GPIO_Init(GPIOA, &GPIO_InitStruct); 98 }
main.c
1 #include "stm32f10x.h" // 2 #include "bsp_key.h" 3 #include "bsp_led.h" 4 #include "bsp_rccclkconfig.h" 5 void Delay( uint32_t count ) //软件延时函数,但是实际时间间隔取决于系统时钟 6 { 7 for(; count!=0; count--); 8 } 9 10 int main(void) 11 { 12 // 来到这里的时候,系统时钟已经被配置成72M 13 LED_GPIO_Config(); 14 KEY_GPIO_Config(); 15 //这里重新配置时钟,如果注释掉下面两条HSE和HSI语句,将使用默认的system_stm32f10x.c寄存器配置版72M
16 //HSE=8MHZ,PLL九倍频=72MHZ 17 HSE_SetSysClk( RCC_PLLMul_9 ); 18 //HSI/2=4MHZ,PLL十六倍频=64MHZ 19 //HSI_SetSysClk( RCC_PLLMul_16 ); 20 21 //MCO的GPIO初始化 22 MCO_GPIO_Config(); 23 //选择系统时钟作为MCO输出 24 RCC_MCOConfig(RCC_MCO_SYSCLK); //PA8接示波器可见 25 //RCC_MCOConfig(RCC_MCO_HSI); 26 27 while(1)//更改系统时钟频率,小灯的闪烁间隔出现变化 28 { 29 // 30 //if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) ==KEY_ON ) 31 // LED_G_TOGGLE; 32 33 LED_G(OFF); 34 Delay(0xFFFFF); 35 36 LED_G(ON); 37 Delay(0xFFFFF); 38 } 39 }
7