STM32完全学习——系统时钟设置

一、时钟框图的解读

首先我们知道STM32在上电初始化之后使用的是内部的HSI未经过分频直接通过SW供给给系统时钟,由于内部HSI存在较大的误差,因此我们在系统完成上电初始化,之后需要将STM32的时钟切换到外部HSE作为系统时钟,那么我们需要完成下面一些设置完成切换。首先我们需要打开外部HSE的震荡电路然后,等待外部震荡电路就绪后,在切换PLLTPRE为HSE的1分频,在设置PLLSRC为PLLXTPRE过来的时钟。然后设置PLLMUL倍频系数,然后打开PLL开关等待PLL稳定。然后设置APB1总线为2分频,最后切换系统时钟为PLL输出的时钟。

二、相关寄存器

三、编程实现

cpp 复制代码
#ifndef __SYSTEM_H__
#define __SYSTEM_H__

#define uint unsigned int
	
typedef struct rRCC
{
	uint CR;
	uint CFGR;
	uint CIR;
	uint APB2RSTR;
	uint APB1RSTR;
	uint AHBENR;
	uint APB2ENR;
	uint APB1ENR;
	uint BDCR;
	uint CSR;
	uint AHBRSTR;
	uint CFGR2;	
}RCC_TypeDef;

static RCC_TypeDef *RCC = (RCC_TypeDef *)0x40021000;

void set_system_clock(void);

#endif
cpp 复制代码
#include "system.h"

uint HSERDY_FLAG = 0;     //HSE就绪标志
uint PLLRDY_FLAG = 0;     //PLL就绪标志
uint SWRDY_FLAG  = 0;     //时钟切换标志
uint false_time = 0;      //超时时间标志

void set_system_clock(void)
{
	rFLASH_ACR = 0x00000032; //这个用来设置系统时钟于Flash访问时间的比率 根据系统时钟的不同设置的值不同
	RCC->CR &= (~(0x01 << 16));      //将HSEON这位清零
	RCC->CR |= (0x01 << 16);         //开启外部HSE振荡器电路
	
	
	do                               //判断外部HSE电路是否就绪
	{
		HSERDY_FLAG = ((RCC->CR) & (0x01 << 17));
		false_time++;
	}while((false_time < 0x00ffffff) && (HSERDY_FLAG == 0));
	false_time = 0;
	if (HSERDY_FLAG != 0)            //如果外部振荡器电路就绪才会执行
	{ 
		RCC->CFGR &= (~((0x01 << 17) | (0x01 << 16) | (0x0f << 18)));  //设置PLL倍频系数为9倍频
		RCC->CFGR |= ((0x01 << 16) | (0x0 << 17) | (0x07 << 18));  //设置PLL时钟来源为PREDIV1 并且设置PLLXTPRE不对输入的时钟分频
		RCC->CR &= (~(0x01 << 24));       //使能PLL时钟
		RCC->CR |= (0x01 << 24);
		do 
		{
			PLLRDY_FLAG = ((RCC->CR) & (0x01 << 25));
			false_time++;
		}while((false_time < 0x00ffffff) && (PLLRDY_FLAG == 0));  //等待PLL时钟就绪
		false_time = 0;
		if (((RCC->CR) & (0x01 << 25)) != 0)
		{	
			RCC->CFGR &= (~((0x01 << 22) | (0x07 << 8)));  
			RCC->CFGR |= ((0x0 << 22) | (0x04 << 8));     //全速USB OTG配置为PLL输出2分频 APB1总线2分频 PLL输出作为系统时钟
			RCC->CFGR &= ~(0x03 << 0); 
			RCC->CFGR |= (0x02);    //切换系统时钟为PLL输出时钟
			do
			{
				SWRDY_FLAG = ((RCC->CFGR) & (0x03 << 2));
		        false_time++;	
			}while((false_time < 0x00ffffff) && ((SWRDY_FLAG) == 0));
			if (((RCC->CFGR) & (0x03 << 2)) != 0)  //判断时钟是否切换成功
			{
				
			}
			else
			{
				while(1);
			}
		}
	}
	else
	{
		while(1);
	}
}

上面的代码一个是.h文件另一个是.c文件,但是当我们运行上面的代码时我发现了一个问题,当我们将时钟切换到PLL输出作为系统时钟时,系统就不运行了。就死机了。这是为什么呢,通过翻看数据手册发现,系统时钟和内部flah有一些关系,我们来看flash的寄存器就可以发现。

我们来看bit0-2发现,当复位时默认是000,因此系统时钟必须在0到24MHz之间,这时候我们使用的是内部的HSI时钟,时钟只有8MHz,因此这个时候系统是可以正常运行的,但是当我们将时钟切换到外部HSE时,由于我们做了一系列的倍频,因此这个时候系统时钟到了72MHz,因此我们呢这里需要将这个寄存器的值也设置为010,系统就可以正常运行了。

cpp 复制代码
#define FLASH_ACR  0x40022000
#define rFLASH_ACR *((uint *)FLASH_ACR)

void set_system_clock(void)
{
	rFLASH_ACR = 0x00000032;     //这个用来设置系统时钟于Flash访问时间的比率 根据系统时钟的不同设置的值不同
	
	RCC->CR &= (~(0x01 << 16));      //将HSEON这位清零
	RCC->CR |= (0x01 << 16);         //开启外部HSE振荡器电路
	
	
	do                               //判断外部HSE电路是否就绪
	{
		HSERDY_FLAG = ((RCC->CR) & (0x01 << 17));
		false_time++;
	}while((false_time < 0x00ffffff) && (HSERDY_FLAG == 0));
	false_time = 0;
	if (HSERDY_FLAG != 0)            //如果外部振荡器电路就绪才会执行
	{ 
		RCC->CFGR &= (~((0x01 << 17) | (0x01 << 16) | (0x0f << 18)));  //设置PLL倍频系数为9倍频
		RCC->CFGR |= ((0x01 << 16) | (0x0 << 17) | (0x07 << 18));  //设置PLL时钟来源为PREDIV1 并且设置PLLXTPRE不对输入的时钟分频
		RCC->CR &= (~(0x01 << 24));       //使能PLL时钟
		RCC->CR |= (0x01 << 24);
		do 
		{
			PLLRDY_FLAG = ((RCC->CR) & (0x01 << 25));
			false_time++;
		}while((false_time < 0x00ffffff) && (PLLRDY_FLAG == 0));  //等待PLL时钟就绪
		false_time = 0;
		if (((RCC->CR) & (0x01 << 25)) != 0)
		{	
			RCC->CFGR &= (~((0x01 << 22) | (0x07 << 8)));  
			RCC->CFGR |= ((0x0 << 22) | (0x04 << 8));     //全速USB OTG配置为PLL输出2分频 APB1总线2分频 PLL输出作为系统时钟
			RCC->CFGR &= ~(0x03 << 0);  
			RCC->CFGR |= (0x02); 
			do
			{
				SWRDY_FLAG = ((RCC->CFGR) & (0x03 << 2));
		    false_time++;	
				
			}while((false_time < 0x00ffffff) && ((SWRDY_FLAG) == 0));
			
			if (((RCC->CFGR) & (0x03 << 2)) != 0)
			{
				
			}
			else
			{
				while(1);
			}
		}
	}
	else
	{
		while(1);
	}
}
相关推荐
yi.Ist4 分钟前
数据定义语言-DDL操作
数据库·学习·mysql·oracle·大海豚
周周记笔记1 小时前
GD32F450xx MCU Datasheet 解读:硬件测试工程师的测试方法论
单片机·嵌入式硬件
骐骥14 小时前
学习:javaScriptProxy和registerJavaScriptProxy有什么区别,能注册多少个对象
学习·鸿蒙
Huathy-雨落江南,浮生若梦4 小时前
Caddy 学习笔记 - 反向代理与 IP 封禁
笔记·学习·tcp/ip
AOI小白新手上路5 小时前
江科协51单片机16-1 AD/DA ADC 三通道综合显示(LCD1602 版)改造说明
单片机·嵌入式硬件·51单片机
HUI-4745 小时前
EG1135|SSOP‑16 同步整流降压控制器,大功率外置 MOS 降压优选
单片机·嵌入式硬件·硬件工程
单片机仿真设计6 小时前
【proteus仿真】基于 STM32 单片机恒温箱控制系统设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
m4Rk_6 小时前
【论文阅读】Agent 记忆机制(57):MemSearch-o1——从查询词元生长证据,重组 Deep Search 记忆路径
论文阅读·人工智能·学习·开源·github
国科安芯6 小时前
星载CAN总线通信网络中抗辐射MCU的通信可靠性设计分析
网络·人工智能·分布式·单片机·嵌入式硬件·架构
闭月之泪舞6 小时前
C++编程学习
c++·学习