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);
	}
}
相关推荐
猫猫的小茶馆1 小时前
【STM32】预分频因子(Prescaler)和重装载值(Reload Value)
c语言·stm32·单片机·嵌入式硬件·mcu·51单片机
riveting2 小时前
明远智睿H618:开启多场景智慧生活新时代
人工智能·嵌入式硬件·智能硬件·lga封装·3506
菜菜why2 小时前
MSPM0G3507学习笔记(一) 重置版:适配逐飞库的ti板环境配置
笔记·学习·电赛·嵌入式软件·mspm0
夜阑卧听风吹雨,铁马冰河入梦来2 小时前
Spring AI 阿里巴巴学习
人工智能·学习·spring
三万棵雪松3 小时前
【STM32HAL-第1讲 基础篇-单片机简介】
stm32·单片机·嵌入式硬件
玉树临风江流儿3 小时前
炸鸡派-基础测试例程
单片机·嵌入式硬件
板栗焖小鸡3 小时前
STM32-PWM驱动无源蜂鸣器
stm32·学习
Code季风3 小时前
Gin 中间件详解与实践
学习·中间件·golang·go·gin
智者知已应修善业5 小时前
【51单片机用数码管显示流水灯的种类是按钮控制数码管加一和流水灯】2022-6-14
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
sealaugh3211 小时前
aws(学习笔记第四十八课) appsync-graphql-dynamodb
笔记·学习·aws