文章基于适用于STM32F4系列,作者使用STM32F401CCU6开发板。
本文章基于此系列和开发板展开讨论。
时钟
时钟的作用
学习过数电课程的应该知道,时钟对于时序逻辑电路的重要性。
时钟在本质上就是一个确定频率(周期)的波形,在数字电路中是以方波的形式出现的。
时钟为存在先后次序的电路(逻辑关系)提供了一个时间基准。缺失了这个基准时序逻辑电路将无法正常运行
时钟的产生
产生最初时钟的方式常用的有两种。
一是RC震荡回路,这是利用电容的充放电产生周期性的波形。 它对于电容和电阻的精度要求高,而且震荡频率稳定性也欠佳,优点在于可以在制造完成后改变其频率
二是石英晶体震荡器,简称晶振,这种震荡器利用了石英晶体的压电效应。
无源晶振可以将其认为是一个检波器,允许特定频率的信号通过,加上放大电路(起振是利用电路的固有噪声)就可以产生时钟信号了。
有源晶振就是将放大器和无源晶振打包起来。
优点是成本低,精度高(再好的RC震荡电路也无法比及同水平的晶振),缺点是因为是利用特定形状的晶体,因此无法在出厂后改变其频率
三是锁相环(PLL),为了解决前两个方案的缺点,聪明的人们发明了一种叫做锁相环的东西,具体原理,这里只需要知道它可以时两个频率接近,相位接近的信号变成同相位同频率的信号。或者接近频率乘倍数的信号相位相同(其实就是跳过一个或几个周期,利用其边沿锁相),就像这样
上面的是晶振输入的标准信号
我们可以使用PLL进行分频和倍频操作。分频可以使用数电中的分频器然后送入锁相环进行锁相,倍频可以利用VCO产生高频时钟然后分频后送入PLL锁相
因此,我们可以使用这3个系统产生单片机所使用的时钟信号。
F4系列的时钟系统
时钟源
STM32F4系列有多个时钟源用于不同需求的外设
下表中的频率为本单片机所支持的,如果使用其他单片机请自行查询
缩写 |
中文名称 |
频率 |
作用 |
HSI |
高速内部时钟 |
默认16MHz |
备用系统时钟 |
HSE |
高速外部时钟 |
最大50MHz(最大晶振为25MHz) |
PLL倍频后做系统时钟 |
LSI |
低速内部时钟 |
32KHz |
看门狗用 |
LSE |
低速外部时钟 |
32.768KHz |
RTC用 |
总线
STM32F4系列有两种总线,AHB(高性能总线)用于高性能模块之间的连接,APB(外设总线)用于连接低速设备
AHB的时钟是系统时钟经过分频得到的,一般情况是与系统时钟相同。 AHB最高工作频率同系统时钟
APB有2根总线,他们的时钟不相同。 APB2的时钟频率大于APB1
APB2最高工作频率为84MHz, APB1最高工作频率为42MHz,
APB1和APB2可以分别分频AHB的时钟
下表中的频率为本单片机所支持的,如果使用其他单片机请自行查询
这是在标准库中查询时可能用到的一些名词解释
缩写 |
名称 |
最大频率 |
来源 |
SYSCLK |
系统时钟 |
168MHz |
HSI,或HSE,或Main PLL直接驱动 |
HCLK |
高速设备的时钟(如CPU) |
SYSCLK |
经AHB预分频器分频SYSCLK |
PCLK1 |
APB1时钟 |
42MHz |
经APB1预分频器分频HCLK |
PCLK2 |
APB2时钟 |
84MHz |
经APB2预分频器分频HCLK |
关于挂载在APB1/2总线下的计时器有一点需要注意
如果APB1/2没有分频,也就是分频系数的值为1,分频选项的宏定义一般为DIV1结尾
则定时器的时钟就是APB1/2的时钟
如果分频了,就是分频选项的值为2或4或8或16,分频选项的宏定义一般为DVI2/DVI4等
则定时器的时钟频率为APB1/2的时钟的两倍
标准库的时钟设置
内部高速时钟设置
注意:需要找到自己单片机型号所对应的宏定义处
输入HSI_VALUE跳转到定义处即可修改内部RC震荡器的数值(单位Hz)
外部高速时钟设置
注意:需要找到自己单片机型号所对应的宏定义处
输入HSE_VALUE跳转到定义处即可修改外部晶振的数值(单位Hz)
注意,因为系统时钟是由外部晶振通过PLL倍频得到的,因此需要修改系统时钟和PLL参数
输入SystemCoreClock跳转到定义处即可修改系统时钟的值(单位Hz)
输入PLL_M跳转到定义处即可修改有关系统时钟的PLL倍频选项
输入PLL_N跳转到定义处即可修改有关系统时钟的PLL倍频选项
输入PLL_P跳转到定义处即可修改有关系统时钟的PLL倍频选项
输入PLL_Q跳转到定义处即可修改有关系统时钟的PLL倍频选项
注意这四个的取值是有范围的
2 <= PLL_Q <= 15
2 <= PLL_M <= 63
192 <= PLL_N <= 432
PLL_P是2, 4, 6, 8其中之一
PLL的VCO的频率的计算公式是
PLL_VCO = [ ( HSE或HSI ) / PLL_M ] * PLL_N
其中HSE是外部晶振频率(单位MHz)
其中HSI是内部RC振荡器频率(单位MHz)
系统时钟频率是PLL_VCO经过分频后得到的
计算公式如下
SYSCLK = PLL_VCO / PLL_P
也就是说
SYSCLK = [ ( HSE或HSI ) / PLL_M ] * PLL_N / PLL_P
PLLQ是关于USB,SDIO,RNG的时钟,其值为
PLL_VCO / PLLQ
AHB时钟设置
注意:需要找到自己单片机型号所对应的宏定义处
输入**SetSysClock()**跳转到定义处,在下面有个带注释的寄存器操作代码
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
也就是这个,直接修改RCC_CFGR_HPRE_DIV1为自己需要的分频数,可以为
#define RCC_CFGR_HPRE_DIV1 ((uint32_t)0x00000000) /*!< SYSCLK not divided */
#define RCC_CFGR_HPRE_DIV2 ((uint32_t)0x00000080) /*!< SYSCLK divided by 2 */
#define RCC_CFGR_HPRE_DIV4 ((uint32_t)0x00000090) /*!< SYSCLK divided by 4 */
#define RCC_CFGR_HPRE_DIV8 ((uint32_t)0x000000A0) /*!< SYSCLK divided by 8 */
#define RCC_CFGR_HPRE_DIV16 ((uint32_t)0x000000B0) /*!< SYSCLK divided by 16 */
#define RCC_CFGR_HPRE_DIV64 ((uint32_t)0x000000C0) /*!< SYSCLK divided by 64 */
#define RCC_CFGR_HPRE_DIV128 ((uint32_t)0x000000D0) /*!< SYSCLK divided by 128 */
#define RCC_CFGR_HPRE_DIV256 ((uint32_t)0x000000E0) /*!< SYSCLK divided by 256 */
#define RCC_CFGR_HPRE_DIV512 ((uint32_t)0x000000F0) /*!< SYSCLK divided by 512 */
默认情况下,HCLK = SYSCLK
APB1/2时钟设置
注意:需要找到自己单片机型号所对应的宏定义处
输入SetSysClock() 跳转到定义处,在下面有个带注释的寄存器操作代码
/* PCLK2 = HCLK / 1*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
修改RCC_CFGR_PPRE2_DIV1和RCC_CFGR_PPRE1_DIV2即可
APB2可以取值为
#define RCC_CFGR_PPRE2_DIV1 ((uint32_t)0x00000000) /*!< HCLK not divided */
#define RCC_CFGR_PPRE2_DIV2 ((uint32_t)0x00008000) /*!< HCLK divided by 2 */
#define RCC_CFGR_PPRE2_DIV4 ((uint32_t)0x0000A000) /*!< HCLK divided by 4 */
#define RCC_CFGR_PPRE2_DIV8 ((uint32_t)0x0000C000) /*!< HCLK divided by 8 */
#define RCC_CFGR_PPRE2_DIV16 ((uint32_t)0x0000E000) /*!< HCLK divided by 16 */
APB1可以取值为
#define RCC_CFGR_PPRE1_DIV1 ((uint32_t)0x00000000) /*!< HCLK not divided */
#define RCC_CFGR_PPRE1_DIV2 ((uint32_t)0x00001000) /*!< HCLK divided by 2 */
#define RCC_CFGR_PPRE1_DIV4 ((uint32_t)0x00001400) /*!< HCLK divided by 4 */
#define RCC_CFGR_PPRE1_DIV8 ((uint32_t)0x00001800) /*!< HCLK divided by 8 */
#define RCC_CFGR_PPRE1_DIV16 ((uint32_t)0x00001C00) /*!< HCLK divided by 16 */
也就是说,APB1默认是2倍分频,APB2默认是不分频
默认值
前提:使用25MHz的外部晶振,没有修改标准库函数
根据上面的式子可以计算出各个时钟的默认值,这里只给结果了
缩写 |
名称 |
默认频率(单位MHz) |
PLL_VCO |
锁相环的压控振荡器 |
336 |
SYSCLK |
系统时钟 |
84 |
HCLK |
AHB时钟 |
84 |
PCLK1 |
APB1时钟 |
42 |
PCLK2 |
APB2时钟 |
84 |
因此STM32所有的定时器的时钟频率均为84MHz,也就是系统时钟频率