嵌入式STM32中时钟系统详细分析

简介: 嵌入式STM32中时钟系统详细分析

00900fdea44d404487e02c1bbcdf5062.png


1. STM32的时钟源主要有:


  • 内部时钟
  • 外部时钟
  • 锁相环倍频输出时钟

0435c998079c134fc9fb41da7af25109.png

1.1 详细介绍

HSI(内部高速时钟)

  • 它是RC振荡器,频率可以达到8MHZ,可作为系统时钟和PLL锁相环的输入。

HSE(外部高速时钟)

  • 接入晶振范围是4-16MHZ,可作为系统时钟和PLL锁相环的输入,还可以经过128分频之后输入给RTC。

LSI(内部低速时钟)

  • 它是RC振荡器,频率大概为40KHZ,供给独立看门狗或者RTC,并且独立看门口只能依靠LSI作为时钟源。

LSE(外部低速时钟)

  • 通常外接32.768MHZ晶振提供给RTC。

PLL(锁相环)

  • 用来倍频输出。因为开发板外部晶振只有8MHZ,而STM32最大工作频率是72MHZ。他可以通过HSI输入,HSE输入或两分频输入,通过PLL倍频(2-16),倍频之后输入给系统时钟。

MCO(时钟输出管脚)

  • 通常对应STM32 PA8,它可以选择一个时钟信号输出,给外部的系统提供时钟源。


2. 标准库的时钟配置


2.1 stm32启动文件

首先打开startup_stm32f10x_hd.s,该文件为stm32的启动文件,在该文件内会发现有这么一块用汇编写的代码。

      Reset_Handler   PROC
            EXPORT  Reset_Handler    [WEAK]
            IMPORT  __main
            IMPORT  SystemInit
            LDR     R0, =SystemInit
            BLX     R0               
            LDR     R0, =__main
            BX      R0
            ENDP


通过这段汇编代码可以看出,程序在执行main函数之前,会先执行SystemInit函数。

2.2 SystemInit函数详解

void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;
  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;
  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;
  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;
  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 
  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}


打开内部8M时钟

RCC->CR |= (uint32_t)0x00000001


通过查看寄存器手册可知,这段代码为打开内部8M时钟。

3f865e4b4720d5c8da6d7de44bef26e5.png

设置时钟配置寄存器

#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   


对应寄存器说明可查看《STM32中文参考手册_V10》的6.3.2 时钟配置寄存器(RCC_CFGR)章节。

后续代码,有兴趣可根据《STM32中文参考手册_V10》手册,查看代码具体作用。

2.3 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
  SetSysClockTo72();
#endif
}


system_stm32f10x.c文件中会根据芯片的型号定义对应的宏

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
 #define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */ 
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif


3. 时钟配置函数


3.1 时钟初始化配置函数

void SystemInit(void);
SYSCLK(系统时钟)=72MHZ;
AHB总线时钟(HCLK=SYSCLK)=72MHZ;
APB1总线时钟(PCLK1=SYSCLK/2)=36MHZ;
APB2总线时钟(PCLK1=SYSCLK/1)=72MHZ;
PLL主时钟=72MHZ;


3.2 外设时钟使能配置函数

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);


3.3 时钟源使能函数

void RCC_HSICmd(FunctionalState NewState);
void RCC_LSICmd(FunctionalState NewState);
void RCC_PLLCmd(FunctionalState NewState);
void RCC_RTCCLKCmd(FunctionalState NewState);


3.4 时钟源和倍频因子配置函数

void RCC_HSEConfig(uint32_t RCC_HSE);
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
void RCC_PCLK1Config(uint32_t RCC_HCLK);
void RCC_PCLK2Config(uint32_t RCC_HCLK);


3.5 外设时钟复位函数

void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);


3.6 自定义系统时钟

void RCC_HSE_Config(u32 div,u32 pllm)
{
    RCC_DeInit();
    RCC_HSEConfig(RCC_HSE_ON);
    if(RCC_WaitForHSEStartUp()==SUCCESS)
    {   
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        RCC_PCLK1Config(RCC_HCLK_Div2);
        RCC_PCLK2Config(RCC_HCLK_Div1);
        RCC_PLLConfig(div,pllm);
        RCC_PLLCmd(ENABLE);     
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)
    while(RCC_GetSCLKSource()!=0x08);
    }
}​


目录
相关文章
|
2月前
|
传感器 监控 物联网
基于STM32+微波雷达设计的非接触式睡眠监控系统
本项目开发一种非接触式的睡眠监控系统,该系统利用先进的60GHz毫米波雷达技术和STM32微控制器,实现了对人体在睡眠过程中的存在感知、运动感知以及生理指标如呼吸频率、心率的实时监测。系统能够自动评估睡眠质量,并在用户睡眠周期结束时提供睡眠评分。为了确保用户能够在任何地点了解自己的睡眠状况,系统集成了Wi-Fi模块,可以将收集到的数据上传至华为云物联网平台,并通过专门设计的移动应用程序供用户远程访问。此外,系统还具备超阈值报警功能,当检测到异常的生理指标时会发出警报提醒。本地1.44寸TFT LCD显示屏用于实时显示监测到的信息,包括生理指标和环境数据。为了全面监测用户的健康状况,系统还加入了
306 0
基于STM32+微波雷达设计的非接触式睡眠监控系统
|
2月前
|
存储 机器学习/深度学习 编解码
基于STM32的车牌识别系统
基于STM32的车牌识别系统
119 0
|
2月前
|
传感器 网络协议 物联网
基于STM32的环境监测系统 (esp8267)(下)
基于STM32的环境监测系统 (esp8267)(下)
123 0
|
2月前
|
传感器 测试技术 芯片
基于STM32的环境监测系统 (esp8266)(上)
基于STM32的环境监测系统 (esp8266)(上)
408 0
|
3月前
|
存储 传感器 Linux
STM32微控制器为何不适合运行Linux系统的分析
总的来说,虽然技术上可能存在某些特殊情况下将Linux移植到高端STM32微控制器上的可能性,但从资源、性能、成本和应用场景等多个方面考虑,STM32微控制器不适合运行Linux系统。对于需要运行Linux的应用,更适合选择ARM Cortex-A系列处理器的开发平台。
285 0
|
5月前
|
前端开发 安全
stm32f407探索者开发板(十一)——SystemInit时钟系统初始化剖析
stm32f407探索者开发板(十一)——SystemInit时钟系统初始化剖析
207 0
|
6月前
使用STM32F103标准库实现定时器控制LED点亮和关闭
通过这篇博客,我们学习了如何使用STM32F103标准库,通过定时器来控制LED的点亮和关闭。我们配置了定时器中断,并在中断处理函数中实现了LED状态的切换。这是一个基础且实用的例子,适合初学者了解STM32定时器和中断的使用。 希望这篇博客对你有所帮助。如果有任何问题或建议,欢迎在评论区留言。
473 2
|
5月前
stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
788 0
|
6月前
|
IDE 开发工具
使用STM32F103标准库实现自定义键盘
通过本文,我们学习了如何使用STM32F103标准库实现一个简单的自定义键盘。我们首先初始化了GPIO引脚,然后实现了一个扫描函数来检测按键状态。这个项目不仅能够帮助我们理解STM32的GPIO配置和按键扫描原理,还可以作为进一步学习中断处理和低功耗设计的基础。希望本文对你有所帮助,祝你在嵌入式开发的道路上不断进步!
537 4