zoukankan      html  css  js  c++  java
  • RCC时钟配置实践

     

    程序运行首先会在启动文件(即startup_stm32f10x_xx.s)里调用SystemInit()函数(最终调用的是SetSysClockTo72()函数)把系统时钟初始化为72MHz。换言之,在没有修改系统时钟时,其默认为72MHz,如果需要修改,则应重新定义并调用初始化函数。

    我们通过观察不同时钟频率下LED灯闪烁的快慢来判断时钟配置情况。

    一般情况下,我们会使用HSE经过PLL倍频之后配置系统时钟。而HSE,我们经常使用8MHz的无源晶振。我们就以HSE配置系统时钟为例,按照时钟树构造流程来完成代码。下图4-1是STM32的时钟树。

    图4-1 STM32时钟树

    图中的数字顺序便是配置流程顺序,代码也是按照这个流程写的。我们简要分析下各个步骤的相关配置。


    1、如图4-2,这一步取决于第二步的PLL时钟来源PLLSRC,由时钟配置寄存器RCC_CFGR的位17:PLLXTPRE设置,“清0”为HSE不分频,“置1”为HSE 2分频。我们这里选择HSE不分频,即“清0”。代码如第二步所示,宏RCC_PLLSource_HSE_Div1即为HSE不分频作为PLL输入时钟。 图4-2

    我们需要先使能HSE,等待HSE稳定,并且在此之前我们还需要将RCC寄存器复位,代码如下。

    #define RCC_HSE_ON                       ((uint32_t)0x00010000)
    
    ErrorStatus HSEStatus;
    	
    // 把RCC寄存器复位
    RCC_DeInit();
    	
    // 使能HSE
    RCC_HSEConfig(RCC_HSE_ON);
    	
    // 返回HSE状态,等待HSE稳定 
    HSEStatus = RCC_WaitForHSEStartUp();
    

    2、这一步即为PLL时钟源配置了。由CFGR寄存器的位16:PLLSRC设置,“清0”为HSI经二分频后作为PLL输入时钟,“置1”为HSE作为PLL输入时钟,如图4-3。

    图4-3

    我们这里选择HSE作为PLL的时钟来源,即“置1”。

    #define RCC_PLLSource_HSE_Div1           ((uint32_t)0x00010000)
    #define RCC_PLLMul_9                     ((uint32_t)0x001C0000)
    
    // 配置锁相环(PLLCLK = HSE * 9 = 72MHz),必须在使能PLL前配置
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    

    这个函数在stm32f10x_rcc.c文件,用于配置PLL时钟源和倍频因子。

    3、设置PLL的倍频因子,对PLL时钟来源进行倍频,具体为多少倍频,由CFGR寄存器的位21-18:PLLMUL[3:0]配置。例如我们可以设置为9倍频,前面我们提到HSE为8MHz的无源晶振,所以倍频之后,PLL时钟PLLCLK = 8MHz * 9 = 72MHz,这是ST官方推荐的稳定时钟频率。我们也可以选择增大倍频因子进行超频,其最高为128MHz。如图4-4为倍频因子描述。代码如上步所示,配置为RCC_PLLMul_9。


    图4-4

    4、配置系统时钟SYSCLK。SYSCLK来源可以是HSI、PLLCLK、HSE,这里我们配置为SYSCLK = PLLCLK = 72MHz,由CFGR寄存器的位1-0:SW[1:0]配置。如图4-5。


    图4-5
    #define RCC_SYSCLKSource_PLLCLK          ((uint32_t)0x00000002)
    
    // 选择PLLCLK作为系统时钟
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    

    5、AHB总线时钟HCLK。HCLK由SYSCLK经过AHB预分频器分频得到,由CFGR寄存器的位7-4:HPRE[3:0]配置。如图4-1的时钟树所示,大部分的片上外设时钟都由HCLK分频得到,这里我们设置为不分频,即:HCLK = SYSCLK = 72MHz。如下图4-6。

    图4-6
    #define RCC_SYSCLK_Div1                  ((uint32_t)0x00000000)
    
    // 配置AHB总线时钟HCLK
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    

    6、APB2总线时钟PCLK2。PCLK2由高速APB2预分频器得到,由CFGR寄存器的位13-11:PPRE2[2:0]配置。APB2总线为高速总线,片上的高速外设,如GPIO、USART1、SPI1等,都挂载到APB2总线上。所以我们这里设置不分频,即:PCLK2 = HCLK = 72MHz。如下图4-7。

    图4-7
    #define RCC_HCLK_Div1                    ((uint32_t)0x00000000)
    
    // 配置APB2总线时钟PCLK2
    RCC_PCLK2Config(RCC_HCLK_Div1);
    

    7、APB1总线时钟PCLK1。PCLK1由低速APB1预分频器得到,由CFGR寄存器的位10-8:PPRE1[2:0]配置。PCLK1为低速总线时钟,最高为36MHz,片上的低速外设,如USART2/3/4/5、SPI2/3、I2C1/2等,都挂载到APB1总线上。我们设置其为2分频,即:PCLK1 = HCLK/2 = 36MHz。如下图4-8。

    图4-8
    #define RCC_HCLK_Div2                    ((uint32_t)0x00000400)
    
    // 配置APB1总线时钟PCLK1
    RCC_PCLK1Config(RCC_HCLK_Div2);
    

    经过以上的简要分析后,我们大概清楚时钟的配置流程了,现在整理整理以上的代码,将其封装为函数。

    /**
      * @brief  配置HSE作为系统时钟来源
      * @param  RCC_PLLMul_x:PLL倍频因子,
      *         x可以是:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
      * @retval 无
      */
    void HSE_SetSysClk(uint32_t RCC_PLLMul_x){
    	
    	ErrorStatus HSEStatus;
    	
    	// 把RCC寄存器复位
    	RCC_DeInit();
    	
    	// 使能HSE
    	RCC_HSEConfig(RCC_HSE_ON);
    	
    	// 返回HSE状态,等待HSE稳定 
            HSEStatus = RCC_WaitForHSEStartUp();
    	
    	if(HSEStatus == SUCCESS){
    		// 使能预取指
    		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    		// 2个等待周期
    		FLASH_SetLatency(FLASH_Latency_2);
    		
    		// 配置AHB总线时钟HCLK
    		RCC_HCLKConfig(RCC_SYSCLK_Div1);
                    // 配置APB2总线时钟PCLK2,PCLK2 = HCLK
    		RCC_PCLK2Config(RCC_HCLK_Div1);
                    // 配置APB1总线时钟PCLK1,PCLK1 = HCLK/2
    		RCC_PCLK1Config(RCC_HCLK_Div2);
    		
    		// 配置锁相环时钟(PLLCLK = HSE * 9 = 72MHz),必须在使能PLL前配置
    		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
    		
                    // 使能PLL
    		RCC_PLLCmd(ENABLE);
    		// 等待PLL稳定
    		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    		
    		// 选择PLLCLK作为系统时钟
    		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    		while(RCC_GetSYSCLKSource() != 0x08);
    	}else{
    		/* 如果HSE启动失败,则可以在这里添加处理错误的代码 */
    	}
    
    }
    

    以上就算封装好函数了,可以在main函数中调用,以重新配置系统时钟。

    int main(void){
    
    	// 倍频因子设置为9,则系统时钟配置为8MHZ * 9 = 72MHz
    	HSE_SetSysClk(RCC_PLLMul_9);
    	
            // 初始化LED灯
    	LED_GPIO_Config();
    	
    	while(1){
    		GPIO_SetBits(GPIOB, GPIO_Pin_0);    // 高电平关闭LED
    		Delay(0xFFFFF);
    		GPIO_ResetBits(GPIOB, GPIO_Pin_0);  // 低电平开启LED
    		Delay(0xFFFFF);
    	}
    	
    }
    

    我们可以通过改变倍频因子大小,来输出不同的时钟频率,如修改为RCC_PLLMul_16,则时钟频率输出为8MHZ * 16 = 128MHz。不同的时钟频率输出,灯闪烁的速度也不同,倍频因子越大,频率越高,灯闪烁越快;倍频因子越小,则实验效果反之。

    另外,图4-1时钟树中的左下角有一个MCO输出,可以对外输出时钟频率,我们可以利用示波器监控MCO引脚的输出频率来检测系统时钟是否配置正确。

  • 相关阅读:
    开源一个常用的小软件的源码——系统数据库服务管理软件
    MySql Windws 下自动备份脚本
    ubuntu-14.04-server配置Jexus --安装步骤记录
    Jumony快速抓取网页 --- Jumony使用笔记--icode
    视频教程--ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库
    收录.NET跨平台及跨数据库的博文...
    ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库
    Windbg程序调试系列
    QCY蓝牙耳机 左右两只耳机配对 方法
    wpf 的 Window或UserControl绑定自己后台属性
  • 原文地址:https://www.cnblogs.com/fire909090/p/8874827.html
Copyright © 2011-2022 走看看