stm32上电后默认使用的是内部8MHZ的HSI,速度比较慢,所以上电后要首先进行时钟的配置,让CPU工作在72MHZ的高速频率下。
一,涉及编程寄存器相关位详解
其中涉及到两个重要的时钟寄存器,时钟控制寄存器(RCC_CR),时钟配置寄存器(RCC_CFGR),RCC寄存器基地址为0x40021000
二,源代码及解析:
// 寄存器宏定义
// RCC寄存器基地址为0x40021000
#define RCC_BASE 0x40021000 // RCC部分寄存器的基地址
#define RCC_CR (RCC_BASE + 0x00) // RCC_CR的地址
#define RCC_CFGR (RCC_BASE + 0x04)
#define FLASH_ACR 0x40022000
// 用C语言来访问寄存器的宏定义
#define rRCC_CR (*((volatile unsigned int *)RCC_CR))
#define rRCC_CFGR (*((volatile unsigned int *)RCC_CFGR))
#define rFLASH_ACR (*((volatile unsigned int *)FLASH_ACR))
void Set_SysClockTo72M(void)
{ //定义三个局部变量在下面的do while 循环中做判断,
unsigned int rccCrHserdy = 0; //rccCrHserdy:外部高速时钟HSE是否就绪
unsigned int rccCrPllrdy = 0; //rccCrPllrdy:pll是否就绪
unsigned int rccCfrSwsPll = 0; //切换系统时钟是否完成
unsigned int faultTime = 0;
rRCC_CR = 0x00000083; //时钟控制寄存器(RCC_CR)的复位值就是0x00000083
rRCC_CR &= ~(1<<16); // 关闭HSEON
rRCC_CR |= (1<<16); // 打开HSEON,让HSE工作
do
{
rccCrHserdy = rRCC_CR & (1<<17); //检测第17位是否为1,即HSERDY:外部高速时钟就绪标志
faultTime++; //检测时间
}
while ((faultTime<0x0FFFFFFF) && (rccCrHserdy==0)); //如果faultTime一直加到0x0FFFFFFF还没就绪就超时
if ((rRCC_CR & (1<<17)) != 0) //如果外部高速时钟就绪标志为1就往下
{
rFLASH_ACR |= 0x10; //flash部分不用管
rFLASH_ACR &= (~0x03);
rFLASH_ACR |= (0x02);
// 到这里外部高速时钟HSE就ready了,下面再去配PLL并且等待他ready
rRCC_CFGR &= (~((0x0f<<4) | (0x07<<8) | (0x07<<11))); //时钟配置寄存器(RCC_CFGR)
// AHB和APB2未分频,APB1被2分频,所以最终:AHB和APB2都是72M,APB1是36M
rRCC_CFGR |= ((0x0<<4) | (0x04<<8) | (0x0<<11));
// 选择HSE作为PLL输入并且HSE不分频,所以PLL输入为8M
rRCC_CFGR &= (~((1<<16) | (1<<17))); // 清零bit17和bit16
rRCC_CFGR |= ((1<<16) | (0<<17)); // 置1 bit16
// 设置PLL倍频系数为9
rRCC_CFGR &= (~(0x0f<<18)); // 清零bit18-21
rRCC_CFGR |= (0x07<<18); // 9倍频
// 打开PLL开关
rRCC_CR |= (1<<24);
// do while 循环等待PLL时钟稳定
faultTime = 0;
do
{
rccCrPllrdy = rRCC_CR & (1<<25); //检测第25位是否为1
faultTime++;//检测时间
}
while ((faultTime<0x0FFFFFFF) && (rccCrPllrdy==0));
//while (rccCrPllrdy==0);
if ((rRCC_CR & (1<<25)) == (1<<25))
{
// 到这里说明PLL已经稳定了,可以用了,下面就可以切换系统时钟了
// 切换PLL输出为SYSCLK系统时钟
rRCC_CFGR &= (~(0x03<<0));
rRCC_CFGR |= (0x02<<0);
faultTime = 0;
do
{
rccCfrSwsPll = rRCC_CFGR & (0x03<<2); //检测第25位是否为1
faultTime++;//检测时间
}
while ((faultTime<0x0FFFFFFF) && (rccCfrSwsPll!=(0x02<<2)));
if ((rRCC_CFGR & (0x03<<2))== (0x02<<2))
{
// 到这里我们的时钟整个就设置好了,可以结束了
}
else
{
// 到这里就说明PLL输出作为SYSCLK不成功
while (1);
}
}
else
{
// 到这里就说明PLL启动时出错了,PLL不能稳定工作
while (1);
}
}
else
{
// HSE配置超时,说明HSE不可用,一般硬件就有问题要去查
while (1);
}
}