STM32F1 - 源码解析SystemInit()


1> SystemInit( )调用位置

startup_stm32f10x_hd.s文件中:

; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit 
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP

复位中,在调用__main()函数时,
先调用了SystemInit(), 他干了点啥活呢?


2> SystemInit ()函数

// 文件system_stm32f10x.h:

/**
  * @brief  Setup the microcontroller system
  *         Initialize the Embedded Flash Interface, the PLL and update the 
  *         SystemCoreClock variable.
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */ 
  RCC->CR |= (uint32_t)0x00000001;
开启内部8MHz内部振荡器

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
  RCC->CFGR &= (uint32_t)0xF8FF0000; // 1111 1000 1111 1111 0000 0000 0000 0000
时钟配置寄存器CFGR全为0, 则系统时钟源选择高速内部时钟HSI

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF; // 1111 1110 1111 0110 1111 1111 1111 1111
关闭外部高速时钟HSE,时钟监测器关闭,PLL关闭

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF; // 1011 1111 1111 1111 1111
外部4-16MHz振荡器没有旁路, 分析到,发现,写库的人不爱用移位运算,这点随我

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  // 1111 1111 1000 0000 1111 1111 1111 1111
  RCC->CFGR &= (uint32_t)0xFF80FFFF; 
HSI振荡器时钟经过2分频后,作为PLL输入时钟;
PLL 2倍频输出, 那就是8MHz ÷ 2 *2 还是8MHz
  
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000; // 0000 0000 1001 1111 0000 0000 0000 0000
配置时钟中断 寄存器

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();
  
  /* Vector Table Relocation in Internal FLASH. */
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 
  这句话,非常重要,把异常向量表映射到Flash起始地址0x0800 0000
  }

2

2

RCC->CFGR &= (uint32_t)0xF8FF0000;
时钟配置寄存器CFGR,全为0, 重点关注SW,HSI作为系统时钟;
2
方法:看程序,对着参考手册, 看程序配置了哪些寄存器;

总结:

配置内部高速时钟HSI为时钟源,
调用 SetSysClock();
中断向量表放到Flash起始地址0x0800 0000;


3> SetSysClock()函数

// 文件system_stm32f10x.c:
#define SYSCLK_FREQ_72MHz  72000000
/**
  * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
  * @param  None
  * @retval None
  */
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
// ...
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
}

根据条件编译,调用SetSysClockTo72();


4> SetSysClockTo72()函数

1

ST公司的命名让人一看就知道干哈,要学学

// stm32f10x.h文件:
/*!< External High Speed clock enable */
#define  RCC_CR_HSEON        ((uint32_t)0x00010000)  
      
/*!< External High Speed clock ready flag */
#define  RCC_CR_HSERDY       ((uint32_t)0x00020000)  
      
/*!< Time out for HSE start up */
#define HSE_STARTUP_TIMEOUT  ((uint16_t)0x0500) 

/*!< SYSCLK not divided */
#define  RCC_CFGR_HPRE_DIV1   ((uint32_t)0x00000000)   
     
 /*!< HCLK not divided */
#define  RCC_CFGR_PPRE2_DIV1 ((uint32_t)0x00000000)  

/*!< HCLK divided by 2 */
// 0000 0000 0000 0000 0000 0100 0000 0000
#define  RCC_CFGR_PPRE1_DIV2 ((uint32_t)0x00000400)             

/*!< PLL entry clock source */
// 0001 0000 0000 0000 0000
#define  RCC_CFGR_PLLSRC  ((uint32_t)0x00010000)  

/*!< HSE divider for PLL entry */
// 0010 0000 0000 0000 0000
#define  RCC_CFGR_PLLXTPRE      ((uint32_t)0x00020000)        
      
/*!< PLLMUL[3:0] bits (PLL multiplication factor) */
// 0011 1100 0000 0000 0000 0000
#define  RCC_CFGR_PLLMULL      ((uint32_t)0x003C0000)    

/*!< HSE clock selected as PLL entry clock source */
#define  RCC_CFGR_PLLSRC_HSE  ((uint32_t)0x00010000)     

/*!< PLL input clock*9 */
#define  RCC_CFGR_PLLMULL9   ((uint32_t)0x001C0000)        
// 0001 1100 0000 0000 0000 0000    

/*!< PLL enable */  
#define  RCC_CR_PLLON  ((uint32_t)0x01000000)   
// 0000 0001 0000 0000 0000 0000 0000 0000 

 /*!< SW[1:0] bits (System clock Switch) */
#define  RCC_CFGR_SW  ((uint32_t)0x00000003)       

/*!< PLL selected as system clock */
#define  RCC_CFGR_SW_PLL ((uint32_t)0x00000002)      
  
/*!< SWS[1:0] bits (System Clock Switch Status) */        
#define  RCC_CFGR_SWS ((uint32_t)0x0000000C) 
// 1100

       
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;  

/**
  * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 
  *         and PCLK1 prescalers. 
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  // 0000 0000 0000 0001 0000 0000 0000 0000
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 外部高速时钟HSE振荡器开启
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

外部高速时钟,需要一定时间才能稳定,所以做超时判断,等待稳定
// do{}while{}这个风格学习下

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

// 如果HSE准备好
  if (HSEStatus == (uint32_t)0x01)
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

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

    /* HCLK = SYSCLK  */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
 APB2外设时钟设置,72MHz
    
    /* PCLK1 = HCLK / 2 */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
APB1外设时钟设置,36MHz

    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
//~ 0000 0000 0011 1111 0000 0000 0000 0000
//  1111 1111 1100 0000 1111 1111 1111 1111
   
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
// 00【0111】 【0】【1】 0000 0000 0000 0000 
// PLL 9倍频输出, HSE不分频, HSE时钟作为PLL输入时钟, 
到此PLLCLK为8X9 = 72MHz

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;
PLL使能, 打开PLL的输出

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
等待PLL使能准备好,这要是PLL准备不好,还就死这了啊,
也不是没道理,心脏都不跳了,还往下进行啥

    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
HSI作为系统时钟
    
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    
PLL输出作为系统时钟;0010,
要设置某几位, 先用【&=】把那几位清零,
再用【|=】设置那几位;

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
判断 系统时钟切换状态 (System clock switch status)
是否为PLL输出作为系统时钟;
  }
}

设置参数流程:
软件设置某项参数,硬件反馈状态标志为,软件再判断;
这个流程中,注意,硬件干的啥活,软件要干啥活;
44

配置完成时钟树:

4

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F1系列微控制器是意法半导体(STMicroelectronics)推出的一款嵌入式32位ARM Cortex-M3内核的微控制器。它具有强大的性能和丰富的功能,广泛应用于各种嵌入式系统中。 要实现STM32F1小灯的闪烁,我们可以通过以下步骤进行操作: 1. 配置硬件:连接STM32F1开发板上的LED灯到指定的GPIO引脚。通常,LED灯连接到开发板上的GPIO输出引脚。 2. 初始化系统时钟:设置STM32F1的系统时钟,以确保正确的时钟频率。这可以通过预定义的函数来完成,例如将系统时钟设置为外部晶体振荡器频率或使用内部时钟源。 3. 配置GPIO引脚:选择用于控制LED灯的GPIO引脚,并将其设置为输出模式。这可以通过设置相应的寄存器位来完成,例如使用GPIO_Init函数。 4. 闪烁逻辑:使用软件逻辑来控制GPIO引脚的状态,从而控制LED灯的闪烁。根据需求,可以编写一个简单的循环,将GPIO引脚的状态设置为高电平或低电平,并添加适当的延迟以产生闪烁效果。 下面是示例代码: ```c #include "stm32f10x.h" int main(void) { // 初始化系统时钟和GPIO引脚 SystemInit(); RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // 使能GPIOC时钟 GPIOC->CRH = (GPIOC->CRH & 0xFF0FFFFF) | 0x00300000; // 设置PC13引脚为输出模式,推挽输出 GPIOC->ODR |= GPIO_Pin_13; // 将PC13引脚设置为高电平 // 循环控制LED的闪烁 while (1) { GPIOC->ODR ^= GPIO_Pin_13; // 切换GPIOC引脚的状态,实现LED灯的闪烁 Delay(500000); // 延迟一段时间 } } // 延迟函数,用于控制LED闪烁频率 void Delay(uint32_t nCount) { for (uint32_t i = 0; i < nCount; i++); } ``` 以上代码中,使用了stm32f10x库函数来简化代码的编写。在主函数中,先进行了系统时钟和GPIO引脚的初始化,然后进入一个无限循环,不断地切换LED灯的状态,并添加延迟函数控制闪烁频率。 通过以上步骤,我们可以实现STM32F1小灯的闪烁效果。当然,具体的实现还需要根据具体的硬件和开发环境进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值