任务:
1. 理解时钟树的基本概念,能大致看懂时钟树框图。
2. 重点掌握AHB、APB1、APB2时钟频率划分。
3. 能实现频率修改操作。
1.时钟树
1.1 时钟
问:什么是时钟?为什么要有时钟?时钟是怎么产生的?
1. 什么是时钟?
时钟就是具有周期性的脉冲信号,相当于单片机的心脏,给单片机提供一个统一的信号,要想使用
单片机的外设必须开启相应的时钟。
对CPU来说,假设CPU在一个时钟周期内执行一条指令,若时钟频率越高,则时钟周期更短,则
在相同的时间CPU能够执行更多的指令,CPU的运行速度更快
2.
为什么要有时钟?
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟就是CPU的脉
搏,决定cpu速率,像人的心跳一样只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口等等其他操作),时钟的重要性不言而喻。
3.
时钟是怎么产生的?
时钟产生比较复杂,方法也有很多种
,
但它们都是从晶体谐振器
(
简称晶振
)
开始的,
在石英晶片上加
上交变电压,晶体就会产生机械振动,机械形变振动又会产生交变电场,尽管这种交变电场的电压极 其微弱,但其振动频率是十分稳定的。(我只能说神奇的物理世界)
1.2 时钟树概述
STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,为了降低整个芯片的功耗,所
有外设时钟默认都是关闭状态(disable),当我们使用某个外设就要开启这个外设的时钟(enable)。
不同外设需要的时钟频率不同,没必要所有外设都用高速时钟造成浪费,而且有些外设也接受不了
这么高的频率,这也是为什么STM32有四个时钟源(HSE、 LSE、HSI、LSI)的原因,就是为了兼容 不同速度的外设。
而51单片机不需要配置时钟,是因为一个时钟开了之后所有的功能都可以用了,而这个时钟是默认
开启的,所以51单片机无法做到低功耗。
STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗
能。时钟树框图见《STM32F4xx中文参考手册》6.2章节
1.3 主时钟树详解
在STM32中,有4个时钟源:
Notice:
以上频率仅针对
STM32F40x
,其它的以数据手册为准
1. HSE 高速外部时钟信号
可以由有源晶振或者无源晶振提供,频率从
4-26MHZ
不等,我们的开发板使用的是
8MHZ
的晶
振,当
HSE
故障时,高速的内部时钟信号
HSI
会作为
备用的系统时钟
,
直到
HSE
恢复正常。
2. 锁相环PLL
PLL
的主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件,由
HSE
或者
HSI
提供时钟
输入信号。
主
PLL
有两路的时钟输出,第一个输出时钟
PLLCLK
用于系统时钟,
F407
里面最高是
168M
。
第二个输出用于
USB OTGFS
的时钟(
48M
)、
RNG
和
SDIO
时钟(
<=48M
)。
专用的
PLLI2S
用于生成精确时钟,给
I2S
提供时钟。
PLLCLK
的计算公式为:
VCOCLK_IN = PLLCLK_IN / M
VCOCLK_OUT = VCOCLK_IN * N
PLLCLK_OUT=VCOCLK_OUT/P
3. 系统时钟SYSCLK
系统时钟来源可以是:
HSI
、
PLLCLK
、
HSE
,具体的由时钟配置寄存器
RCC_CFGR
的
SW
位配
置。我们这里设置系统时钟:
SYSCLK = PLLCLK =168M
。
如果系统时钟是由
HSE
经过
PLL
倍频 之后的
PLLCLK
得到,当
HSE
出现故障的时候,系统时钟会
切换为
HSI=16M
,直到
HSE
恢复正常为止。
4. APB2 总线时钟PCLK2
APB2 总线时钟
PCLK2
由
HCLK
经过高速
APB2
预分频器得到,分频因子可以是
:[1,2,4
,
8
,
16]
,
具体由时钟配置寄存器
RCC_CFGR
的
PPRE2
位设置。
PCLK2
属于高速的总线时钟,片上高速的 外 设就挂载到这条总线上,比如全部的GPIO
、
USART1
、
SPI1
等。
这里设置为2
分频,即
PCLK2 = HCLK /2= 84M
5. APB1
总线时钟
PCLK1
APB1
总线时钟
PCLK1
由
HCLK
经过低速
APB
预分频器得到,分频因子可以是
:[1,2,4
,
8
,
16]
,
具体由时钟配置寄存器
RCC_CFGR
的
PPRE1
位设置。
PCLK1
属于低速的总线时钟,最高为
42M
,
片上低速的外设就挂载到这条总线上,比如
USART2/3/4/5
、
SPI2/3
,
I2C1/2
等。
这里设置为
4
分频,即
PCLK1= HCLK/4 = 42M
。
1.4 启动文件
提问:
在
main
函数里,我们没有调用任何函数修改时钟参数,那么时钟频率被修改后是怎么生效的呢?
启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:
1.
初始化堆栈指针
SP=_initial_sp
2.
初始化
PC
指针
=Reset_Handler
3.
初始化中断向量表
4.
配置系统时钟
5.
调用
C
库函数
_main
初始化用户堆栈,从而最终调用
main
函数去到
C
的世界
比如:
开辟栈的大小为
0X00000400
(
1KB
),名字为
STACK
,
NOINIT
即不初始化,可读可写,
8
(
2^3
)字节对齐。
SystemInit()
是一个标准的库函数,在
system_stm32f4xx.c
这个库文件总定义。主要作用是配置系
统时钟
__main
是一个标准的
C
库函数,主要作用是初始化用户堆栈,最终调用
main
函数去到
C
的世界。
这就是为什么我们写的程序都有一个
main
函数的原因。如果我们在这里不调用
__main
,那么程
序最终就不会调用我们
C
文件里面的
main
。
回到刚刚的问题:在
main
函数里,我们没有调用任何函数修改时钟参数,那么时钟频率被修改后是怎
么生效的呢?
答:既然
main
函数没有调用,那修改时钟的操作当然是在
main
函数之前执行的
SystemInit()
函数设置的 了。
static void SetSysClock(void)
;
系统时钟计算方式:
超频和降频