时钟
外部时钟
外部时钟更为精确
高速外部时钟信号 --- HSE(High-Speed External Clock Signal)
- 复用端口:OSC_OUT 和 OSC_IN
管脚信息可在 数据手册 中查看
- 频率:4~16 MHz(一般连接 8MHz 晶振)
低速外部时钟信号# --- LSE(Low-Speed External Clock Signal)
- 复用端口:OSC32_OUT 和 OSC32_IN
管脚信息可在 数据手册 中查看
- 频率:32.768 kHz(只能连接 32.768kHz 晶振)
内部时钟
高速内部时钟信号 --- HSI(High-Speed Internal Clock Signal)
- 频率:8 MHz(由内部 RC振荡器 产生)
低速内部时钟信号 --- LSI(Low-Speed Internal Clock Signal)
- 频率:40 kHz 左右(由内部 RC振荡器 产生)
锁相环时钟 --- PLLCLK(Phase Locked Loop Clock)
- 产生:由图中可以看出,PLLCLK有两种来源—— HSI 和 HSE,经过倍频(PLLMUL)后输出。
- 频率:在默认情况下,输入时钟为 HSE = 8MHz ,倍频因子为 x9,系统时钟选择 PLLCLK 达到最大频率 72MHz。如果使用内部时钟,输入时钟为 HSI / 2 = 4MHz,倍频因子最大为 x16,最高只能输出 64MHz时钟。
- 注意:
- PLL的设置(选择HIS振荡器除2或HSE振荡器为PLL的输入时钟,和选择倍频因子)必须在其被激活前完成。一旦PLL被激活,这些参数就不能被改动(自行配置时钟时一定要先设置再激活!)。
- 如果需要在应用中使用USB接口,PLL必须被设置为输出48或72MHZ时钟,用于提供48MHz的USBCLK时钟。
RCC寄存器
-
时钟控制寄存器 --- CR(Clock control register):使能 和 调整 HSI、HSE、PLL 时钟;
- 作用---使能:位0为 HSI 使能;位16为 HSE 使能;位24为 PLL 使能;
- 作用---时钟就绪标志:位1为 HSI 就绪;位17为 HSE 就绪;位25为 PLL 就绪;
- 复位值:0x000 XX83
-
时钟配置寄存器 --- CFGR(Clock configuration register):配置 分频和倍频、系统时钟和PLL时钟选择、时钟外部输出(至示波器等);
- 作用---选择系统时钟:位1:0,00为HSI,01为HSE,10为PLL;
- 作用---选择 PLL 时钟( HSE 或 HSI / 2 或 HSE / 2);
- 作用---(预)分频和倍频,并设置分频因子和倍频因子;
- 作用---输出时钟至IO口(IO口最高频率为50MHz,即输出时钟频率最大为50MHz);(其实高于50MHz也可以,但是会失真)
- 复位值:0x0000 0000
-
时钟中断寄存器 --- CIR(Clock interrupt register):使能时钟就绪的中断,清楚时钟就绪标志位;
- 作用---使能时钟就绪的中断:时钟准备就绪,标志位置位,如果使能了该中断则会产生一个中断;
- 作用---清除(复位)时钟准备就绪后产生的标志位;
- 作用---判断 HSE 是否故障,若失效则 位7"CSCC" 置1;
- 复位值:0x0000 0000
-
APB2外设复位寄存器 --- APB2RSTR(APB2 peripheral reset register):将APB2总线上的外设恢复至复位值;
- 复位值:0x0000 0000
-
APB1外设复位寄存器 --- APB1RSTR(APB1 peripheral reset register):将APB1总线上的外设恢复至复位值;
- 复位值:0x0000 0000
-
AHB外设时钟使能寄存器 --- AHBENR(AHB peripheral clock enable register):使能AHB总线上的外设;
- 复位值:0x0000 0014
- 注意:该寄存器只有DMA1、DMA2、SRAM、FLITF、CRC(循环冗余校验)、FSMC(可变静态存储控制器)、SDIO的时钟使能,其中DMA1、DMA2、SRAM、FLITF的时钟默认已经被使能;
-
APB2外设时钟使能寄存器 --- APB2ENR(APB2 peripheral clock enable register):使能APB2总线上的外设;
- 复位值:0x0000 0000
- 注意:除 EXTI(外部中断)外所有挂载在 APB2总线 上的外设均能通过该寄存器使能;
-
APB1外设时钟使能寄存器 --- APB1ENR(APB1 peripheral clock enable register):使能APB1总线上的外设;
- 复位值:0x0000 0000
- 注意:除 RTC(Real-Time Clock)(实时时钟)外所有挂载在 APB1总线上的外设均可通过该寄存器使能;
-
备份域控制寄存器 --- BDCR(Backup domain control register):RTC(Real-Time Clock)(实时时钟)的使能和配置,LSE 的使能和配置;
- 复位值:0x0000 0000
- 注意:RTC是一个掉电后还继续运行的定时器
-
控制/状态寄存器 --- CSR(Control/status register):储存/消除 复位标志,LSI 的就绪标志位;
- 复位值:0x0000 0000
常用RCC固件库函数 (stm32f10x_rcc.h)
固件库中 HSE默认为 8M, 默认使用 HSE 9倍频 的 PLL时钟 作为系统时钟,若要更改时钟配置,推荐使用固件库函数更改而非直接更改固件库
AHB上外设使能函数 --- RCC_AHBPeriphClockCmd
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
- RCC_AHBPeriph:对应外设;
- NewState:ENABLE 为使能,DISABLE 为关闭;
- 示例:
//使能 FMSC
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE)
APB2高速总线上外设使能函数 --- RCC_APB2PeriphClockCmd
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
- RCC_APB2Periph:对应外设;
- NewState:ENABLE 为使能,DISABLE 为关闭;
- 示例:
//使能 GPIOA口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)
APB1低速总线上外设使能函数 --- RCC_APB1PeriphClockCmd
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
- RCC_APB1Periph:对应外设;
- NewState:ENABLE 为使能,DISABLE 为关闭;
- 示例:
//使能 USART2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC清理函数 --- RCC_DeInit
void RCC_DeInit(void);
- 作用:只打开 HSI 时钟,其余所有时钟包括系统时钟均关闭,清楚所有时钟就绪中断标志位,关闭时钟对外输出;
- 示例:
RCC_DeInit();
HSE时钟使能函数 --- RCC_HSEConfig
void RCC_HSEConfig(uint32_t RCC_HSE);
- RCC_HSE:可以为 OFF,ON,Bypass;
- 作用:参数 RCC_HSE 为 RCC_HSE_OFF 时关闭 HSE 时钟,为 RCC_HSE_ON 时打开 HSE 时钟,为RCC_HSE_Bypass 时打开 HSE 时钟的同时还打开 时钟安全系统(CSS) 的时钟;
- 注明:时钟安全系统(CSS) 开启后,如果HSE时钟发生故障,HSE振荡器被自动关闭,时钟失效事件将被送到高级定时器(TIM1和TIM8)的刹车输入端,并产生时钟安全中断CSSI,此CSSI中断连接到Cortex™-M3的NMI中断;
- 示例:
//使能HSE
RCC_HSEConfig(RCC_HSE_ON);
HSE判断时钟启动就绪函数--- RCC_WaitForHSEStartUp
typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
ErrorStatus RCC_WaitForHSEStartUp(void);
- 返回值:SUCCESS 表示启动成功, ERROR 表示启动失败;
- 示例:
ErrorStatus HSEStatus;
HSEStatus = RCC_WaitForHSEStartUp();
//等待 HSE 就绪
if(HSEStatus == SUCCESS)
{
// HSE 就绪后实现后需要运行的程序
}
HSI时钟使能函数 --- RCC_HSICmd
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
void RCC_HSICmd(FunctionalState NewState);
- NewState:可以为 ENABLE,DISABLE;
- 示例:
//使能HSI
RCC_HSICmd(ENABLE);
PLL时钟配置函数 --- RCC_PLLConfig
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul);
- RCC_PLLSource:PLL的时钟源,可选择 HSI二分频(RCC_PLLSource_HSI_Div2)、HSE(RCC_PLLSource_HSE_Div1)、HSE二分频(RCC_PLLSource_HSE_Div2);
- RCC_PLLMul_x:倍频因子,互联型 x 可为 (2~9),其他则可为 (2~16);
- 示例:
//配置锁相环时钟 PLLCLK = HSE * 9
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
PLL时钟使能函数 --- RCC_PLLCmd
void RCC_PLLCmd(FunctionalState NewState);
- NewState:可以为 ENABLE,DISABLE;
- 注意:必须先配置PLL,再使能;
- 示例:
//使能 PLL
RCC_PLLCmd(ENABLE);
系统时钟配置函数 --- RCC_SYSCLKConfig
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
- RCC_SYSCLKSource:系统的时钟源,可选择 HSI(RCC_SYSCLKSource_HSI)、HSE(RCC_SYSCLKSource_HSE)、PLL(RCC_SYSCLKSource_PLLCLK);
- 示例:
//选择系统时钟 为PLL时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
自行配置系统时钟
程序思路
- RCC清除,便于自行配置;
- 使能 HSE 或 HSI(系统时钟为高速时钟);
- 等待使能完成;
- 使能FLASH预取缓冲器,并设置为2个等待周期;
- 设置 AHB、APB1、APB2的预分频因子;
- 配置锁相环时钟:选择锁相环时钟源和倍频因子;
- 使能锁相环时钟(再次强调要先配置锁相环再使能);
- 等待PLL时钟稳定;
- 选择系统时钟为PLL时钟;
- 等待系统时钟稳定;
(若不选择PLL为系统时钟,且不需USB,可不开启PLL)
以下程序为复制粘贴火哥源码。
HSE作为系统时钟
// 默认 HSE 晶振频率为 8M
void HSE_SetSysClk(uint32_t RCC_PLLMul_x) //时钟为8M*x
{
ErrorStatus HSEStatus;
//RCC寄存器复位
RCC_DeInit();
//使能HSE
RCC_HSEConfig(RCC_HSE_ON);
//等待HSE就绪
HSEStatus = RCC_WaitForHSEStartUp();
if(HSEStatus == SUCCESS)
{
//使能预取缓冲器(预取指)
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//配置两个等待周期
FLASH_SetLatency(FLASH_Latency_2);
//设置分频因子
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
//配置锁相环时钟 PLLCLK = HSE * RCC_PLLMul_x
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_x);
//使能PLL
RCC_PLLCmd(ENABLE);
//等待PLL时钟稳定
while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
//选择系统时钟 为PLL时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while( RCC_GetSYSCLKSource() != 0x08 );
}
else
{
// 故障后处理程序
}
}
HSI作为系统时钟
void HSI_SetSysClk(uint32_t RCC_PLLMul_x) //时钟为4M*x
{
__IO uint32_t HSIStatus = 0;
//RCC寄存器复位
RCC_DeInit();
//使能HSI
RCC_HSICmd(ENABLE);
//等待HSI就绪
HSIStatus = RCC->CR & RCC_CR_HSIRDY;
if(HSIStatus == RCC_CR_HSIRDY)
{
//使能预取缓冲器(预取指)
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//配置两个等待周期
FLASH_SetLatency(FLASH_Latency_2);
//设置分频因子
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
//配置锁相环时钟 PLLCLK = HSE * RCC_PLLMul_x
RCC_PLLConfig(RCC_PLLSource_HSI_Div2,RCC_PLLMul_x);
//使能PLL
RCC_PLLCmd(ENABLE);
//等待PLL时钟稳定
while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
//选择系统时钟 为PLL时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while( RCC_GetSYSCLKSource() != 0x08 );
}
else
{
// 故障后处理程序
}
}