前面代码并没有设置时钟为什么可以直接使用。

内部晶振不稳定,当我们上电后,会自动产生振动,自动产生时钟,但是晶振不稳定。
不经过PPLMUL,默认使用8MHZ。所以如果我们想要72MHZ,则需要使用外部晶振

当接上外部晶振,当接通电源之后,不用软件操作,会自动产生振动。可以进行分频等操作。

从外部接上外部晶振的时候,我们需要等待一段时间,让其稳定后,才开始工作。(所以要进行判断)

当上电后,经过他时,要等待一段时间,让其稳定后,才可以开始工作。(所以我们有一个寄存器专门用来判断其是否准备好开始工作,当我们去读取到其准备好了才可以进行下一步)


- #ifndef __CLOCK_H__
- #define __CLOCK_H__
-
- #include "gpio.h"
-
-
- // 寄存器宏定义
- // 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,将主频设置为72MHz
- void Set_SysClockTo72M(void);
-
-
-
- #endif
-

#define rRCC_APB2ENR (*((unsigned int *)RCC_APB2ENR))
RCC->CR就相当于rRCC_APB2ENR

- //复位RCC_CR寄存器
- rRCC_CR=0x00000083;

&:将某一些位置0
|:将某一些位置1



- //开启外部时钟(外部晶振)
- //第一步:先置0【将bit16清零】
- rRCC_CR &= ~(1<<16);//关闭HSEON
-
- //第二步:在置1
- rRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作
do while十分适合检测是否超时!!!!!!!



- do{
- //检测HSEREAY(bit17)是否为1,1表示准备好
- Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17
- faultTime++;
- }while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0))
- //跳出do-while 1)要么超时2)要么准好了


- rFLASH_ACR |= 0x10;
- rFLASH_ACR &= (~0x03);
- rFLASH_ACR |= (0x02);



- //HPRE【AHB】:对应bit4-bit7:不分频(000)
- //PPRE1【APB1】:对应bit8-bit10:进行二分频(100)
- //PPRE2【APB2】:对应bit11-bit13:不分频(000)
- //AHB和APB2未分频,APB1被2分频
- //所以最终:AHB和APB2都是72MHZ,APB1是36MHZ
- //第一步:先置0
- rRCC_CFGR=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));
- //等价于:rRCC_CFGR=(~(0x3ff<<4));
- //第二步:置1
- rRCC_CFGR=(((0x0<<4) | (0x04<<8) | (0x0<<11)));




- //设置为输入时钟:bit16
- //设置为不分频:bit17
- //第一步:先置0
- rRCC_CFGR &=(~((1<<16) | (1<<17)));
- //第二步:置1
- rRCC_CFGR |= ((1<<18) | (0<<17));
因为我们在开发板上接上的外部晶振就是8MHZ,如果我们想要在内部使用72MHZ,则需要在内部进行分频率(9倍)




- //9分频:0111:0x07
-
- rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21
- rRCC_CFGR |= (0x07<<18);//设置为9倍频


- //七、打开PLL开关
- rRCC_CR |= (1<<24);


- //八、等待开启PLL开启成功
- do{
-
- Rcc_CR_PLL_Ready=rRcc_CR & (1<<25);//检测第25位是否为1
- faultTime++;
- }while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0))





- //到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了
- rRCC_CFGR &=(~(0x03)<<0);
- rRCC_CFGR |=(0x10<<0);


- do{
- RCC_CF_SWS_PLL=rRCC_CFGR & (0x03<<2);//读出bit2-bit3
- faultTime++;
- //0x02<<2:表示此时转换成PLL
- }while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready!=(0x02<<2)))

- #include "clock.h"
-
- void Set_SysClockTo72M(void){
-
- //检测外部晶振是否准备好
- unsigned int Rcc_CR_HSE_Ready=0;
- //等待开启PLL开启成功
- unsigned int Rcc_CR_PLL_Ready=0;
- //判断切换成PLL是否成功
- unsigned int RCC_CF_SWS_PLL=0;
- unsigned int faultTime=0;//判断等待是否超时
-
-
- //一、复位RCC_CR寄存器
- rRCC_CR = 0x00000083;
-
- //二、开启外部时钟(外部晶振)
- //第一步:先置0【将bit16清零】
- rRCC_CR &= ~(1<<16);//关闭HSEON
-
- //第二步:在置1
- rRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作
-
- //三、检测外部时钟开启是否成功
- do{
- //检测HSEREAY(bit17)是否为1,1表示准备好
- Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17
- faultTime++;
- }while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0));
- //跳出do-while 1)要么超时2)要么准好了
-
-
- //判断是超时还是准备好
- //注意点:不能直接使用“Rcc_CR_HSE_Ready”因为rRCC_CR是需要读一次寄存器
- //但是读出的结果可能还未改变,所以一定不能直接使用
- if((rRCC_CR&(1<<17))!=0)//rRCC_CR&(1<<17)==1
- {//这里HSE就ready,下面再去配置PLL并且等待他ready
-
- //四、对其进行预分频
- //HPRE【AHB】:对应bit4-bit7:不分频(000)
- //PPRE1【APB1】:对应bit8-bit10:进行二分频(100)
- //PPRE2【APB2】:对应bit11-bit13:不分频(000)
- //AHB和APB2未分频,APB1被2分频
- //所以最终:AHB和APB2都是72MHZ,APB1是36MHZ
- //第一步:先置0
- rRCC_CFGR=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));
- //等价于:rRCC_CFGR=(~(0x3ff<<4));
- //第二步:置1
- rRCC_CFGR=(((0x0<<4) | (0x04<<8) | (0x0<<11)));
-
-
- //五、设置SHE为输入时钟,同时HSE不分频
- //选择HSE作为PLL输入并且HSE不分频
- //设置为输入时钟:bit16
- //设置为不分频:bit17
- //第一步:先置0
- rRCC_CFGR &=(~((1<<16) | (1<<17)));
- //第二步:置1,bit16
- rRCC_CFGR |= ((1<<18) | (0<<17));
-
-
- //六、设置PLL倍频系数
- //9分频:0111:0x07
-
- rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21
- rRCC_CFGR |= (0x07<<18);//设置为9倍频
-
- //七、打开PLL开关
- rRCC_CR |= (1<<24);
-
-
- //八、等待开启PLL开启成功
- do{
-
- Rcc_CR_PLL_Ready=rRCC_CR & (1<<25);//检测第25位是否为1
- faultTime++;
- }while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0));
-
- if((rRCC_CR & (1<<25)) == (1<<25)){
- //到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了
-
- //九、切换成PLL
- rRCC_CFGR &=(~(0x03)<<0);
- rRCC_CFGR |=(0x10<<0);
-
- //十、判断切换成PLL是否成功
- do{
- RCC_CF_SWS_PLL=rRCC_CFGR & (0x03<<2);//读出bit2-bit3
- faultTime++;
- //0x02<<2:表示此时转换成PLL
- }while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready!=(0x02<<2)));
-
- //十一、此时PLL转换成功
- if((rRCC_CFGR & (0x03<<2))==(0x02<<2)){
-
- //到这里我们的时钟整个就设置好了,可以结束了
- }else{
- //到这里说明PLL输出作为PLL失败
- while(1);
- }
- }
- else{
- //到这里说明PLL启动时出错了,PLL不能稳定工作
- while(1);
- }
- }else{//超时,或者未准备好,此时HSE不可以使用
- while(1);
- }
-
- }
-
- void delay(){
- unsigned int i=0,j=0;
- for(i=0;i<1000;i++){
- for(j=0;j<2000;j++){
- }
- }
- }
-
- void led_init(){
- rRCC_APB2ENR = 0x00000008;
-
- rGPIOB_CRH = 0x33333333;
- rGPIOB_ODR = 0x0000ff00;//全灭
-
- }
- void led_flash(void){
- unsigned int i=0;
- for(i=0;i<3;i++){
- rGPIOB_ODR = 0x00000000;//全亮
- delay();
- rGPIOB_ODR = 0x0000ff00;//全灭
- delay();
- }
- }
- void main(void){
- led_init();
- led_flash();
- Set_SysClockTo72M();
- led_flash();
- }
但是实际上并无法实现,只能在闪烁完3次后就熄灭。
led初始化时,默认是全亮的
把点亮led灯的函数加到clock中去,看看代码运行到哪里不会亮
因为我们多次使用到超时变量,则每一个进入do-while循环之前要重新置0


