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

【经验分享】STM32- 时钟树、时钟配置

[复制链接]
STMCU小助手 发布时间:2022-1-28 20:57
reset clock control 复位和时钟控制器
一、stm32时钟树

1251897-20190520122927631-2146778766.png

stm32时钟树:由时钟源到外设的结构框图。
基本时钟源(图中绿色箭头指出):
(1)HSI高速内部时钟,RC振荡器,8MHz。
(2)HSE高速外部时钟,石英/陶瓷谐振器,8MHz。
(3)LSI低速内部时钟,RC振荡器,40kHz。
(4)LSE低速外部时钟,RTC石英晶振,32.768kHz。
注:内部指的是片上外设,外部指的是芯片外部。
(5)除了上述基本时钟源,还有num3中的PLL锁相环倍频时钟源,它是将HSI和HSE倍频后输出。
二、PLLCLK  -  PLL时钟(num4)
时钟来源:(1)HSI/2        (2)HSE
三、SYSCLK  -  系统时钟(num5)
时钟来源:(1)HSI          (2)PLLCLK      (3)HSE
SYSCLK经过分频后,得到AHB总线时钟HCLK;
HCLK再分频得到APB1总线时钟PCLK1和APB2总线时钟PCLK2;
PCLK2分频后得到ADCCLK最大14MHz。
四、RTCCLK(灰色框中)
时钟来源:(1)HSE/128   (2)LSE             (3)LSI
五、系统时钟配置
系统时钟有三个来源,PLLCLK、HSE、HSI。
正常情况下,时钟配置是在system_stm32f10x.c中完成,这里的的时钟配置是直接控制寄存器完成的。
在 stm32f10x_rcc.c中定义了关于时钟配置的库函数,此时未用。
打开system_stm32f10x.c,找到void SystemInit (void),再找到 SetSysClock()并查看定义,
定义中可知是通过在system_stm32f10x.c中宏定义SYSCLK_FREQ_72MHz选择系统时钟配置函数SetSysClockTo72(),
即72MHz的系统时钟就是在此函数中配置的,函数如下:(HSE(不分频)->PLLCLK(9倍频)->72MHz系统时钟)
  1. static void SetSysClockTo72(void)
  2. {
  3.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  4.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
  5.   /* 使能 HSE */
  6.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);

  7.   /* 等待HSE就绪并做超时处理 */
  8.   do
  9.   {
  10.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
  11.     StartUpCounter++;
  12.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  13.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  14.   {
  15.     HSEStatus = (uint32_t)0x01;
  16.   }
  17.   else
  18.   {
  19.     HSEStatus = (uint32_t)0x00;
  20.   }

  21.   // 如果HSE启动成功,程序则继续往下执行
  22.   if (HSEStatus == (uint32_t)0x01)
  23.   {
  24.     /* 使能预取指 */
  25.     FLASH->ACR |= FLASH_ACR_PRFTBE;

  26.     /* Flash 2 wait state */
  27.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
  28.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;


  29.     /* HCLK = SYSCLK = 72M */
  30.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

  31.     /* PCLK2 = HCLK = 72M */
  32.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

  33.     /* PCLK1 = HCLK = 36M*/
  34.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

  35.     /*  锁相环配置: PLLCLK = HSE * 9 = 72 MHz */
  36.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
  37.                                         RCC_CFGR_PLLMULL));
  38.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

  39.     /* 使能 PLL */
  40.     RCC->CR |= RCC_CR_PLLON;

  41.     /* 等待PLL稳定 */
  42.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
  43.     {
  44.     }
  45.     /* 选择PLLCLK作为系统时钟*/
  46.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  47.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

  48.     /* 等待PLLCLK切换为系统时钟 */
  49.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
  50.     {
  51.     }
  52.   }
  53.   else
  54.   { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
  55.   }
  56. }
复制代码

这里再以库函数形式中重新配置系统时钟和MCO:
user中新建RCC文件夹,新建bsp_rccclkconfig.c和bsp_rccclkconfig.h文件,同时对main函数做补充。(GPIO&KEY例程继续写的)
bsp_rccclkconfig.h
  1. #ifndef __BSP_RCCCLKCONFIG_H
  2. #define __BSP_RCCCLKCONFIG_H

  3. #include "stm32f10x.h"

  4. void HSE_SetSysClk( uint32_t RCC_PLLMul_x );
  5. void MCO_GPIO_Config();
  6. void HSI_SetSysClk( uint32_t RCC_PLLMul_x );
  7. #endif /*__BSP_RCCCLKCONFIG_H */
复制代码
bsp_rccclkconfig.c
  1. #include "bsp_rccclkconfig.h"

  2. void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
  3. {
  4.     ErrorStatus HSEStatus;

  5.     //把RCC寄存器复位成复位值
  6.     RCC_DeInit();

  7.     // 使能 HSE
  8.     RCC_HSEConfig(RCC_HSE_ON);

  9.     HSEStatus = RCC_WaitForHSEStartUp();

  10.     if( HSEStatus == SUCCESS )
  11.     {
  12.         // 使能预取址
  13.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
  14.         FLASH_SetLatency(FLASH_Latency_2);

  15.         RCC_HCLKConfig(RCC_SYSCLK_Div1);
  16.         RCC_PCLK1Config(RCC_HCLK_Div2);
  17.         RCC_PCLK2Config(RCC_HCLK_Div1);

  18.         // 配置 PLLCLK = HSE * RCC_PLLMul_x
  19.     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);

  20.     // 使能PLL
  21.         RCC_PLLCmd(ENABLE);

  22.         // 等待PLL稳定
  23.         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );

  24.     // 选择系统时钟
  25.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

  26.     while( RCC_GetSYSCLKSource() != 0x08 );
  27.     }
  28.     else
  29.   {
  30.         /* 如果HSE启动失败,用户可以在这里添加错误的处理代码 */
  31.     }
  32. }

  33. void HSI_SetSysClk( uint32_t RCC_PLLMul_x )
  34. {
  35.     __IO uint32_t HSIStatus = 0;

  36.     // 把RCC寄存器复位成复位值
  37.     RCC_DeInit();

  38.     // 使能 HSI
  39.     RCC_HSICmd(ENABLE);

  40.     HSIStatus = RCC->CR & RCC_CR_HSIRDY;

  41.     if( HSIStatus == RCC_CR_HSIRDY )
  42.     {
  43.         // 使能预取址
  44.         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
  45.         FLASH_SetLatency(FLASH_Latency_2);

  46.         RCC_HCLKConfig(RCC_SYSCLK_Div1);
  47.         RCC_PCLK1Config(RCC_HCLK_Div2);
  48.         RCC_PCLK2Config(RCC_HCLK_Div1);

  49.         // 配置 PLLCLK = HSI * RCC_PLLMul_x
  50.     RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);

  51.     // 使能PLL
  52.         RCC_PLLCmd(ENABLE);

  53.         // 等待PLL稳定
  54.         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );

  55.     // 选择系统时钟
  56.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

  57.     while( RCC_GetSYSCLKSource() != 0x08 );
  58.     }
  59.     else
  60.   {
  61.         /* 如果HSI启动失败,用户可以在这里添加处理错误的代码 */
  62.     }
  63. }

  64. void MCO_GPIO_Config()//MCO时钟输出GPIO配置,PA8
  65. {
  66.     GPIO_InitTypeDef  GPIO_InitStruct;

  67.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  68.     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
  69.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  70.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  71.     GPIO_Init(GPIOA, &GPIO_InitStruct);
  72. }
复制代码

main.c
  1. 1 #include "stm32f10x.h"   //
  2. 2 #include "bsp_key.h"
  3. 3 #include "bsp_led.h"
  4. 4 #include "bsp_rccclkconfig.h"
  5. 5 void Delay( uint32_t count )   //软件延时函数,但是实际时间间隔取决于系统时钟
  6. 6 {
  7. 7     for(; count!=0; count--);
  8. 8 }
  9. 9
  10. 10 int main(void)
  11. 11 {
  12. 12     // 来到这里的时候,系统时钟已经被配置成72M
  13. 13     LED_GPIO_Config();
  14. 14     KEY_GPIO_Config();
  15. 15     //这里重新配置时钟,如果注释掉下面两条HSE和HSI语句,将使用默认的system_stm32f10x.c寄存器配置版72M16                                    //HSE=8MHZ,PLL九倍频=72MHZ
  16. 17     HSE_SetSysClk( RCC_PLLMul_9 );
  17. 18                                    //HSI/2=4MHZ,PLL十六倍频=64MHZ
  18. 19     //HSI_SetSysClk( RCC_PLLMul_16 );
  19. 20     
  20. 21     //MCO的GPIO初始化
  21. 22     MCO_GPIO_Config();
  22. 23     //选择系统时钟作为MCO输出
  23. 24     RCC_MCOConfig(RCC_MCO_SYSCLK);  //PA8接示波器可见
  24. 25     //RCC_MCOConfig(RCC_MCO_HSI);
  25. 26     
  26. 27     while(1)//更改系统时钟频率,小灯的闪烁间隔出现变化
  27. 28     {
  28. 29         //
  29. 30         //if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) ==KEY_ON )
  30. 31         //    LED_G_TOGGLE;
  31. 32         
  32. 33         LED_G(OFF);
  33. 34         Delay(0xFFFFF);
  34. 35         
  35. 36         LED_G(ON);
  36. 37         Delay(0xFFFFF);
  37. 38     }
  38. 39 }
复制代码

收藏 评论0 发布时间:2022-1-28 20:57

举报

0个回答

所属标签

相似分享

官网相关资源

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