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

【经验分享】STM32F103单片机使用内部RC振荡器做时钟源

[复制链接]
STMCU小助手 发布时间:2022-3-22 13:00
平时在做项目的时候都用的是外部晶振做为时钟源,想试试用内部RC振荡器做为时钟源,在网上搜了一下如何设置内部时钟,发现资料比较少的。决定将设置内部RC振荡器做为时钟源的方法记录下来。
用的单片机是STM32F103C8T6,项目工程是在正点原子的示例代码上修改来的。用一个LED工程测试,在主程序中闪烁LED灯。

  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "led.h"
  5. int main ( void )
  6. {
  7.     delay_init();       //延时函数初始化
  8.     LED_Init();         //初始化与LED连接的硬件接口
  9.     while ( 1 )
  10.     {
  11.         LED = 0;
  12.         delay_ms ( 100 ); //延时300ms
  13.         LED = 1;
  14.         delay_ms ( 100 ); //延时300ms
  15.     }
  16. }
复制代码

首先使用默认时钟设置,也就是外部8M晶振做为时钟源。LED灯灭100ms,然后再亮100ms。
下来看默认时钟设置的代码:
在 system_stm32f10x.c 文件里面, SystemInit()函数设置时钟。

  1. void SystemInit (void)
  2. {
  3.     /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  4.     /* Set HSION bit */
  5.     RCC->CR |= (uint32_t)0x00000001;
  6.     /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
  7. #ifndef STM32F10X_CL
  8.     RCC->CFGR &= (uint32_t)0xF8FF0000;
  9. #else
  10.     RCC->CFGR &= (uint32_t)0xF0FF0000;
  11. #endif /* STM32F10X_CL */
  12.     /* Reset HSEON, CSSON and PLLON bits */
  13.     RCC->CR &= (uint32_t)0xFEF6FFFF;
  14.     /* Reset HSEBYP bit */
  15.     RCC->CR &= (uint32_t)0xFFFBFFFF;
  16.     /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  17.     RCC->CFGR &= (uint32_t)0xFF80FFFF;
  18. #ifdef STM32F10X_CL
  19.     /* Reset PLL2ON and PLL3ON bits */
  20.     RCC->CR &= (uint32_t)0xEBFFFFFF;
  21.     /* Disable all interrupts and clear pending bits  */
  22.     RCC->CIR = 0x00FF0000;
  23.     /* Reset CFGR2 register */
  24.     RCC->CFGR2 = 0x00000000;
  25. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  26.     /* Disable all interrupts and clear pending bits  */
  27.     RCC->CIR = 0x009F0000;
  28.     /* Reset CFGR2 register */
  29.     RCC->CFGR2 = 0x00000000;
  30. #else
  31.     /* Disable all interrupts and clear pending bits  */
  32.     RCC->CIR = 0x009F0000;
  33. #endif /* STM32F10X_CL */
  34. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  35. #ifdef DATA_IN_ExtSRAM
  36.     SystemInit_ExtMemCtl();
  37. #endif /* DATA_IN_ExtSRAM */
  38. #endif
  39.     /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  40.     /* Configure the Flash Latency cycles and enable prefetch buffer */
  41.     SetSysClock();

  42. #ifdef VECT_TAB_SRAM
  43.     SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
  44. #else
  45.     SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
  46. #endif
  47. }
复制代码

如何要使用内部RC振荡器做时钟源的话,需要重写SystemInit()函数。设置代码如下:
  1.    /* 开启HSI 即内部晶振时钟 */
  2.         RCC->CR |= ( uint32_t ) 0x00000001;
  3.         /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
  4.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;
  5.         /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/
  6.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                        //设置倍频后的频率
  7.         /* PLL不分频输出 ?*/
  8.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
  9.         /* 使能 PLL时钟 */
  10.         RCC->CR |= RCC_CR_PLLON;
  11.         /* 等待PLL时钟就绪*/
  12.         while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
  13.         {
  14.         }
  15.         /* 选择PLL为系统时钟的时钟源 */
  16.         RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
  17.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
  18.         /* 等到PLL成为系统时钟的时钟源*/
  19.         while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )
  20.         { }
复制代码

为了方便和以前的代码兼容,这里使用条件编译来选择使用外部晶振或者内部RC震荡。代码流程如下:
#if USE_HSI
{undefined
//使用内部RC
}
else
{undefined
//使用外部晶振
}
#endif
通过宏定义 USE_HSI 来选择时钟源,USE_HSI 为1时,使用内部RC做为时钟源,USE_HSI 为0时,使用外部晶振做为时钟源。
修改后的代码如下:

  1. #define  USE_HSI   0                        // 是否使用内部晶振  0 不使用  1使用
  2. void SystemInit ( void )
  3. {

  4. #if USE_HSI
  5.     {
  6. //设置使用内部晶振
  7.         /* 开启HSI 即内部晶振时钟 */
  8.         RCC->CR |= ( uint32_t ) 0x00000001;
  9.         /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
  10.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;
  11.         /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/
  12.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                         //设置倍频后的频率
  13.         /* PLL不分频输出 ?*/
  14.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
  15.         /* 使能 PLL时钟 */
  16.         RCC->CR |= RCC_CR_PLLON;
  17.         /* 等待PLL时钟就绪*/
  18.         while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
  19.         {
  20.         }
  21.         /* 选择PLL为系统时钟的时钟源 */
  22.         RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
  23.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
  24.         /* 等到PLL成为系统时钟的时钟源*/
  25.         while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )
  26.         { }
  27.     }
  28. #else
  29.     {
  30. //设置使用外部8M晶振
  31.         /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  32.         /* Set HSION bit */
  33.         RCC->CR |= ( uint32_t ) 0x00000001;

  34.         /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
  35. #ifndef STM32F10X_CL
  36.         RCC->CFGR &= ( uint32_t ) 0xF8FF0000;
  37. #else
  38.         RCC->CFGR &= ( uint32_t ) 0xF0FF0000;
  39. #endif /* STM32F10X_CL */

  40.         /* Reset HSEON, CSSON and PLLON bits */
  41.         RCC->CR &= ( uint32_t ) 0xFEF6FFFF;

  42.         /* Reset HSEBYP bit */
  43.         RCC->CR &= ( uint32_t ) 0xFFFBFFFF;

  44.         /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  45.         RCC->CFGR &= ( uint32_t ) 0xFF80FFFF;

  46. #ifdef STM32F10X_CL
  47.         /* Reset PLL2ON and PLL3ON bits */
  48.         RCC->CR &= ( uint32_t ) 0xEBFFFFFF;

  49.         /* Disable all interrupts and clear pending bits  */
  50.         RCC->CIR = 0x00FF0000;

  51.         /* Reset CFGR2 register */
  52.         RCC->CFGR2 = 0x00000000;
  53. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  54.         /* Disable all interrupts and clear pending bits  */
  55.         RCC->CIR = 0x009F0000;

  56.         /* Reset CFGR2 register */
  57.         RCC->CFGR2 = 0x00000000;
  58. #else
  59.         /* Disable all interrupts and clear pending bits  */
  60.         RCC->CIR = 0x009F0000;
  61. #endif /* STM32F10X_CL */

  62. #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  63. #ifdef DATA_IN_ExtSRAM
  64.         SystemInit_ExtMemCtl();
  65. #endif /* DATA_IN_ExtSRAM */
  66. #endif

  67.         /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  68.         /* Configure the Flash Latency cycles and enable prefetch buffer */
  69.         SetSysClock();

  70. #ifdef VECT_TAB_SRAM
  71.         SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
  72. #else
  73.         SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
  74. #endif
  75.     }

  76. #endif
  77. }
复制代码

内部RC默认为8M,将倍频数设置为9,这样使用内部RC振荡器之后,时钟频率就是36MHz。为使用外部晶振频率72MHz的一半。

  1.   /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/
  2.         RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;                         //设置倍频后的频率
复制代码

这时候在运行代码,用示波器测试LED的电平,发现是高电平200ms,低电平200ms。比使用外部时钟慢了一半,说明使用内部RC振荡器的设置代码是正确的。


收藏 评论0 发布时间:2022-3-22 13:00

举报

0个回答

所属标签

相似分享

官网相关资源

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