打印
[STM32F1]

STM32F103系统时钟配置

[复制链接]
49|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-11-25 11:07 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定CPU速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。

一、STM32F103时钟介绍
STM32F103本身十分复杂,外设非常多 但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费 并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32F103的时钟系统和时钟树。



1.1 系统时钟
系统时钟(SYSCLK)有多种选择,图中左边的部分就是设置系统时钟使用那个时钟源;

HSI振荡器时钟:HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高;
HSE振荡器时钟:HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz;
PLL时钟;其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz;
系统时钟的右边,则是系统时钟通过AHB预分频器,给相对应的外设设置相对应的时钟频率.

从左到右可以简单理解为 各个时钟源--->系统时钟来源的设置--->各个外设时钟的设置。

在我们使用的STM32F103F103开发板中:

OSC32_IN、OSC32_OUT连接了32.768kHz的晶振,用于给RTC提供时钟信号;
OSC_IN、OSC_OUT连接了8MHz的晶振,作为系统时钟的来源。
Keil编写程序是默认的时钟为72Mhz,其实是这么来的:

外部晶振(HSE)提供的8MHz通过PLLXTPRE分频器后;
进入PLLSRC选择开关;
进而通过PLLMUL锁相环进行倍频(x9)后,为系统提供72MHz的系统时钟(SYSCLK);
之后是AHB预分频器对时钟信号进行分频,然后为低速外设提供时钟。
1.2 USB时钟
STM32F103中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取(唯一的),可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。

1.3 时钟输出到外部
STM32F103可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。可以把时钟信号输出供外部使用。

1.4 外设时钟
系统时钟通过AHB分频器给外设提供时钟,AHB分频器可选择1、2、4、8、16、64、128、256、512分频。其中AHB分频器输出的时钟送给如下模块使用:

SDIO;
FSMC;
内核总线:送给AHB总线、核心存、储器和DMA使用的HCLK时钟。;
Tick定时器:通过8分频后送给Cortex的系统定时器时钟;
直接送给Cortex的空闲运行时钟FCLK;
APB1外设:送给APB1分频器。APB1分频器可选择1、2、4、8、16分频;
其输出一路供APB1外设使用(PCLK1,最大频率36MHz);
另一路送给通用定时器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2-7使用;
APB2外设:送给APB2分频器。APB2分频器可选择1、2、4、8、16分频:
其输出一路供APB2外设使用(PCLK2,最大频率72MHz);
另一路送给高级定时器。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用;
另外APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2、4、6、8分频;
经过2分频送至SDIO的AHB。
需要注意的是,如果APB预分频器分频系数是1,则定时器时钟频率 (TIMxCLK) 为PCLKx。否则,定时器时钟频率将为APB域的频率的两倍:TIMxCLK = 2xPCLKx。

1.4.1 APB1和APB2的对应外设



APB1上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等;

而APB2上面连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-Pg)、第二功能I/O(AFIO)口等。

二、时钟相关寄存器
2.1 时钟控制寄存器(RCC_CR)





2.2 时钟配置寄存器(RCC_CFGR)







2.3 时钟中断寄存器(RCC_CIR)









2.4 APB2外设复位寄存器(RCC_APB2RSTR))







2.5 APB1外设复位寄存器(RCC_APB1RSTR))







2.6 AHB外设使能寄存器(RCC_AHBENR)





2.7 APB2外设时钟使能寄存器(RCC_APB2ENR)





2.8 APB1外设时钟使能寄存器(RCC_APB1ENR)





三、时钟配置源码
3.1 RCC_TypeDeff
RCC寄存器结构RCC_TypeDeff,在文件stm32f10x_map.h中定义如下:

/*------------------------ Reset and Clock Control ---------------------------*/
typedef struct
{
  vu32 CR;             // 时钟控制寄存器 ;
  vu32 CFGR;         // 时钟配置寄存器 ;
  vu32 CIR;                 // 时钟中断寄存器 ;
  vu32 APB2RSTR; // APB2外设复位寄存器 ;
  vu32 APB1RSTR; // APB1外设复位寄存器 ;
  vu32 AHBENR;         // AHB外设时钟使能寄存器 ;
  vu32 APB2ENR;         // APB2外设时钟使能寄存器 ;
  vu32 APB1ENR;         // APB1外设时钟使能寄存器 ;
  vu32 BDCR;         // 备份域控制寄存器 ;
  vu32 CSR;                 // 控制/状态寄存器 ;
} RCC_TypeDef;

#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)

#ifdef _RCC
  #define RCC                 ((RCC_TypeDef *) RCC_BASE)
#endif /*_RCC */

在第二节中我们已经对RCC_TypeDef结构体中定义的大部分结构体进行了详细的介绍,那么我们如何编码去初始化这些寄存器呢?

3.2 RCC初始化
这里我们采用HSE作为系统时钟输出,正常使用的时候也都是使用外部时钟。其初始化流程如下:

(1) APB1外设复位,复位结束;

RCC_APB1RSTR寄存器每一位写入1,然后再写入0;
(2) APB2外设复位,复位结束;

RCC_APB2RSTR寄存器每一位写入1,然后再写入0;
(3)AHB开启SRAM、闪存(睡眠模式时);

(4)APB1外设时钟关闭;

RCC_APB1ENR寄存器每一位写入0;
(5)APB2外设时钟关闭;

RCC_APB2ENR寄存器每一位写入0;

(6)复位MCO、USBPRE、PLLMUL、PLLXTRRE、PLLSRC、ADCPRE、PPRE2、PPRE1、HPRE、SW;PLLON、CSSON、HSEBYP、HSEON;

RCC_CR寄存器相应位写入0;
RCC_CFGR寄存相应位写入0;
(7) 设置:

HSEON使能:开启高速外部时钟信号,即设置RCC_CR寄存器的位16为1;
等待HSERDY就绪:即等待RCC_CR寄存器位17置1;
设置APB1、APB2、AHB分频系数、PLL倍频系数;
系统时钟为72MHz:PLL倍频系数设置为9,即RCC_CFGR寄存器位[21:18]设置为0111b;
AHB预分频器设置为1分频:即RCC_CFGR寄存器位[7:4]设置为0xxxb;
APB1预分频器由RCC_CFGR寄存器位[10:8]设置;如果设置为2分频,则时钟频率为36MHz;
APB2预分频器由RCC_CFGR寄存器位[13:11]设置;如果设置为1分频,则时钟频率为72MHz;
设置PLLSRC:选择HSE时钟作为PLL输入时钟;
设置HSE时钟作为PLL输入时钟,即RCC_CFGR寄存器位16设置为1;
PLL使能:即设置RCC_CR寄存器的位24为1;
等待PLL就绪:即等待RCC_CR寄存器位25置1;
设置SW:系统时钟切换PLL作为系统时钟,即设置RCC_CFGR寄存器的位[1:0]为10b;
等待PLL切换为系统时钟输入源:即等待RCC_CFGR寄存器的位[3:2]为10b。
3.2.1 STM32_Clock_Init
/*****************************************************************************************************
*
*           Description:系统时钟初始化
       PLL        :倍频系数 2~16   
*                                        APB1设置为2分频,APB2设置为1分频,AHB设置为1分频
*                  设置PLLCLK作为系统时钟
*
****************************************************************************************************/
void STM32_Clock_Init(u8  PLL)
{
         u8 temp=0;
         RCC_Init();                             //复位并配置向量表
         RCC->CR |=0x00010000;                   //外部高速时钟使能HSEON:即外部晶振(4MHZ~16MHZ)
         while(!(((RCC->CR>>17)&0x01)==0x01));   //等待外部时钟就绪
         RCC->CFGR = 0x00000400;                 //APB1设置为2分频,APB2设置为1分频,AHB设置为1分频
         PLL-=2;                                 //抵消两个单元
         RCC->CFGR|=PLL<<18;                     //设置PLL的值2~16      
         RCC->CFGR|=1<<16;                       //PLLSRC ON  HSE时钟作为PLL输入时钟
         FLASH->ACR |= 0x32;                     //FLASH两个延时周期
         RCC->CR|=0x01000000;                    //PLLON
         while(!(((RCC->CR>>25)&0x01)==0x01));   //等待PLL锁定
         RCC->CFGR|=0x02;                        //PLL作为系统时钟
         while(temp!=0x02)                       //等待PLL作为系统时钟设置成功
         {
             temp = RCC->CFGR>>2;
                 temp&=0x03;
         }     
}

我们只需要在 main函数开始调用该函数,传入参数9,即可设置系统时钟为72MHz。

STM32_Clock_Init(9);                           //系统时钟初始化
3.2.2 RCC_Init
/*****************************************************************************************************
*
*           Description:复位外设,并关断所有中断,同时配置中断向量表
*                                        APB1RST:APB1外设复位寄存器 0:无效      1:复位外设
                        APB1RST:APB2外设复位寄存器 0:无效      1:复位外设
                                        AHBENR :AHB 外设时钟使能寄存器
                                        CR      :时钟控制寄存器
                                        CFGR    :时钟配置寄存器
                                        ICR     :中断标志寄存器
*
****************************************************************************************************/
void RCC_Init(void)
{
       RCC->APB1RSTR = 0x00;         //APB1外设初始化复位结束
           RCC->APB2RSTR = 0x00;         //APB2外设初始化复位结束
           RCC->AHBENR   = 0x14;         //睡眠模式时闪存接口电路时钟开启,睡眠模式时SRAM时钟开启,DMA时钟关闭
           RCC->APB2ENR = 0x00;          //APB2总线上外设时钟关闭
           RCC->APB1ENR = 0x00;          //APB1总线上外设时钟关闭
           RCC->CFGR    &= 0xF8000000;   //复位SW[3:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0],PLLSRC,PLLXTPRE,PLLMUL[3:0],USBPRE  
           RCC->CR      &= 0xFEF2FFFF;   //复位HSEON,CSSON,PLLON,HSEBYP   
           RCC->CIR      = 0x00000000;   //关闭所有中断
          
           /********** 配置中断向量表 ***********************/
           #ifdef VECT_TAB_RAM
              NVIC_SetVectorTable(0x20000000,0x00);
           #else
              NVIC_SetVectorTable(0x08000000,0x00);
           #endif
}

3.2.3 NVIC_SetVectorTable
/*****************************************************************************************************
*
*           Description:设置向量表偏移地址
                    NVIC_VectorTable:基址
                                        Offset:       偏移量
****************************************************************************************************/
void NVIC_SetVectorTable(u32 NVIC_VectorTable,u32 Offset)
{
   SCB->VTOR = NVIC_VectorTable|(Offset&(u32)0x1FFFFF80);   //设置NVIC的向量表偏移寄存器,用于标识向量表是在CODE区,还是在RAM区
}
四、源码下载
源码下载路径:stm32f103

参考文章

[1] STM32F103时钟系统讲解

[2] Mini2440裸机开发之系统时钟配置
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Graceful_scenery/article/details/143899463

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1935

主题

15659

帖子

12

粉丝