STM32的时钟总体设计
- 时钟源:纯外部(不精准)、内外部(时钟产生的振荡电路在外部,然而晶振在内部)、纯内部(间接从内部接入一个时钟)。
- 单片机外部有齐全独立的多个时钟。
- PLL时钟:锁相环电路。性能就是进行倍频。
- 外部设有两套独立时钟:HSx(高速时钟源)和LSx(低速时钟源)。
- 纯外部:HSI、LSI。
- 内外部;HSE、LSE。
- 纯内部:OSC_IN、OSC32_IN(应用较少)
- 红方框中SYSCLK是零碎时钟,是共给CPU的时钟(SYSCLK是多少CPU主频就是多少);之后的局部是配置各个模块的时钟。
- 上电复位后,默认用的是外部时钟(红线门路)(外部时钟不精确)
STM32时钟寄存器
- STM32所有的时钟上电默认是敞开的(即寄存器默认都是0)。
- 下列寄存器图中上面的r、w是可读可写的意思(r:可读,由硬件置位。w:可写)(rw:既可读又可写)
时钟管制寄存器(RCC_CR)
- PLLRDY:PLL时钟就绪标记,PLL锁定后由硬件置一。(PLL倍频不是一瞬间实现的,须要肯定的工夫)(0:PLL未锁定。1:PLL锁定)
- PLLON:PLL使能,由软件置一和清零。当PLL时钟被用作或被抉择将要作为零碎时钟时,该位不能被清零。(0:PLL敞开。1:PLL使能)
- HSERDY:内部高速时钟就绪标记。由硬件置一来批示内部4-16MHz振荡器曾经稳固。在HSEON位清零后,该位须要6个内部4-25MHz振荡器周期清零。(0:未就绪。1:就绪)
- HSEON:内部高速时钟使能。由软件置一和清零。(0:HSE振荡器敞开。1:HSE振荡器关上)
- HSIRDY:外部高速时钟就绪标记。由硬件置一来批示外部8MHz振荡器曾经稳固。在HSION位清零后,该位须要6个外部8MHz振荡器周期清零。(0:外部8MHz振荡器未就绪,1:外部8MHz振荡器就绪)
- HSION:外部高速时钟使能。由软件置一和清零。(0:外部8MHz振荡器敞开。1:外部8MHz振荡器关上)
时钟配置寄存器(RCC_CFGR)
留神与上图的时钟树绝对应。
- USBPRE:USB预分频。由软件置一或清零来产生48MHz的USB时钟。在RCC_APB1ENR寄存器中使能USB时钟之前,必须保障该位曾经无效。如果USB时钟被使能,该位不能被清零。(0:PLL时钟1.5倍分频作为USB时钟。1:PLL时钟间接作为USB时钟)
- PLLMUL:PLL倍频系数。由软件设置来确定PLL倍频系数。只有在PLL敞开的状况下才可被写入(留神:PLL的输入频率不能超过72MHz)
- PLLXTPRE:HSE分频器作为PLL输出。(软件置一和清零抉择HSE是否分频)
- PLLSRC:抉择PLL输出时钟源。(0:抉择HSI经2分频后作为PLL输出时钟。1:抉择HSE时钟作为PLL输出时钟)
- ADCPRE:ADC预分频。由软件设置。
- PPRE2:高速APB预分频设置(APB2)。由软件设置预分频系数。
- PPRE1:低速APB预分频设置(APB1)。由软件设置预分频系数。
- HPRE: AHB预分频。由软件设置预分频系数。
- SW:零碎时钟切换(即时钟树中的SW地位)。(00:HSI)(01:HSE)(10:PLL)(11:不可用)
时钟中断寄存器 (RCC_CIR)
- PLLRDYC:革除PLL就绪中断(1:革除PLL就绪中断标记位PLLRDYF)
- HSERDYC:革除HSE就绪中断(1:革除HSE就绪中断标记位HSERDYF)
- HSIRDYC:革除HSI就绪中断(1:革除HSI就绪中断标记位HSIRDYF)
- LSERDYC:革除LSE就绪中断(1:革除LSE就绪中断标记位LSERDYF)
- LSIRDYC:革除LSI就绪中断(1:革除LSI就绪中断标记位LSIRDYF)
- PLLRDYIE:PLL就绪中断使能(1:HSE就绪中断使能)
- HSIRDYIE:HSI就绪中断使能(1:HSI就绪中断使能)
- LSERDYIE:LSE就绪中断使能(1:LSE就绪中断使能)
- LSIRDYIE:LSI就绪中断使能(1:LSI就绪中断使能)
- PLLRDYF:PLL就绪中断标记(在PLL就绪且PLLRDYIE位被置一时,由硬件置一)
- HSERDYF:HSE就绪中断标记(在内部低速时钟就绪且HSERDYIE位被置一时,由硬件置一)
- HSIRDYF:HSI就绪中断标记
- LSERDYF:LSE就绪中断标记
- LSIRDYF:LSI就绪中断标记
代码示例
// 寄存器宏定义// 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))// 函数作用:时钟源切换到HSE并且使能PLL,将主频设置为72MHzvoid Set_SysClockTo72M(void){ unsigned int rccCrHserdy = 0; unsigned int rccCrPllrdy = 0; unsigned int rccCfrSwsPll = 0; unsigned int faultTime = 0; rRCC_CR = 0x00000083; //复位时钟,设置为初始状态(上电复位用的HSI时钟) //开启内部时钟 rRCC_CR &= ~(1<<16); // 敞开HSEON rRCC_CR |= (1<<16); // 关上HSEON,让HSE工作 do { rccCrHserdy = rRCC_CR & (1<<17); //检测第17位是否为1(检测内部高速时钟是否准备就绪) faultTime++;//超时计数 } while ((faultTime<0x0FFFFFFF) && (rccCrHserdy==0)); //内部时钟开启胜利 if ((rRCC_CR & (1<<17)) != 0) { rFLASH_ACR |= 0x10; rFLASH_ACR &= (~0x03); rFLASH_ACR |= (0x02); // 到这里HSE就准备就绪了,上面再去配PLL并且期待他准备就绪 //复位配置寄存器RCC_CFGR(APB、AHB不分频,时钟切换不可用) rRCC_CFGR &= (~((0x0f<<4) | (0x07<<8) | (0x07<<11))); // AHB和APB2未分频,APB1被2分频,所以最终:AHB和APB2都是72M,APB1是36M rRCC_CFGR |= ((0x00<<4) | (0x04<<8) | (0x00<<11)); rRCC_CFGR &= (~((1<<16) | (1<<17))); // 清零bit17和bit16 rRCC_CFGR |= ((1<<16) | (0<<17)); // 抉择HSE作为PLL输出,HSE不分频 // 设置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)); 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); }}