100ask七天物联网训练营学习笔记 - RCC

100ask七天物联网训练营学习笔记 - RCC

今天回顾了直播课程又自己阅读芯片手册系统学习了stm32f103的RCC模块,针对学习的内容做一些梳理和总结。

1. 什么是时钟

计算机硬件中时钟不是我们日常理解的时钟,其实是一个固定频率的方波发生器,可以理解成队列在行进时喊得“1、2、1”口令。时钟系统就是CPU的脉搏,决定CPU速率。

2. 为什么要有时钟

时钟是为了同步CPU中的各种门电路。有了时钟信号,就可以通过每一个信号来驱动CPU进行工作,当然还包括其他需要同步时钟才能工作的外设电路。CPU以及不同的外设电路需要的时钟频率各不相同,为了满足大家的需求,通常系统中有多个时钟源组成时钟总线,优势在于可以满足不同速率需求的外设,同时也方便硬件的管理,关闭不需要工作的外设的时钟,从而优化能耗。

3. STM32的时钟

3.1 时钟源

STM32F103中的4种可选时钟源:

  1. 高速外部时钟 (HSE): 以外部晶振作时钟源,晶振频率可取范围为 4~16 MHz,常用 8MHz 晶振,开发板上的 8MHz 时钟就是指的这个。
  2. 高速内部时钟 (HSI): 由内部 RC 振荡器产生,频率为8MHz, 无须外接晶振,但精确性比外部时钟差。
  3. 低速外部时钟 (LSE): 以外部晶振作时钟源,可以提供时钟信号给实时时钟模块,一般采用 32.768KHz 晶振,较为少用。
  4. 低速内部时钟 (LSI): 由内部 RC 振荡器产生,也主要提供信号给实时时钟模块,频率在 30-60KHz 间浮动,较为少用。

单片机启动时默认使用高速内部时钟 (HSI),启动之后可以通过 RCC 时钟控制寄存器器改用其他时钟源。

3.2 系统时钟(SYSCLK)

STM32F103为例,系统时钟 SYSCLK 最大频率为 72MHz,它是供 STM32 中绝大部分部件工作的时钟源。系统时钟可由 PLL(锁相环)、HSI 或者 HSE 提供输入,并且通过 AHB(高速总线) 分频器分频后输出送给各模块使用。

3.3 锁相环(PLL)

如果打算使单片机运行在最高频率 (72 MHz),我们还需要倍频高速时钟源的时钟信号。锁相环能够将输出频率锁定在输入频率的正整数倍。STM32F103 的锁相环提供了 2 到 16 倍的倍频系数。假设我们使用高速内部时钟源 (8 MHz) ,想要使 STM32F103 达到最高主频 (72 MHz),那么我们就要要启用锁相环,设置为 9 倍倍频,并将SYSCLK时钟源设置为 PLL

3.4 时钟总线

STM32F103 中有 4 条时钟总线:

  1. AHB 高速总线,时钟为HCLK,最大频率为 72 MHz,时钟信号提供给存储器,DMACortex 内核,是内核运行的时钟,也就是主频,它的大小与STM32运算速度,数据存取速度密切相关。

  2. APB1 低速外设总线,时钟为 PCLK1,最大频率为 36 MHz,提供给挂载在APB1总线上的外设, 如 USART2

  3. APB2高速外设总线,时钟为 PCLK2,最大频率为 72 MHz,提供给挂载在APB2总线上的外设,如 GPIO, USART1

  4. FCLK自由运行时钟,独立于内核运行,一般设置为与 HCLK 同频率,常用于采样中断和调试模块供时。

3.5 时钟系统框图

请添加图片描述

4. 时钟的配置(以STM32F103为例)

4.1 时钟初始化流程

要想通过寄存器进行时钟配置,需要先搞清楚时钟初始化流程。

经过查阅芯片手册得知,RCC时钟初始化过程可以分为以下几个步骤:

  1. 启用外部晶振 (可选)
  2. 等待外部晶振稳定
  3. 设置各总线分频系数(AHB、APB1、APB2、PLL)
  4. 设置FLASH等待系数与预读取
  5. 启动PLL锁相环
  6. 等待PLL锁相环锁定
  7. SYSCLK切换到锁相环信号输入
  8. 等待信号切换完成

4.1 通过CubeMX配置时钟

请添加图片描述

请添加图片描述

由于STM32芯片上电时默认使用HSI作为时钟源,HSI集成在芯片内部,从上图可以看出其频率为8MHz,若让HSI时钟作为PLL信号源则必须要先进行2分频,导致SYSCLK最高为36MHz,所以我们通常会使用外部晶振。

4.2 通过寄存器配置时钟

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述

请添加图片描述
请添加图片描述请添加图片描述

// main.c
#include <stdint.h>

// 定义RCC的基地址
#define RCC_BASE        0x40021000U
// RCC_CR寄存器地址
#define RCC_CR          (RCC_BASE + 0x00U)
// RCC_CFGR寄存器地址
#define RCC_CFGR        (RCC_BASE + 0x04U)

// 定义FLASH的基地址
#define FLASH_BASE      0x40022000U
// FLASH_ACR寄存器地址
#define FLASH_ACR       (FLASH_BASE + 0x00U)

int main(void) 
{
    volatile uint32_t *rcc_cr = (uint32_t *)RCC_CR;
    volatile uint32_t *rcc_cfgr = (uint32_t *)RCC_CFGR;
    volatile uint32_t *flash_acr = (uint32_t *)FLASH_ACR;
    uint32_t tmp = 0;
    
    // 1. 使能外部晶振
    *rcc_cr |= (1 << 16);
    
    // 2. 等待外部晶振稳定
    while (!(*rcc_cr & (1U << 17)));
    
    // 3. 分别设置AHB总线时钟不分频、APB1总线时钟2分频,APB2总线时钟不分频
    *rcc_cfgr |= (0 << 4) | (4 << 8) | (0 << 11);
    
    // 3. 设置PLL倍频系数为9
    *rcc_cfgr |= (7 << 18);
    
    // 3. 设置HSE不分频信号作为PLL信号源
    *rcc_cfgr |= (1 << 16);
    
    // 4. 设置FLASH等待系数与预读取,其实我也不知道这个起什么作用,手册说需要设置
    *flash_acr |= (2 << 0) | (1 << 3) | (1 << 4);
    
    // 5. 启动PLL
    *rcc_cr |= (1 << 24);
    
    // 6. 等待PLL锁定
    while (!(*rcc_cr & (1U << 25)));
    
    // 7. 把PLL切换为SYSCLK的时钟源
    *rcc_cfgr |= (2 << 0);
    
    // 8. 等待SYSCLK信号切换完成
    do {
        tmp = *rcc_cfgr & (3 << 2);
        tmp >>= 2;
    } while (tmp != 2);
    
    // 此时,系统时钟频率为72M
    while (1)
    {
    
    }
}

至此,完全通过寄存器完成了RCC的配置。

5. 总结

至此,完全通过寄存器完成了RCC的配置。我们发现RCC的配置过程还是相对繁琐的,我们日常使用时完全可以通过CubeMX来进行配置,但是还是要熟悉时钟初始化的流程,才能更好的理解时钟系统。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值