时钟树
- 1、时钟树的简介
- 2、相关寄存器与配置
- 3、代码实验
1、时钟树的简介
每次在使用单片机的片上外设之前,第一步就是开启此外设的时钟(内核外设除外)。这一步就像是开关,只有开启了时钟,这个外设才能正常的使用。我们知道STM32有很多的片上外设,他们挂载的对应的时钟总线如下图所示。
那么这些时钟总线APB1,APB2,AHB的时钟频率是如何改变的喃?这就与时钟树有关。
2、相关寄存器与配置
如下图就是STM32F103C8T6的时钟树。总线AHB频率不能超过72MHz,APB1频率不能超过36MHz,APB2频率不能超过72MHz。其中系统时钟SystemClock的时钟来源由HSI(8MHz),HSE(8MHz),PLL(8~72MHz)。SystemClock经过分频后得到AHB总线时钟频率,AHB总线时钟结果分频得到APB1总线和APB2总线时钟频率。
1.HSE:
外部高速晶振,一般可提供4~16MHz的频率,而我们使用的最小系统板的外部高速晶振为8MHz。
与之相关的寄存器如下:
/*开启外部高速晶振HSE*/RCC->CR |= RCC_CR_HSEON;//开启HSEwhile(!(RCC->CR & RCC_CR_HSEON));//等待开启成功
2.HSI:
内部高速晶振,是单片机内部提供,一般为8MHz。和HSE相比,稳定性和精度不如HSE。
与之相关的寄存器如下:
/*开启内部晶振HSI*/
RCC->CR |= RCC_CR_HSION;//开启HSI
while(!(RCC->CR & RCC_CR_HSIRDY));//等待开启成功
3.HSE Prescaler:
内部高速晶振HSE的分频器:一般为1分频(不分频),2分频。
与之相关的寄存器如下:
// 配置 PLLXTPRE 为 1,意味着 HSE 时钟将进行 2 分频后送入 PLL
RCC->CFGR |= RCC_CFGR_PLLXTPRE; // 设置 PLLXTPRE 为 1
// 配置 PLLXTPRE 为 0,意味着 HSE 时钟不进行分频,直接送入 PLL
RCC->CFGR &= ~RCC_CFGR_PLLXTPRE; // 清除 PLLXTPRE 为 0
4.PLL Source Mux:
PLL输入时钟源选择。可选2分频后的HSI,未分频/分频的HSE。
与之相关的寄存器如下:
/*配置PLL输入时钟源为HSE:RCC_CFGR_PLLSRC = 1*/
RCC->CFGR |= RCC_CFGR_PLLSRC;
5.PLLMul:
PLL倍频器,倍率2~16
与之相关的寄存器如下:
/* 设置PLL倍频为9(只有PLL未开启才能配置):RCC_CFGR_PLLMULL[3:0] */
RCC->CFGR |= RCC_CFGR_PLLMULL;
RCC->CFGR &= ~RCC_CFGR_PLLMULL_3;//配置为0111
/*使能PLL:RCC_CR_PLLON = 1*/
RCC->CR |= RCC_CR_PLLON;//使能PLL
while(!(RCC->CR & RCC_CR_PLLRDY));//等待使能成功
6.System Clock Mux:
系统SystemClock时钟源选择。可选HSI作为系统时钟源,HSE作为系统时钟源,PLL作为系统时钟源。
与之相关的寄存器如下:
/*配置为选择PLL:RCC_CFGR_SW[1:0] = 10 */
RCC->CFGR &= ~RCC_CFGR_SW_0;
RCC->CFGR |= RCC_CFGR_SW_1;
7.AHB Prescaler:
AHB总线时钟预分频器,将系统时钟SystemClock进行分频后得到AHB总线时钟频率。分频系数1~512
与之相关的寄存器如下:
/*设置AHB分频为1分频:RCC_CFGR_HPRE[3:0] = 0XXX*/
RCC->CFGR &= ~RCC_CFGR_HPRE_3;
8.APB1 Prescaler:
APB1总线时钟预分频器,将AHB总线时钟频率进行分频后得到APB1总线时钟频率。分频系数1~16
与之相关的寄存器如下:
/*设置APB1为2分频:RCC_CFGR_PPRE1[2:0] = 100 */
RCC->CFGR &= ~(RCC_CFGR_PPRE1_0 |RCC_CFGR_PPRE1_1);
RCC->CFGR |= RCC_CFGR_PPRE1_2;
9.APB2 Prescaler:
APB2总线时钟预分频器,将AHB总线时钟频率进行分频后得到APB2总线时钟频率。分频系数1~16
与之相关的寄存器如下:
/*设置APB2为1分频:RCC_CFGR_PPRE2[2:0] = 0xx*/
RCC->CFGR &= ~RCC_CFGR_PPRE2_2;
3、代码实验
实验:将系统时钟SystemClock配置为72MHz,AHB总线时钟配置为72MHz,APB1总线时钟配置为36MHz,APB2总线时钟配置为72MHz。
配置代码如下:
void Config_SystemClock(void)
{/* 1、使能外部高速晶振HSE:RCC_CR_HSEON = 1(因为停机模式使HSE停止了,所以要使能)*/RCC->CR |= RCC_CR_HSEON;/* 2、等待开启成功:RCC_CR_HSERDY = 1 */while(!(RCC->CR & RCC_CR_HSERDY));//系统默认HSE未分频,所以可以不用配置HSE Prescaler/* 3、配置PLL输入时钟源为HSE:RCC_CFGR_PLLSRC = 1 */RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;/* 4、设置PLL倍频为9(只有PLL未开启才能配置):RCC_CFGR_PLLMULL[3:0] */RCC->CFGR |= RCC_CFGR_PLLMULL;RCC->CFGR &= ~RCC_CFGR_PLLMULL_3;//配置为0111/* 3、使能PLL:RCC_CR_PLLON = 1 */RCC->CR |= RCC_CR_PLLON; /* 5、等待开启成功:RCC_CR_PLLRDY*/while(!(RCC->CR & RCC_CR_PLLRDY));/* 6、配置系统时钟源为选择PLL:RCC_CFGR_SW[1:0] = 10 */RCC->CFGR &= ~RCC_CFGR_SW_0;RCC->CFGR |= RCC_CFGR_SW_1;//系统时钟SystemClock = 72MHz/* 7、设置AHB分频为1分频:RCC_CFGR_HPRE[3:0] = 0XXX */RCC->CFGR &= ~RCC_CFGR_HPRE_3;//AHB总线时钟 = 72MHz/* 8、设置APB2为1分频:RCC_CFGR_PPRE2[2:0] = 0xx*/RCC->CFGR &= ~RCC_CFGR_PPRE2_2;//APB2总线时钟 = 72MHz/* 9、设置APB1为2分频:RCC_CFGR_PPRE1[2:0] = 100 */RCC->CFGR &= ~(RCC_CFGR_PPRE1_0 |RCC_CFGR_PPRE1_1);RCC->CFGR |= RCC_CFGR_PPRE1_2;//APB1总线时钟 = 36MHz
}
上面的代码成功将系统时钟SystemClock配置为72MHz,AHB总线时钟配置为72MHz,APB1总线时钟配置为36MHz,APB2总线时钟配置为72MHz。
但是,还存在一个细节的疏忽,就是Flash参数的设置。因为代码存储在Flash中,要想CPU将Flash中的代码取出来进行执行,那么系统时钟SystemClock频率和Flash时钟频率同步。而Flash的时钟频率最大值为24MHz。所以需要添加系统时钟的等待。相关寄存器如下:
综上:完整的代码如下:
void Config_SystemClock(void)
{/* Flash参数的设置 */FLASH->ACR |= FLASH_ACR_PRFTBE;//使能Flash预取缓冲区/* 设置系统时钟进行2个等待周期 :FLASH_ACR_LATENCY[2:0] = 010*/FLASH->ACR &= FLASH_ACR_LATENCY_0;//FLASH_ACR_LATENCY_0 ((uint8_t)0x00)FLASH->ACR |= FLASH_ACR_LATENCY_2;//FLASH_ACR_LATENCY_2 ((uint8_t)0x02)/* 1、使能外部高速晶振HSE:RCC_CR_HSEON = 1(因为停机模式使HSE停止了,所以要使能)*/RCC->CR |= RCC_CR_HSEON;/* 2、等待开启成功:RCC_CR_HSERDY = 1 */while(!(RCC->CR & RCC_CR_HSERDY));//系统默认HSE未分频,所以可以不用配置HSE Prescaler/* 3、配置PLL输入时钟源为HSE:RCC_CFGR_PLLSRC = 1 */RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;/* 4、设置PLL倍频为9(只有PLL未开启才能配置):RCC_CFGR_PLLMULL[3:0] */RCC->CFGR |= RCC_CFGR_PLLMULL;RCC->CFGR &= ~RCC_CFGR_PLLMULL_3;//配置为0111/* 3、使能PLL:RCC_CR_PLLON = 1 */RCC->CR |= RCC_CR_PLLON; /* 5、等待开启成功:RCC_CR_PLLRDY*/while(!(RCC->CR & RCC_CR_PLLRDY));/* 6、配置系统时钟源为选择PLL:RCC_CFGR_SW[1:0] = 10 */RCC->CFGR &= ~RCC_CFGR_SW_0;RCC->CFGR |= RCC_CFGR_SW_1;//系统时钟SystemClock = 72MHz/* 7、设置AHB分频为1分频:RCC_CFGR_HPRE[3:0] = 0XXX */RCC->CFGR &= ~RCC_CFGR_HPRE_3;//AHB总线时钟 = 72MHz/* 8、设置APB2为1分频:RCC_CFGR_PPRE2[2:0] = 0xx*/RCC->CFGR &= ~RCC_CFGR_PPRE2_2;//APB2总线时钟 = 72MHz/* 9、设置APB1为2分频:RCC_CFGR_PPRE1[2:0] = 100 */RCC->CFGR &= ~(RCC_CFGR_PPRE1_0 |RCC_CFGR_PPRE1_1);RCC->CFGR |= RCC_CFGR_PPRE1_2;//APB1总线时钟 = 36MHz
}