STM32 时钟系统(RCC)知识
STM32时钟非常重要,无论是MCU系统启动需要系统时钟(系统启动就会调用该函数),还是后面通信还有许许多多的外设功能都基于时钟这个组基础的功能
这个时钟源于哪里?(如果看前面代码就会意识到延时函数好像就和这个有关),目前已知的信息是:晶体振荡器像跷跷板一样给系统提供了一种标准(虽然不会太准是了),所以时钟源和频率关系很大。
STM32时钟详情
总结在一种图上就是这样的(倍频还有分频就不解释了)
还需要一些描述:
1.1 5个时钟源
STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。
-
①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。 ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。 ③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。WDG ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC ⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。 倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
图中最中间的最重要 1的是系统时钟SYSCLK(系统时钟不止一个)
1.2 系统时钟SYSCLK
系统时钟SYSCLK可来源于三个时钟源:
-
①、HSI振荡器时钟②、HSE振荡器时钟③、PLL时钟
系统时钟可以输出给其他外设: 图中最左侧MCO引脚(PA8)能够输出时钟信号(PLL/2、HSI、HSE、或者系统时钟)
实际上:FCLK,HCLK,PCLK都称为系统时钟(输出频率最大不得超过72MHz)https://blog.youkuaiyun.com/edgar_l/article/details/23611901
-
FCLK,提供给CPU内核的时钟信号,CPU的主频就是指这个信号; HCLK,提供给高速总线AHB的时钟信号; PCLK,提供给低速总线APB的时钟信号;
SYSCLK 系统时钟,最大72MHz,所以以上都不能超过这个数值
常用:HCLK :AHB总线时钟,由系统时钟SYSCLK 分频得到,一般不分频,等于系统时钟经过总线桥AHB–APB,通过设置分频,可由HCLK得到 PCLK1与PCLK2时钟不过PCLK2时钟最高可达72MHz,而PCLK1最大36MHz。PCLK2对应APB2外设。PCLK1对应APB1外设。
1.3 实际代码
在实际代码中这块很复杂,虽然只需要配置一个结构体,但是寄存器配置麻烦的要死
typedef struct
{
…
} RCC_TypeDef;
其中涉及到的库函数
教学中提到stm32系统启动会调用SystemInit();(3.5版本在单片机供电的时候会在startup_stm32f10x_xx.s自动调用,还有SYSCLK_FREQ_72MHz系统频率)
时钟源定义都在系统库中,仅学习没有意义,重要的是他用在了各种样的功能中(比方说延时函数)
2 定时器
2.1 倒计时定时器
这种定时器完全用不到时钟源,是一种娱乐的产物,简单来说就是一种通过C++计数后触发循环中止达到类似定时的效果。不介绍。
2.2 Systick定时器
Systick定时器是一个非常基础的MCU内部定时器(和现实时间不会太准就是了),会自己倒计时结束之后会重新装载数值(永不停止)。正点原子在延时函数中就是用了这个定时器
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。
Systick中断的优先级也可以设置。
信息轰炸结束:所以已知道的信息全部都是描述SysTick定时器的,这个定时器非常的复杂
单纯用来控制的与Systick定时器相关的就有四个寄存器
-
CTRL SysTick 控制和状态寄存器 LOAD SysTick 自动重装载除值寄存器 VAL SysTick 当前值寄存器 CALIB SysTick 校准值寄存器
控制和状态寄存器-CTRL(是否曾今计时结束,选择时钟源(内外)、计时结束产生异常请求、使能)
SysTick-> CALIB 不常用
在实际延时函数通过设定时钟源(SysTick_CLKSourceConfig() )以及系统固件库定义了的SysTick定时器中断( SysTick_Config(uint32_t
ticks) )
这里还需要值得注意的是:stm32虽然是一个MCU但是并不是真的将操作系统装进入了,目前嵌入式装系统有很多,比方说:UCOS
如果STM32还装了系统,这时候考虑的就有很大差别了
2.3代码部分
(正点原子的延时函数支持带入操作系统UCOSII ):
在ppt中谈到两种实现延时:
- 一种是通过中断的方式实现(还没介绍中断,就先不谈)
- 另一种就是使用查询寄存器的方式实现delay(代码了)
延时文件delay.h比较简单(只有第三个,不做介绍(没啥意义))
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);
如果考虑操作系统的话(比方说UCOSII ),那会更加复杂。
如果使用 OS 的时候,则会进行一些不同的配置,函数中的条件编译是根据 SYSTEM_SUPPORT_OS 这个宏来确定的,该宏在 sys.h 里面定义。但是delay.c比较复杂(但是不做OS,就随他吧)