STM32F103单片机使用内部RC振荡器做时钟源

这是我参与更文挑战的第23天,活动详情查看: 更文挑战

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

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
int main ( void )
{
    delay_init();       //延时函数初始化
    LED_Init();         //初始化与LED连接的硬件接口
    while ( 1 )
    {
        LED = 0;
        delay_ms ( 100 ); //延时300ms
        LED = 1;
        delay_ms ( 100 ); //延时300ms
    }
}

复制代码

首先使用默认时钟设置,也就是外部8M晶振做为时钟源。LED灯灭100ms,然后再亮100ms。
下来看默认时钟设置的代码:
在 system_stm32f10x.c 文件里面, 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
}
复制代码

如何要使用内部RC振荡器做时钟源的话,需要重写SystemInit()函数。设置代码如下:

   /* 开启HSI 即内部晶振时钟 */
        RCC->CR |= ( uint32_t ) 0x00000001;
        /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;
        /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9;			//设置倍频后的频率
        /* PLL不分频输出 ?*/
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
        /* 使能 PLL时钟 */
        RCC->CR |= RCC_CR_PLLON;
        /* 等待PLL时钟就绪*/
        while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
        {
        }
        /* 选择PLL为系统时钟的时钟源 */
        RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
        /* 等到PLL成为系统时钟的时钟源*/
        while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )
        { }
复制代码

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


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

#if USE_HSI
    {
//设置使用内部晶振
        /* 开启HSI 即内部晶振时钟 */
        RCC->CR |= ( uint32_t ) 0x00000001;
        /*选择HSI为PLL的时钟源HSI必须2分频给PLL*/
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLSRC_HSI_Div2;
        /*PLLCLK=8/2*9=36MHz  设置倍频得到时钟源PLL的频率*/
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_PLLMULL9; 			//设置倍频后的频率
        /* PLL不分频输出 ?*/
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_HPRE_DIV1;
        /* 使能 PLL时钟 */
        RCC->CR |= RCC_CR_PLLON;
        /* 等待PLL时钟就绪*/
        while ( ( RCC->CR & RCC_CR_PLLRDY ) == 0 )
        {
        }
        /* 选择PLL为系统时钟的时钟源 */
        RCC->CFGR &= ( uint32_t ) ( ( uint32_t ) ~ ( RCC_CFGR_SW ) );
        RCC->CFGR |= ( uint32_t ) RCC_CFGR_SW_PLL;
        /* 等到PLL成为系统时钟的时钟源*/
        while ( ( RCC->CFGR & ( uint32_t ) RCC_CFGR_SWS ) != ( uint32_t ) 0x08 )
        { }
    }
#else
    {
//设置使用外部8M晶振
        /* 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
    }

#endif
}
复制代码

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

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

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

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享