在刚开始学习单片机的时候,一直以为程序启动后就直接进入到了main函数,但是随着学习的深入才发现,程序在进入main函数前其实还要干好多事情。现在就来分析一下,STM32系列单片机程序在进入main函数前都在干些什么?

单片机上电后,程序首先跳转到地址0处,此时主堆栈指针MSP的初值也为0。然后单片机产生了复位信号,主堆栈指针加1,由于单片机内核为32位,所以地址增加一位,实际上是增加了32位,也就是增加了4个字节。此时MSP指针就指向了复位向量。而Cortex-M内核处理器的向量表可以重新定位,所以此时程序就会跳转到复位向量重新映射的地址处。

通过上面的两个图可以看到,通过复位向量的重映射后,MSP指针就会跳转到复位向量处,在STM32系列单片机中,复位向量的函数通常在启动文件startup_stm32f10x_xx.s中实现。

下来接着看一下复位函数都实现了哪些功能。

可以看到复位函数首先获取到了main()函数和系统初始化函数SystemInit()的地址,然后跳转到系统初始化函数中SystemInit()中,接着就会跳转到main函数中。

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_CLRCC->CFGR &= ( uint32_t )0xF8FF0000;
#elseRCC->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_ExtSRAMSystemInit_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_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}

在系统复位函数SystemInit()中,主要是复位各个寄存器,将寄存器值设置位默认值,最后调用时钟设置函数 SetSysClock()对系统时钟进行设置。

static void SetSysClock( void )
{
#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHzSetSysClockTo72();
#endif/* If none of the define above is enabled, the HSI is used as System clocksource (default after reset) */
}

系统设置函数,根据不同的晶振和单片机型号,选择相应频率的时钟进行设置。

static void SetSysClockTo72( void )
{__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*//* Enable HSE */RCC->CR |= ( ( uint32_t )RCC_CR_HSEON );/* 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 ) );if ( ( RCC->CR & RCC_CR_HSERDY ) != RESET ){HSEStatus = ( uint32_t )0x01;}else{HSEStatus = ( uint32_t )0x00;}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;/* PCLK1 = HCLK */RCC->CFGR |= ( uint32_t )RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL/* Configure PLLs ------------------------------------------------------*//* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz *//* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */RCC->CFGR2 &= ( uint32_t )~( RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC );RCC->CFGR2 |= ( uint32_t )( RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5 );/* Enable PLL2 */RCC->CR |= RCC_CR_PLL2ON;/* Wait till PLL2 is ready */while( ( RCC->CR & RCC_CR_PLL2RDY ) == 0 ){}/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */RCC->CFGR &= ( uint32_t )~( RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL );RCC->CFGR |= ( uint32_t )( RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |RCC_CFGR_PLLMULL9 );
#else/*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */RCC->CFGR &= ( uint32_t )( ( uint32_t )~( RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |RCC_CFGR_PLLMULL ) );RCC->CFGR |= ( uint32_t )( RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9 );
#endif /* STM32F10X_CL *//* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while( ( RCC->CR & RCC_CR_PLLRDY ) == 0 ){}/* Select PLL as system clock source */RCC->CFGR &= ( uint32_t )( ( uint32_t )~( RCC_CFGR_SW ) );RCC->CFGR |= ( uint32_t )RCC_CFGR_SW_PLL;/* Wait till PLL is used as system clock source */while ( ( RCC->CFGR & ( uint32_t )RCC_CFGR_SWS ) != ( uint32_t )0x08 ){}}else{/* If HSE fails to start-up, the application will have wrong clockconfiguration. User can add here some code to deal with this error */}
}
#endif

在系统时钟设置函数中,设置锁相环,及各个时钟的频率。

关于时钟的具体设置,可以参考下面这张图。

通过上面的分析,可以知道,程序在进入main之前执行流程为

这里大概分析了单片机在进入main函数之前,大概都做了哪些工作,对于具体的启动文件代码没做分析。对于启动文件startup_stm32f10x_hd.s的详细分析,在另一篇文章中进行说明。

STM32单片机启动文件startup_stm32f10x_hd.s详解

STM32系列单片机在进入main函数前都在干些什么?相关推荐

  1. STM32系列单片机SPI速度研究(flash读取写入速度提高,液晶显示屏刷新率提高)

    STM32系列单片机SPI速度研究(flash读取写入速度提高,液晶显示屏刷新率提高) 前言 设备参数 测试内容 1.软件模拟SPI 1). 程序代码 2). 示波器波形采集 2.HAL库SPI函数 ...

  2. C++main函数的参数介绍以及如何在main函数前执行一段代码

    C++中参数介绍:https://www.cnblogs.com/jisongxie/p/7892366.html C++中主函数的执行过程以及如何在main函数前执行一段代码:https://www ...

  3. STM32系列单片机向量表和向量表重新定位

    在使用STM32系列单片机的IAP升级功能时,第一行代码就是关于向量表重定位的设置. 那么这个向量表具体是什么东西?为什么可以重定位?关于这方面的资料在ARM Cortex-M3 与 Cortex-M ...

  4. 关于STM32系列单片机中断触发时间问题

    在使用STM32系列单片机的时候,经常要使用到中断,但是STM32参考手册上关于中断只说明了有哪些中断源和中断向量表相关问题.没有具体说明触发中断的信号至少需要多长时间?中断检测到中断源需要多长时间? ...

  5. **浅谈STM32系列单片机的零基础学习方法**

    浅谈STM32系列单片机的零基础学习方法 *很多朋友想必在零基础学习STM32F1这系列单片机时会感觉无从下手,或者不知道写程序时到底是用库函数好还是寄存器好.* 我个人认为一个零基础的朋友可以通过以 ...

  6. STM32系列单片机标准库移植FreeRTOS V10.4.6详解

      文中所用到的资料下载地址 https://download.csdn.net/download/qq_20222919/87370679   最近看正点原子新录制了手把手教你学FreeRTOS的视 ...

  7. DSP芯片上电后在执行main函数前的执行流程

    以tms320f28377d为例: 假设我们创建工程test: 该项目中需要注意的文件包括(见图1): 1. main.c文件: 2. DSP用于连接.coff(可执行文件)的  .cmd文件: 3. ...

  8. 一个C++程序执行main函数前和执行完main函数后会发生什么。

    总结: main函数执行之前,主要就是初始化系统相关资源: 设置栈指针 初始化static静态和global全局变量,即data段的内容 将未初始化部分的赋初值:数值型short,int,long等为 ...

  9. 01 STM32系列单片机的基本结构

    1. 微型计算机和单片机的基本结构 微型计算机的基本结构如下图所示. 1.1 控制器 控制器(Controller)是计算机的控制核心,它的功能是负责从内部存储器取出指令,对指令进行分析.判断,并根据 ...

最新文章

  1. 东莞网络推广浅析如何通过简化标题来提升核心关键词排名能力呢?
  2. chapter 01
  3. 超低延迟直播架构解析
  4. linux离线安装python3.7教程_Linux傻瓜式七步完美安装Python3.7
  5. [导入]Google Earth坐标集(能更看清这个世界喽!)
  6. LeetCode 2013. 检测正方形(字典)
  7. 创建struct fib_info
  8. Material Design(九)--CoordinatorLayout和App Bar
  9. ubuntu ssh密钥_生成SSH密钥以在Ubuntu中进行无密码登录
  10. 基于目标检测的电车充电插孔检测实践
  11. t-SNE数据降维可视化
  12. RPM命令详解(安装、升级、卸载)
  13. Verilog学习日志(2021.7.31)
  14. 新版个人所得税计算python_最新个税计算 / 个税计算器 小程序 wepy 开发
  15. H5唤起主流安卓应用市场
  16. 看柴静《苍穹之下》有感
  17. 用 Python 自动玩王者荣耀,有点意思!
  18. platform模型
  19. java计算机毕业设计ssm学生宿舍管理系统15pjb(附源码、数据库)
  20. NLP经典论文:Layer Normalization 笔记

热门文章

  1. Android打开App2SD
  2. [转]把复杂事物简明化
  3. 应用层协议之CCNA必备知识点精髓
  4. Delphi XE10.1 引用计数
  5. eclipse+maven远程(自动)部署web项目到tomcat
  6. leetcode Sudoku java
  7. SQL2005迁移账户密码粗鲁设置
  8. 接口测试工具--apipost如何取消json参数中转义字符
  9. JUnit5 @AfterAll注解示例
  10. excel删除行 uipath_高级会计师都在用的Excel批处理技巧,祝你早日告别加班