[STM32F4] stm32f4晶振管理

[复制链接]
1579|17
 楼主| wang6623 发表于 2023-8-25 17:28 | 显示全部楼层 |阅读模式
       最近要使用STM32F4芯片做开发,根据自己的编程习惯,做一些学习记录,以便于自己以后查阅。我们在设计电路的时候,一般都会设计MCU使用外部晶振,笔者工作中曾经遇到外部晶振故障芯片无法正常启动问题(无内部晶振老的MCU),使用示波器发现的,在更换了外部晶振以后,问题就解决了。由此笔者想到,STM32F4系列自带内部晶振,在外部晶振故障的时候完全可以使用内部晶振,确保软件能够正常工作。因为F4外部晶振通常使用168Mhz,而内部晶振默认并不是168Mhz,参考了网上一些资料,查阅了芯片手册,设计了一个软件保护,当外部晶振故障的时候,自动使用内部晶振锁定为168Mhz。

评论

———————————————— 版权声明:本文为CSDN博主「科教兴国」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/u010422438/article/details/80937906  发表于 2023-8-25 17:28
 楼主| wang6623 发表于 2023-8-25 17:32 | 显示全部楼层
    STM32官方巡回演讲里面介绍说内部晶振现在已经能够可靠使用了,我决定实测一下,结果发现这个说法不太准确。使用系统滴答定时器中断里普通IO用100HZ方波间接测量,示波器实测使用外部晶振100HZ很稳定,使用内部晶振在100--103HZ跳动,所以最新官方演讲说内部晶振稳定性很好可以直接使用这个说法有待商酌。
 楼主| wang6623 发表于 2023-8-25 17:32 | 显示全部楼层
  具体实现思路如下,编写外部晶振软件设定函数,编写内部晶振软件设定函数,在时钟安全中断里做好时钟切换工作。代码如下
 楼主| wang6623 发表于 2023-8-25 17:33 | 显示全部楼层
  1. void NMI_Handler(void)
  2. {
  3.     if(RCC_GetITStatus(RCC_IT_CSS)!= RESET)
  4.     {
  5.         HSI_SetSysClock(); //外部晶振故障时启用内部晶振
  6.         RCC_ClearITPendingBit(RCC_IT_CSS); //清除时钟安全系统中断的挂起位
  7.     }
  8. }
  9. / *
  10. *使用HSI时,设置系统时钟的步骤
  11. * 1,开启HSI,并等待HSI稳定
  12. * 2,设置AHB,APB2,APB1的预分频因子
  13. * 3,设置PLL的时钟来源
  14. *设置VCO输入时钟分频因子m
  15. *设置VCO输出时钟倍频因子
  16. *设置SYSCLK时钟分频因子p
  17. *设置OTG FS,SDIO,RNG时钟分频因子q
  18. * 4,开启PLL,并等待PLL稳定
  19. * 5,把PLLCK切换为系统时钟SYSCLK
  20. * 6,读取时钟切换状态位,确保PLLCLK被选为系统时钟
  21. * /
  22. void HSI_SetSysClock(void)       
  23. {
  24.         __IO uint32_t HSIStartUpStatus = 0;
  25.         RCC_DeInit(); //复位RCC寄存器
  26.         RCC_HSEConfig(RCC_HSE_OFF); //关闭外部晶振(HSE)               
  27.         RCC_HSICmd(ENABLE); //使能HSI,HSI = 16M
  28.         while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)== RESET); //等待使能HSI成功
  29.         //调压器电压输出级别配置为1,以便在器件为最大频率
  30.         //工作时使性能和功耗实现平衡
  31.         RCC-> APB1ENR | = RCC_APB1ENR_PWREN;
  32.         PWR-> CR | = PWR_CR_VOS;
  33.         RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置ABH时钟HCLK =系统时钟HCLK = SYSCLK
  34.         RCC_PCLK2Config(RCC_HCLK_Div2); //设置高速APB时钟PCLK2 =系统时钟2分频PCLK2 = SYSCLK / 2
  35.         RCC_PCLK1Config(RCC_HCLK_Div4); //设置低速APB时钟PCLK1 =系统时钟4分频PCLK = SYSCLK / 4       
  36.         //默认VCO输入频率=外部晶振频率/外部晶振频率= 1Mhz,所以PLLM =频率,注意的是2 <= PLLM <= 63
  37.         //默认VCO输出频率= VCO输入频率* PLLN,并且192 <= PLLN <= 432,默认设置PLLN = 336,正好使VCO输出频率两分频后为168Mhz
  38.         //默认PLL输出时钟频率= VCO输出频率/ PLLP,并且PLLP = 2,4,6,8默认设置为2,使得PLL输出频率为168Mhz
  39.         //默认USB OTG FS时钟频率= VCO输出频率/ PLLQ,并且2 <= PLLQ <= 15默认设置为7,使得输出频率为48Mhz       
  40.         RCC_PLLConfig(RCC_PLLSource_HSI,16,336,2,7);
  41.         RCC_PLLCmd(ENABLE);       
  42.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)== RESET); //等待PLL稳定
  43.         / *配置Flash预取,指令缓存,数据缓存和等待状态* /
  44.         FLASH-> ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;               
  45.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK       
  46.         while(RCC_GetSYSCLKSource()!= 0x08); //读取时钟切换状态位,确保PLLCLK被选为系统时钟
  47. }
  48. / *
  49. *使用HSE时,设置系统时钟的步骤
  50. * 1,开启HSE,并等待HSE稳定
  51. * 2,设置AHB,APB2,APB1的预分频因子
  52. * 3,设置PLL的时钟来源
  53. *设置VCO输入时钟分频因子m
  54. *设置VCO输出时钟倍频因子
  55. *设置PLLCLK时钟分频因子p
  56. *设置OTG FS,SDIO,RNG时钟分频因子q
  57. * 4,开启PLL,并等待PLL稳定
  58. * 5,把PLLCK切换为系统时钟SYSCLK
  59. * 6,读取时钟切换状态位,确保PLLCLK被选为系统时钟
  60. * /
  61. void HSE_SetSysClock(uint32_t frequency)       
  62. {
  63.     __IO uint32_t HSEStartUpStatus = 0;
  64.     RCC_DeInit(); //复位RCC寄存器
  65.     RCC_HSEConfig(RCC_HSE_ON); //设置外部晶振HSE
  66.     HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE起振
  67.     if(HSEStartUpStatus == SUCCESS)
  68.     {
  69.         RCC_ClockSecuritySystemCmd(ENABLE); //启动时钟安全系统CSS
  70.         //调压器电压输出级别配置为1,以便在器件为最大频率
  71.         //工作时使性能和功耗实现平衡
  72.         RCC-> APB1ENR | = RCC_APB1ENR_PWREN;
  73.         PWR-> CR | = PWR_CR_VOS;
  74.         RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置ABH时钟HCLK =系统时钟HCLK = SYSCLK
  75.         RCC_PCLK2Config(RCC_HCLK_Div2); //设置高速APB时钟PCLK2 =系统时钟2分频PCLK2 = SYSCLK / 2
  76.         RCC_PCLK1Config(RCC_HCLK_Div4); //设置低速APB时钟PCLK1 =系统时钟4分频PCLK = SYSCLK / 4       
  77.         //默认VCO输入频率=外部晶振频率/外部晶振频率= 1Mhz,所以PLLM =频率,注意的是2 <= PLLM <= 63
  78.         //默认VCO输出频率= VCO输入频率* PLLN,并且192 <= PLLN <= 432,默认设置PLLN = 336,正好使VCO输出频率两分频后为168Mhz
  79.         //默认PLL输出时钟频率= VCO输出频率/ PLLP,并且PLLP = 2,4,6,8默认设置为2,使得PLL输出频率为168Mhz
  80.         //默认USB OTG FS时钟频率= VCO输出频率/ PLLQ,并且2 <= PLLQ <= 15默认设置为7,使得输出频率为48Mhz
  81.         RCC_PLLConfig(RCC_PLLSource_HSE,频率,336,2,7);
  82.         RCC_PLLCmd(ENABLE); //使能PLL               
  83.         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)== RESET); //等待PLL稳定
  84.         / *配置Flash预取,指令缓存,数据缓存和等待状态* /
  85.         FLASH-> ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;               
  86.         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK       
  87.         while(RCC_GetSYSCLKSource()!= 0x08); //读取时钟切换状态位,确保PLLCLK被选为系统时钟
  88.     }
  89.     else
  90.     {// HSE启动出错使用系统内部HSI时钟
  91.         HSI_SetSysClock();
  92.     }
  93. }
wenfen 发表于 2023-8-25 21:37 | 显示全部楼层
在外部晶振故障的时候完全可以使用内部晶振
daichaodai 发表于 2023-8-26 09:18 来自手机 | 显示全部楼层
ST出新型号H5了
Uriah 发表于 2024-9-11 07:31 | 显示全部楼层

环氧树脂由于硬度的原因不能用于应力敏感和含有贴片元件的模块灌封,在模块电源中基本被淘汰
帛灿灿 发表于 2024-9-11 09:27 | 显示全部楼层

产生一个充电放电的过程
Bblythe 发表于 2024-9-11 10:30 | 显示全部楼层

齐纳二极管作为ESD保护与单向TVS原理相同
周半梅 发表于 2024-9-11 12:26 | 显示全部楼层

之所以称为ESD静电保护器
Pulitzer 发表于 2024-9-11 13:29 | 显示全部楼层

钳位二极管最常用于集成电路中
童雨竹 发表于 2024-9-11 15:25 | 显示全部楼层

它迅速由高阻态变为低阻态
Wordsworth 发表于 2024-9-11 16:28 | 显示全部楼层

减少反射,避免振荡,方便调试
Clyde011 发表于 2024-9-11 17:31 | 显示全部楼层

大于1的定义为极高导热的性能,而对于模块电源此水平的导热系数是无法达到其散热功能的需求
公羊子丹 发表于 2024-9-11 18:24 | 显示全部楼层

得到正常工作状态下的输出电压和电流。
万图 发表于 2024-9-11 19:27 | 显示全部楼层

在电路中有部分电子元器件比较“脆弱”
您需要登录后才可以回帖 登录 | 注册

本版积分规则

71

主题

617

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部