第八章 时钟:时钟树与编程配置

787 字 · 约 2 分钟学习笔记#STM32#嵌入式#学习笔记#单片机

8.1 [时钟]时钟树

时钟和时钟树的概念

分频器、锁相环和复用器

树根

内 外
低 LSI(Low Speed Internal,40kHz) LSE(Low Speed External,32.768kHz)
高 HSI(High Speed Internal,8MHz) HSE(High Speed External,4~16MHz)
  • 高速:
    • HSI:内部 8MHz RC 振荡器
    • HSE:外部 4~16MHz 晶振(常用 8MHz)
  • 低速:
    • LSI:内部 40kHz RC 振荡器(供 IWDG)
    • LSE:外部 32.768kHz 晶振(供 RTC)

树干

树枝

8.2 [时钟]时钟树编程

时钟树的初始状态

标准库的启动代码

实验代码

用分号注释
; LDR R0, =SystemInit

; BLX R0

#include "stm32f10x.h"

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOC, &GPIO_InitStruct);

    while(1)
    {
        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
        for(uint32_t i = 0; i<400000; i++); // 延迟500ms
        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
        for(uint32_t i = 0; i<400000; i++); // 延迟500ms
    }
}

时钟树的编程接口

RCC 定义

RCC = Reset And Clock Controller,是 STM32 中负责时钟管理、复位控制的核心模块,所有外设时钟的开启 / 配置都依赖它。

函数原型 核心作用
void RCC_HSEConfig(uint32_t RCC_HSE); 配置 高速外部时钟(HSE) 的开关状态(开启 / 关闭)
void RCC_HSICmd(FunctionalState NewState); 控制 ** 高速内部时钟(HSI)**的使能 / 禁用
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul); 配置锁相环(PLL)的时钟源(HSI/2 或 HSE)和倍频系数(×2~×16)
void RCC_PLLCmd(FunctionalState NewState); 控制 PLL(锁相环)的使能 / 禁用
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource); 选择 **系统时钟(SYSCLK)**的来源(HSI/HSE/PLL)
void RCC_HCLKConfig(uint32_t RCC_SYSCLK); 配置 AHB 总线时钟(HCLK),由 SYSCLK 分频得到(供 CPU 内核)
void RCC_PCLK1Config(uint32_t RCC_HCLK); 配置 APB1 总线时钟(PCLK1),由 HCLK 分频得到(低速外设专用,最高 36MHz)
void RCC_PCLK2Config(uint32_t RCC_HCLK); 配置 APB2 总线时钟(PCLK2),由 HCLK 分频得到(高速外设专用,最高 72MHz)
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG); 读取 RCC 相关标志位(如时钟稳定标志、复位标志等)
uint8_t RCC_GetSYSCLKSource(void); 获取当前 SYSCLK 的实际时钟源(HSI/HSE/PLL)

配置时钟树

配置Flash指令预取

App_SystemClock_Init

void App_SystemClock_Init(void);

void App_SystemClock_Init(void)
{
    FLASH_PrefetchBufferCmd(ENABLE);
    FLASH_SetLatency(FLASH_Latency_2);
    
    // #1. 开启HSE
    RCC_HSEConfig(RCC_HSE_ON);
    while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
    
    // #2. 配置并启动锁相环
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    RCC_PLLCmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    
    // #3. 配置AHB APB1 和APB2分频器的分频系数
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);
    RCC_PCLK2Config(RCC_HCLK_Div1);
    
    // #4. 切换SYSCLK的来源
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while(RCC_GetSYSCLKSource() != 0x08);
}

片上外设开关和复位

时钟控制函数

函数原型 作用 对应总线
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState); 开启 / 关闭AHB 总线外设时钟 AHB(如 DMA、SRAM、FSMC 等)
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); 开启 / 关闭APB2 总线外设时钟 APB2(如 GPIOA~G、USART1、SPI1、ADC1、TIM1 等高速外设)
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState); 开启 / 关闭APB1 总线外设时钟 APB1(如 USART2/3、SPI2、I2C1/2、CAN、TIM2~4 等低速外设,最高 36MHz)

外设复位函数

函数原型 作用 对应总线
void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); 复位APB2 总线上的外设 APB2
void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState); 复位APB1 总线上的外设 APB1

完整实验代码

#include "stm32f10x.h"

void App_SystemClock_Init(void);

int main(void)
{
    App_SystemClock_Init();
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOC, &GPIO_InitStruct);

    while(1)
    {
        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
        for(uint32_t i = 0; i<400000; i++); // 延迟500ms
        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
        for(uint32_t i = 0; i<400000; i++); // 延迟500ms
    }
}

void App_SystemClock_Init(void)
{
    FLASH_PrefetchBufferCmd(ENABLE);
    FLASH_SetLatency(FLASH_Latency_2);
    
    // #1. 开启HSE
    RCC_HSEConfig(RCC_HSE_ON);
    while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
    
    // #2. 配置并启动锁相环
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    RCC_PLLCmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    
    // #3. 配置AHB APB1 和APB2分频器的分频系数
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);
    RCC_PCLK2Config(RCC_HCLK_Div1);
    
    // #4. 切换SYSCLK的来源
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while(RCC_GetSYSCLKSource() != 0x08);
}

本文由 FormerlyXZ 创作, 采用CC BY-NC-SA 4.0 许可协议。转载请注明出处,禁止商业使用。

作者

评论

评论由 Giscus提供。首次评论需要在评论框里登录一次 GitHub(与页头的站点登录互相独立,这是浏览器安全限制), 之后当前浏览器会记住,不用反复登录;评论框里可以直接粘贴图片、拖入 PDF 等附件(GitHub 会帮你存好)。

还没有在播放

点碟片开始播放

0:00
0:00