stm32时钟系统
基于stm32f407zgt6芯片
给单片机提供一个时钟信号(一个非常稳定的频率信号),使单片机各内部组件同步工作,并且在和外部设备通信时是也能达到同步。
为什么要了解时钟体系呢?
动态调整运行频率,就可以控制性能与功耗,以及系统精确的定时!
先简单介绍一下51时钟
51时钟的组成主要是由外部所带11.0592Mhz的晶振提供,以达到相对稳定的定时以及最后面的串口波特率计算。
外部晶振每震荡一次单片机执行一条指令
Stm32时钟
stm32共有5个时钟源分别为 HSE、LSE、HSI、LSI、PLL,其中,HSE叫做高速外部时钟,可以接外部 4-16 MHz的时钟源;HSI 是高速内部时钟,它内部有一个RC振荡器,可以提供 8 MHz的时钟;LSE是低速外部时钟,外接32.768KHz时钟,作为RTC时钟;LSI 是低速内部时钟,也是一个内部的RC 振荡器,可以提供 40 KHz的时钟,可用作独立看门狗,或RTC的时钟;最后一个 PLL 是锁相环倍频,它的来源可以是HSI/2、HSE、HSE/2,倍频范围为 2-16 倍
①HSI 时钟信号由内部 16 MHz RC 振荡器生成,可直接用作系统时钟,或者用作 PLL 输入。HSI RC 振荡器的优点是成本较低(无需使用外部组件)。此外,其启动速度也要比 HSE 晶振块,但即使校准后,其精度也不及外部晶振或陶瓷谐振器。
②HSE 是高速外部时钟,可接石英 / 陶瓷谐振器,或者接外部时钟源,频率范围是 4MHz – 16MHz ;
③32 kHz 低速内部 RC (LSI RC),该 RC 用于驱动独立看门狗,也可选择提供给 RTC 用于停机/待机模式下的自动唤醒;
④LSE 是低速外部时钟,接频率为 32.768KHz 的石英晶体,用于驱动 RTC 时钟 (RTCCLK)对于每个时钟源来说,在未使用时都可单独打开或者关闭,以降低功耗。
当然我们可以选取需要的时钟源作为系统时钟源
PLL是系统默认的系统时钟源
选择其他的时钟作为系统时钟源我们只需要在main函数开头 添加一下代码即可
-选择PLL作为系统时钟源
1 RCC‐>CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
2 RCC‐>CFGR |= RCC_CFGR_SW_PLL;
- 选择HSI作为系统时钟源
1 RCC‐>CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
2 RCC‐>CFGR |= RCC_CFGR_SW_HSI;
- 选择HSE作为系统时钟源
1 RCC‐>CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
2 RCC‐>CFGR |= RCC_CFGR_SW_HSE;
较为常用的是PLL时钟源,我们主要介绍PLL
STM32F4xx 器件具有两个 PLL: ● 主 PLL (PLL) 由 HSE 或 HSI振荡器提供时钟信号,并具有两个不同的输出时钟:
— 第一个输出用于生成高速系统时钟(最高达 168 MHz)
—第二个输出用于生成 USB OTG FS 的时钟 (48 MHz)、随机数发生器的时钟 (<=48 MHz) 和 SDIO 时钟(<=48 MHz)。 ,PLL常用于频率翻倍,经过PLL的频率调整可输出一个新的频率,充宏观上来说可以看作汽车的变速箱。 经过分频后输出的频率最高不超过72MHZ
来子参考手册时钟树
当然这也许有点难懂下面是我学习时所保存的简图
可以简单了解下时钟提供的
当然在系统中我们有是需要他工作在不同的频率是我们需要对其频率进行一个设置,此时对需要对PLL时钟进行设置,PLL又分为PLL_M与PLL_N,在官方源码中这是定义在system_stm32f4xx.h文件中
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M 25
/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
#define PLL_Q 7
#if defined (STM32F40_41xxx)
#define PLL_N 336
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 2
#endif /* STM32F40_41xxx */
官网使用的外部高速晶振25MHz,而我开发板上使用的外部晶振是8MHZ,但如果用官方提供的数据进行计算的话得出来的频率不准确此时我们需要对其进行更改PLL_M 8,既可以
但要注意应为官方默认对stm32主要文件是只读的,我们需要在安装目录下找到文件并取消他的只读权限如果这些设置好了我们介绍一下PLL时钟的运算公式
f(vco时钟)=PLL(时钟输入)(PLLN/PLL_M)
f(PLL时钟输出)=f(vco)/PLL_P
例如 外部晶振为8MHZ
PLL输出频率=8336/8/2得到精准的168MHZ频率,大家可以更具自己的需求来计算修改PLL_M的值,甚至超频,但经过实验最高可以超频到281Mhz,相应的功耗也要增加
注意::他们的值是由范围的
不同的芯片,倍频(频率翻倍)公式是不一样的,需要查询芯片手册!
2≤ PLL_M ≤63
192≤ PLL_N ≤432
PLL_P:2、4、6、8
经过简明的介绍也许大家对时钟系统有一些简单的了解,下面我介绍一下运用系统内部定时实现1us与1ms的精准定时
void delay_ms(uint32_t n)
{
while(n--)
{
SysTick->CTRL = 0; // Disable SysTick,关闭系统定时器
SysTick->LOAD = (168000)-1; // 配置计数值(168000)-1 ~ 0
SysTick->VAL = 0; // Clear current value as well as count flag
SysTick->CTRL = 5; // Enable SysTick timer with processor clock
while ((SysTick->CTRL & 0x10000)==0);// Wait until count flag is set
}
SysTick->CTRL = 0; // Disable SysTick
}
void delay_us(uint32_t n)
{
while(n--)
{
SysTick->CTRL = 0; // Disable SysTick,关闭系统定时器
SysTick->LOAD = 168-1; // 配置计数值(168000)-1 ~ 0
SysTick->VAL = 0; // Clear current value as well as count flag
SysTick->CTRL = 5; // Enable SysTick timer with processor clock
while ((SysTick->CTRL & 0x10000)==0);// Wait until count flag is set
}
SysTick->CTRL = 0; // Disable SysTick
}`
我先介绍一下SysTick的寄存器有什么作用
SysTick->CTRL:简单来说就是启不启动定时功能,当他为0时就关闭
SysTick->LOAD :计数次数,应为,没有分频此时系统时钟频率为168MHZ,每计数一次时间为1/168000000 s,当计数次数为168时极为1us
SysTick->VAL = 0;:(复位值不可预测)
while ((SysTick->CTRL & 0x10000)==0);此条程序主要是检测计数次数到达LOAD中数值没
注:寄存器定义在core_cm4.h中,定义如下
typedef struct
{
__IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IO uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IO uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__I uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
时钟系统就简明的介绍到这,自学有点粗超,大家提出来相互学习