一、系统时钟配置
基本概念
HSE 振荡器时钟:可以由外部源(可能是其他单片机输出的时钟信号)和外部晶振提供。野火霸天虎 V2 开发板是由外部晶振提供信号源,使用时需要先确定稳定 (RCC->CR的HSERDY)并使能 (RCC->CR的HSEON)后使用。
HSI 系统内部时钟:开机上电后系统首先使用的时钟,SYSCLK 默认初始使用的时钟。
PLLCLK 时钟:由 HSE 时钟经过 PLL 机构进行分频、倍频之后得到的时钟。
SYSCLK 系统时钟:可以设置成 HSI、HSE 以及 PLLCLK 作为输入。
时钟树
时钟树左侧都是和片外进行信号通信的输入输出的时钟源信号,右侧箭头最终指向系统给各个片内设备的时钟。
先关注系统时钟,也就是 HCLK到AHB总线、内核、存储器和DMA的时钟。通过时钟树可以看到,到 AHB 总线、内核、存储器和 DMA 的时钟由 SYSCLK 提供,而 SYSCLK 由 HSI、HSE 或 PLLCLK 三者其中一个提供,通常为 PLLCLK。而 PLLCLK 的源头是 HSE 经过 PLL 的各种变频变化后得到。

这样系统的时钟的来源就很清晰了,这样就可以配置系统时钟了。

代码编写
手动写代码配置时钟,通过正常配置时钟后点亮 LED,并通过配置时钟频率来控制 LED 闪烁的速度快慢。
仅展示时钟配置的函数部分(部分参考标准库固件时钟配置函数)
#include "bsp_myclkconfig.h"
void MyClkconfig(){
__IO uint32_t HSE_READY = 0;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
while(1){
HSE_READY = RCC->CR & RCC_CR_HSERDY;
if(HSE_READY == (0xFFFF & RCC_CR_HSERDY)){
break;
}
}
RCC->APB1ENR |= (uint32_t)(RCC_APB1ENR_PWREN);
PWR->CR |= PWR_CR_VOS_1;
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
// 由于PLLCFGR中PLLP的值2、4、6、8对应00、01、10、11,所以需要搞(((2 >> 1) - 1) << 16)这么个操作才能把值弄对。
RCC->PLLCFGR |= 25 | 336<<6 | (((2 >> 1) - 1) << 16) | 7 << 24;
RCC->CR |= RCC_CR_PLLON;
while(1){
if((RCC->CR & RCC_CR_PLLRDY) == 0){
break;
}
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
;
{
}
}
BUG 点记录
在编写到判断 HSE 时钟是否初始化完成的时候,下意识地写了 if(HSE_READY == 1)的时候 break 跳出 while 循环的代码,以为能用,结果一直不通。后面 debug 后才发现,当 HSE_READY的值为 1 的时候,RCC->CR & RCC_CR_HSERDY的值应该是 0x0200,也就是说是第 14 位的值为 1 才对,所以应该要判断是否等于 0x0200才对。但是这么写兼容性又不是很强,所以考虑写成 0xFFFF & RCC_CR_HSERDY(虽然也不会真的移植到其他 F4xx 板子上用)。
二、配置 MCO 输出时钟信号
配置 MCO 后可以通过 GPIO 口输出时钟信号,作为一个信号源给其他的设备。
配置方式:先初始化 MCOx 对应的 GPIO,再使能 MCOx 即可。
手册翻阅
-
先查 MCOx 对应的 GPIO
在《STM32F4xx 参考手册》中找到
6.2.10 时钟输出功能,可以看到有 MCO1 和 MCO2,其中 MCO1 对应 PA8,MCO2 对应 PC9。 -
对 MCO 进行基础配置
在《STM32F4xx 参考手册》中找到
6.3.3 RCC 时钟配置寄存器 (RCC_CFGR),MCOx 可以选择时钟源,MCOxPRE 可以配置分频。
代码编写
init_MCO1.c
void init_MCO1(){
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIOA_CONFIG;
GPIOA_CONFIG.GPIO_Pin = GPIO_Pin_8;
GPIOA_CONFIG.GPIO_Mode = GPIO_Mode_AF;
GPIOA_CONFIG.GPIO_OType = GPIO_OType_PP;
GPIOA_CONFIG.GPIO_Speed = GPIO_Low_Speed;
GPIO_Init(GPIOA, &GPIOA_CONFIG);
RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_2);
}
由于没有示波器,好像测不出结果,没办法验证,先这样了。