你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 时钟配置与使用

[复制链接]
STMCU小助手 发布时间:2022-1-25 17:00
0、前言
RCC-复位和时钟控制器
可以实现配置系统时钟SYSCLK,配置AHB(HCLK)总线时钟,配置外设APB1(PCLK1)和APB2(PCLK2)时钟
库函数的标准配置为PCLK2=HCLK=SYSCLK=PLLCLK=72M,PCLK1=HCLK/2=36M
系统初始化时会调用函数实现时钟配置。
  1. #ifdef SYSCLK_FREQ_HSE
  2.   uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;     /*!< System Clock Frequency (Core Clock) */
  3. #elif defined SYSCLK_FREQ_24MHz
  4.   uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;   /*!< System Clock Frequency (Core Clock) */
  5. #elif defined SYSCLK_FREQ_36MHz
  6.   uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;   /*!< System Clock Frequency (Core Clock) */
  7. #elif defined SYSCLK_FREQ_48MHz
  8.   uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;   /*!< System Clock Frequency (Core Clock) */
  9. #elif defined SYSCLK_FREQ_56MHz
  10.   uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;   /*!< System Clock Frequency (Core Clock) */
  11. #elif defined SYSCLK_FREQ_72MHz
  12.   uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;   /*!< System Clock Frequency (Core Clock) */
复制代码
  1. static void SetSysClock(void)
  2. {
  3. #ifdef SYSCLK_FREQ_HSE
  4.   SetSysClockToHSE();
  5. #elif defined SYSCLK_FREQ_24MHz
  6.   SetSysClockTo24();
  7. #elif defined SYSCLK_FREQ_36MHz
  8.   SetSysClockTo36();
  9. #elif defined SYSCLK_FREQ_48MHz
  10.   SetSysClockTo48();
  11. #elif defined SYSCLK_FREQ_56MHz
  12.   SetSysClockTo56();  
  13. #elif defined SYSCLK_FREQ_72MHz
  14.   SetSysClockTo72();
  15. #endif
复制代码

在system_stm32f10x.c文件中可更改宏定义改变系统时钟频率
  1. #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  2. /* #define SYSCLK_FREQ_HSE    HSE_VALUE */
  3. #define SYSCLK_FREQ_24MHz  24000000
  4. #else
  5. /* #define SYSCLK_FREQ_HSE    HSE_VALUE */
  6. /* #define SYSCLK_FREQ_24MHz  24000000 */
  7. /* #define SYSCLK_FREQ_36MHz  36000000 */
  8. /* #define SYSCLK_FREQ_48MHz  48000000 */
  9. /* #define SYSCLK_FREQ_56MHz  56000000 */
  10. #define SYSCLK_FREQ_72MHz  72000000
  11. #endif
复制代码


1、时钟树

2604878-20220111094549623-739236124.png
主要时钟
  • HSE:高速外部时钟,可由有源晶振或无源晶振提供,4-16MHz
    PLL以HSE为来源时可设置不分频或2分频
  • PLL:锁相环时钟源,可配置来自HSE或HSI/2
  • PLLCLK:锁相环时钟,可设置倍频[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
  • SYSCLK:系统时钟
  • HCLK:AHB总线时钟,系统时钟经AHB预分频得到,分频因子[1,2,4,8,16,64,128,256,512]
  • PCLK1:APB1总线时钟,由HCLK通过低速APB1预分频得到,分频因子[1,2,4,8,16]
  • PCLK2:APB2总线时钟,由HCLK通过高速APB2预分频得到,分频因子[1,2,4,8,16]

其他时钟
  • USB时钟:由PLLCLK通过USB预分频器得到,分频因子[1,1.5]
  • Cortex系统时钟:由HCLK8分频得到,用来驱动内核的系统定时器SysTick
  • ADC时钟:由PCLK2经ADC预分频得到,分频因子[2,4,6,8]
  • RTC时钟:由HSE/128或LSE或LSI得到
  • MCO时钟:输出时钟,可由PLLCLK/2,HSI,HSE,SYSCLK配置

2、时钟配置

相关库函数
配置函数
  1. /*
  2.         将RCC外设初始化为复位状态
  3. */
  4. void RCC_DeInit(void);               
  5. /*
  6.         使能HSE,可选参数RCC_HSE_OFF,RCC_HSE_ON,RCC_HSE_Bypass
  7. */
  8. void RCC_HSEConfig(uint32_t RCC_HSE);        
  9. /*
  10.         等待时钟源启动稳定,返回SUCCESS,ERROR
  11. */
  12. ErrorStatus RCC_WaitForHSEStartUp(void);
  13. /*
  14.         配置PLL时钟源和PLL倍频因子
  15.         RCC_RLLSource:RCC_PLLSource_HSE_Div1,RCC_PLLSource_HSE_Div2,RCC_PLLSource_HSI_Div2
  16.         RCC_PLLMul:RCC_PLLMul_2 [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
  17. */
  18. void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul);
  19. /*
  20.         配置系统时钟,可选参数RCC_SYSCLKSource_HSI,RCC_SYSCLKSource_HSE,RCC_SYSCLKSource_PLLCLK
  21. */
  22. void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
  23. /*
  24.         配置HCLK,可选参数RCC_SYSCLK_Div1 [1,2,4,8,16,64,128,256,512]
  25. */
  26. void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
  27. /*
  28.         配置PCLK1,可选参数RCC_HCLK_Div1 [1,2,4,8,16]
  29. */
  30. void RCC_PCLK1Config(uint32_t RCC_HCLK);
  31. /*
  32.         配置PCLK2,可选参数RCC_HCLK_Div1 [1,2,4,8,16]
  33. */
  34. void RCC_PCLK2Config(uint32_t RCC_HCLK);
复制代码


使用HSE配置系统时钟
  • 1、开启HSE ,并等待 HSE 稳定
  • 2、设置 AHB、APB2、APB1的预分频因子
  • 3、设置PLL的时钟来源,和PLL的倍频因子,设置各种频率主要就是在这里设置
  • 4、开启PLL,并等待PLL稳定
  • 5、把PLLCK切换为系统时钟SYSCLK
  • 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟

使用HSI配置系统时钟
  • 1、开启HSI ,并等待 HSI 稳定
  • 2、设置 AHB、APB2、APB1的预分频因子
  • 3、设置PLL的时钟来源,和PLL的倍频因子,设置各种频率主要就是在这里设置
  • 4、开启PLL,并等待PLL稳定
  • 5、把PLLCK切换为系统时钟SYSCLK
  • 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟
  1. /* 设置 系统时钟:SYSCLK, AHB总线时钟:HCLK, APB2总线时钟:PCLK2, APB1总线时钟:PCLK1
  2. * PCLK2 = HCLK = SYSCLK
  3. * PCLK1 = HCLK/2,最高只能是36M
  4. * 参数说明:pllmul是PLL的倍频因子,在调用的时候可以是:RCC_PLLMul_x , x:[2,3,...16]
  5. * 举例:HSI_SetSysClock(RCC_PLLMul_9);  则设置系统时钟为:4MHZ * 9 = 72MHZ
  6. *       HSI_SetSysClock(RCC_PLLMul_16); 则设置系统时钟为:4MHZ * 16 = 64MHZ
  7. *
  8. * HSI作为时钟来源,经过PLL倍频作为系统时钟,这是在HSE故障的时候才使用的方法
  9. * HSI会因为温度等原因会有漂移,不稳定,一般不会用HSI作为时钟来源,除非是迫不得已的情况
  10. * 如果HSI要作为PLL时钟的来源的话,必须二分频之后才可以,即HSI/2,而PLL倍频因子最大只能是16
  11. * 所以当使用HSI的时候,SYSCLK最大只能是4M*16=64M
  12. */
  13. void HSI_SetSysClock(uint32_t pllmul)
  14. {
  15.     __IO uint32_t HSIStartUpStatus = 0;
  16.     // 把RCC外设初始化成复位状态,这句是必须的
  17.     RCC_DeInit();

  18.     //使能HSI
  19.     RCC_HSICmd(ENABLE);
  20.     // 等待 HSI 就绪
  21.     HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;
  22.     // 只有 HSI就绪之后则继续往下执行
  23.     if (HSIStartUpStatus == RCC_CR_HSIRDY)
  24.     {
  25. //----------------------------------------------------------------------//
  26.         // 使能FLASH 预存取缓冲区
  27.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
  28.         // SYSCLK周期与闪存访问时间的比例设置,这里统一设置成2
  29.         // 设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,
  30.         // 如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了
  31.         // 0:0 < SYSCLK <= 24M
  32.         // 1:24< SYSCLK <= 48M
  33.         // 2:48< SYSCLK <= 72M
  34.         FLASH_SetLatency(FLASH_Latency_2);
  35. //----------------------------------------------------------------------//
  36.         // AHB预分频因子设置为1分频,HCLK = SYSCLK
  37.         RCC_HCLKConfig(RCC_SYSCLK_Div1);
  38.         // APB2预分频因子设置为1分频,PCLK2 = HCLK
  39.         RCC_PCLK2Config(RCC_HCLK_Div1);
  40.         // APB1预分频因子设置为1分频,PCLK1 = HCLK/2
  41.         RCC_PCLK1Config(RCC_HCLK_Div2);
  42. //-----------------设置各种频率主要就是在这里设置-------------------//
  43.         // 设置PLL时钟来源为HSE,设置PLL倍频因子
  44.         // PLLCLK = 4MHz * pllmul
  45.         RCC_PLLConfig(RCC_PLLSource_HSI_Div2, pllmul);
  46. //------------------------------------------------------------------//
  47.         // 开启PLL
  48.         RCC_PLLCmd(ENABLE);
  49.         // 等待 PLL稳定
  50.         while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  51.         {
  52.         }
  53.         // 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK
  54.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  55.         // 读取时钟切换状态位,确保PLLCLK被选为系统时钟
  56.         while (RCC_GetSYSCLKSource() != 0x08)
  57.         {
  58.         }
  59.     }
  60.     else
  61.     {
  62.         // 如果HSI开启失败,那么程序就会来到这里,用户可在这里添加出错的代码处理
  63.         // 当HSE开启失败或者故障的时候,单片机会自动把HSI设置为系统时钟,
  64.         // HSI是内部的高速时钟,8MHZ
  65.         while (1)
  66.         {
  67.         }
  68.     }
  69. }
复制代码


MCO输出
MCO GPIO初始化
  1. /*
  2. * 初始化MCO引脚PA8
  3. * 在F1系列中MCO引脚只有一个,即PA8,在F4系列中,MCO引脚会有两个
  4. */
  5. void MCO_GPIO_Config(void)
  6. {
  7.     GPIO_InitTypeDef GPIO_InitStructure;
  8.     // 开启GPIOA的时钟
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  10.     // 选择GPIO8引脚
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  12.     //设置为复用功能推挽输出
  13.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  14.     //设置IO的翻转速率为50M
  15.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16.     // 初始化GPIOA8
  17.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  18. }
复制代码

输出
  1. // MCO 引脚初始化
  2. MCO_GPIO_Config();
  3. // 设置MCO引脚输出时钟,用示波器即可在PA8测量到输出的时钟信号,
  4. // 我们可以把PLLCLK/2作为MCO引脚的时钟来检测系统时钟是否配置准确
  5. // MCO引脚输出可以是HSE,HSI,PLLCLK/2,SYSCLK
  6. //RCC_MCOConfig(RCC_MCO_HSE);
  7. //RCC_MCOConfig(RCC_MCO_HSI);
  8. //RCC_MCOConfig(RCC_MCO_PLLCLK_Div2);
  9. RCC_MCOConfig(RCC_MCO_SYSCLK);
复制代码


Systick系统定时器简介
SysTick——系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。
系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 72M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。
因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。
相关库函数
  • SysTick配置函数
    1. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
    2. {
    3.   if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
    4.                                                                
    5.   SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
    6.   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
    7.   SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
    8.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
    9.                    SysTick_CTRL_TICKINT_Msk   |
    10.                    SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
    11.   return (0);                                                  /* Function successful */
    12. }
    复制代码

    ticks用来设置重载寄存器的值,最大不超过 B3@0${X[3K]3($GOL5KF~TF.png ,当寄存器值递减到0时产生中断,随后重载、递减,循环往复。
    每一个tick对应1/SYSCLK 秒
    每次中断间隔时间为 WAU946P@$BUWH_~)IV}WJMA.png
  • ,当寄存器值递减到0时产生中断,随后重载、递减,循环往复。
  • 修改系统定时器中断优先级(非必要)
    1. NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
    复制代码

  • 对应中断函数
    1. void SysTick_Handler(void)
    2. {
    3.    
    4. }
    复制代码






收藏 评论0 发布时间:2022-1-25 17:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版