STM32时钟初始化函数SystemInit()详解

发布者:Tianyun2021最新更新时间:2016-09-28 来源: eefocus关键字:STM32  时钟初始化  函数SystemInit() 手机看文章 扫描二维码
随时随地手机看文章
花了一天的时间,总算是了解了SystemInit()函数实现了哪些功能,初学STM32,,现记录如下(有理解错误的地方还请大侠指出):
使用的是3.5的库,用的是STM32F107VC,开发环境RVMDK4.23
我已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz
函数调用顺序:
startup_stm32f10x_cl.s(启动文件) → SystemInit() →  SetSysClock () → SetSysClockTo72()
初始化时钟用到的RCC寄存器复位值:
RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;
SystemInit()
在调用 SetSysClock()之前RCC寄存器的值如下(都是一些与运算,或运算,在此就不赘述了):
RCC->CR = 0x0000 0083;  RCC->CIR = 0x00FF0000; RCC->CFGR2 = 0x00000000;至于这些寄存器都代表着什么意思,详见芯片资料RCC寄存器,该文重点不在此处;
SetSysClock()函数如下:
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz //我的定义的是SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72()
  SetSysClockTo72();
#endif
}
SetSysClockTo72()函数如下:
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
 
  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  
  if (HSEStatus == (uint32_t)0x01)
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;
 
    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
     /* Enable PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* Wait till PLL2 is ready */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
      /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else    
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */
 
    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;
 
    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    
 
    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
  }
}
 
 
1:AHB, APB1,APB2时钟确定
//HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ(至于72MHZ如何得来,请看下面分析)
   //那么就是HCLK(AHB总线时钟)=PLLCLK = 72MHZ    
    //AHB总线时钟等于系统时钟SYSCLK,也就是 AHB时钟 = HCLK = SYSCLK = 72MHZ
   /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
 
   //PLCK2等于HCLK一分频, 所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2总线时钟) = 72MHZ   
   //APB2总线时钟等于HCLK的一分频,也就是不分频;APB2 时钟 = HCLK = SYSCLK = 72MHZ 
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
 
    //PCLK1 = HCLK / 2;PCLK1 等于HCLK时钟的二分频,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ    
    //APB1总线时钟等于HCLK的二分频,也就是 APB1时钟= HCLK / 2 = 36MHZ
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
 
2:如何得出SYSCLK(系统时钟)为72MHZ(外部晶振25MHZ)
//记得参考英文芯片资料的时钟树P115页和RCC时钟寄存器进行理解
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
 
RCC_CFGR2_PREDIV2_DIV5:  PREDIV2 = 5; 5分频
          也就是PREDIV2对输入的外部时钟 5分频,那么PLL2和PLL3没有倍频前是25 /5 = 5MHZ
RCC_CFGR2_PLL2MUL8  : PLL2MUL = 8; 8倍频  
          8倍频后,PLL2时钟 = 5 * 8 = 40MHZ; 因此 PLL2CLK = 40MHZ
RCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1, 选择PLL2CLK 作为PREDIV1的时钟源
RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入时钟5分频 PREDIV1CLK = PLL2CLK / 5 = 8MHZ
 
STM32时钟初始化函数SystemInit()详解 - lucjn - 我的博客STM32时钟初始化函数SystemInit()详解 - lucjn - 我的博客以上是对RCC_CFGR2进行的配置
--------------------------------------------------------------------------------------
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
 RCC_CFGR_PLLMULL9); 
 
RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作这一位和操作RCC_CFGR2寄存器的 位[3:0]中的最低位是相同的效果  
RCC_CFGR_PLLSRC_PREDIV1 :选择PREDIV1输出作为PLL输入时钟;PREDIV1CLK = 8MHZ,所以输入给PLL倍频的 时钟源是8MHZ
RCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频系数为9,也就是对 PLLCLK = PREDIV1CLK * 8 = 72MHZ
 
以上是对RCC_CFGR进行的配置
---------------------------------------------------------------------------------------------------
 
 RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   //选择PLLCLK作为系统时钟源 
 
--------------------------------------------------------------------------------------------------
至此基本配置已经完成,配置的时钟如下所述:
SYSCLK(系统时钟) = 72MHZ
AHB总线时钟   = 72MHZ
APB1总线时钟  = 36MHZ
APB2总线时钟  = 72MHZ
PLL时钟   = 72MHZ
PLL2时钟  = 40MHZ

关键字:STM32  时钟初始化  函数SystemInit() 引用地址:STM32时钟初始化函数SystemInit()详解

上一篇:LPC2136用Jlink下载程序注意事项
下一篇:STM32的GPIO设置

推荐阅读最新更新时间:2024-03-16 15:12

USE_STDPERIPH_DRIVER, STM32F10X_HD说明
如果在STM32工程编译时没有添加USE_STDPERIPH_DRIVER, STM32F10X_HD时会出现如下错误: ..\library\cortex_m3\stm32f10x.h(96): error: #35: #error directive: Please select first the target STM32F10x device used in your application (in stm32f10x.h file) 这时候我们需要在 Target Options 中的 C/C++ 选项卡中添加USE_STDPERIPH_DRIVER、STM32F10X_HD。这样才能使编顺利通过。 那么这个错
[单片机]
USE_STDPERIPH_DRIVER, STM32F10X_HD说明
STM32的GPIO输入编程实例之读取按键状态
一、概述 1、按键简介 按键是一种机械器件,按键两端分别对应某电路的两个断点,我们可以通过按键接通和断开控制该电路的电压等参数,我们利用按键做的应用通常有控制继电器、键盘、复位等。随着应用的扩展,按键已成为电路板上不可或缺的一部分。 2、按键类别简介 按键主要有四种类型:常开带复位、常开不带复位、常闭带复位、常闭不带复位。(本次实验使用的是常开带复位按键) 按键主要有以下4种工作模式: 常开带复位:初始默认状态是开路,当受力按下时按键使电路连通,受力结束后其自动返回开路状态。 常开带不复位:初始默认状态是开路,每按下一次按键改变一次开闭状态。 常闭带复位:初始默认状态是连通,当受力按下时按键使电路开路,受力结束后其自动返回
[单片机]
stm32 DMA 的 buffersize 意义与设置
总结一下: 我的理解是一次传输多个数据,不管你的数据是8位,16位还是32位,也就相当于你接收数据部分缓存的数据量。buf ,就是这个bufe_size。 1.看库函数中 DMAy_Channelx- CNDTR = DMA_InitStruct- DMA_BufferSize; 而CNDTR即数据传输数量 (Number of data to transfer) 数据传输数量为0至65535。这个寄存器只能在通道不工作(DMA_CCRx的EN=0)时写入。通 道开启后该寄存器变为只读,指示剩余的待传输字节数目。寄存器内容在每次DMA传输后递 减。 数据传输结束后,寄存器的内容或者变为0;或者当该通道配置为自
[单片机]
STM32硬件复位时间
两个参数,,1低电平时间 2低电平压值 1.stm32复位时间 ------ 低电平时间:1.5 至 4.5 ms 2.压值
[单片机]
<font color='red'>STM32</font>硬件复位时间
嵌入式stm32学习:USART串口通信
bsp_debug_usart.h #ifndef __DEBUG_USART_H #define __DEBUG_USART_H #include stm32f4xx.h #include stdio.h //引脚定义 /*******************************************************/ #define DEBUG_USART USART1 #define DEBUG_USART_CLK RCC_APB2Periph_USART1 #define DEBUG_USART_BAUDRATE 1152
[单片机]
STM32内部flash分配
在Keil中编译工程成功后,在下面的Bulid Ouput窗口中会输出下面这样一段信息: Program Size: Code=6320 RO-data=4864 RW-data=44 ZI-data=1636 代表的意思: Code :是程序中代码所占字节大小 RO-data :程序中所定义的指令和常量大小 (个人理解 :Read Only) RW-data :程序中已初始化的变量大小 (个人理解”:Read/Write) ZI-Data :程序中未初始化的变量大小 (个人理解 :Zero Initialize) ROM(Flash) size = Code+RO-data+RW-data; RAM size = RW-data
[单片机]
基于STM32的危险品运输系统
一.系统设计 本次设计的是基于STM32F103C8T6单片机设计的一款 危险品运输,系统内有DHT11采集车内温湿度,气压传感器采集气压,adxl345计数模块采集震动次数 , lcd1602显示温湿度,气压值,震动次数 ,同时还有ESP8266将数据传输到one,在one端可以显示,温湿度,气压值,震动次数。 图1 系统框图 二.硬件设计 系统内的主要电路有单片机最小系统电路,气压检测电路、温湿度检测电路、震动检测电路、显示电路、无线通信电路、电源电路等。 图2 硬件电路 三.软件设计 系统的软件逻辑清晰,首先先进行一次系统初始化,此时就开始进行温湿度检测和压力检测以及震动计数,将数据现在显示屏上进行显示,再将数据上传
[单片机]
基于<font color='red'>STM32</font>的危险品运输系统
STM32按键控制LED的亮灭
使用一个按键控制 LED 的亮灭,按键按下时LED亮起,按键松开时LED熄灭。通过按键控制实验来介绍下 IO 口作为输入的使用。本例中用到了GPIOE的PE3管脚。 LED和按键的电路图。 按键 K_LEFT、K_DOWN、K_RIGHT 分别连接在 STM32 F1 芯片 的 PE2、PE3、PE4引脚上。 按键另一端是全部接在 GND 上,这个和我们学习 51单片机 是一样的,采用独立式按键接法,按下时输入到芯片管脚即为低电平。 整个程序实现的流程步骤如下: 初始化按键使用的 端口 及 时钟 按键 检测 处理 按键控制处理 工程文件目录如下。 IO口初始化程序代码在key.c文件中。 /**********
[单片机]
<font color='red'>STM32</font>按键控制LED的亮灭
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved