本内容是基于江协科技STM32视频学习之后,并参考【重写】简析stm32启动过程-CSDN博客和STM32 最小系统_stm32最小系统-CSDN博客以及其他资料综合整理而成。
1. STM32
1.1 STM32简介
- STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器;
- STM32常应用在嵌入式领域,如智能车、无人机、机器人、无线通讯、物联网、工业控制、娱乐电子产品等;
- STM32F1系列是主流系列,有177的内核跑分和72Mhz的Cortex-M3内核;
1.2 ARM
- ARM:既指ARM公司,也指ARM处理器内核
- ARM公司是全球领先的半导体知识产权(IP)提供商,全世界超过95%的智能手机和平板都采用ARM架构;
- ARM公司设计ARM内核,半导体厂商完善内核周边电路并生产芯片;
A系列:应用(application),主要用于手机,苹果手机、高通手机芯片、联发科手机芯片;
R系列:RealTime,主要面向实时性很高的场景,硬盘控制器
M系列:Microcontroller,主要应用在单片机领域;
1.3 STM32F103C8T6:
系列:主流系列STM32F1
内核:ARM Cortex-M3
主频:72MHz
RAM:20K (SRAM)
ROM:64K (Flash)
供电:2.0~3.6V (标准3.3V)
封装:LQFP48
1.4 片上资源/外设
英文缩写 | 名称 | 英文缩写 | 名称 |
---|---|---|---|
NVIC | 嵌套向量中断控制器 | CAN | CAN通信 |
SysTick | 系统滴答定时器 | USB | USB通信 |
RCC | 复位和时钟控制 | RTC | 实时时钟 |
GPIO | 通用IO口 | CRC | CRC校验 |
AFIO | 复用IO口 | PWR | 电源控制 |
EXTI | 外部中断 | BKP | 备份寄存器 |
TIM | 定时器 | IWDG | 独立看门狗 |
ADC | 模数转换器 | WWDG | 窗口看门狗 |
DMA | 直接内存访问 | DAC | 数模转换器 |
USART | 同步/异步串口通信 | SDIO | SD卡接口 |
I2C | I2C通信 | FSMC | 可变静态存储控制器 |
SPI | SPI通信 | USB OTG | USB主机接口 |
- NVIC和SysTick是内核内的外设,其余是内核外的外设
- NVIC:内核内用于管理中断的设备,比如配置中断优先级这些东西
- SysTick:内核里面的一个定时器,主要用来给操作系统提供定时服务
- RCC:对系统的时钟进行配置,就是使能各模块的时钟。在STM32中,其它的这些外设在上电的情况下默认是没有时钟的,不给时钟的情况下,操作外设是无效的。外设也不会工作,这样的目的是降低功耗。所以,在操作外设之前,必须要先使能它的时钟。因此,需要用RCC来完成时钟的使能
- GPIO:用GPIO来点灯,读取按键
- AFIO:完成复用端口的重定义,还有中断端口的配置
- EXTI:外部中断,配置好外部中断后,当引脚有电平变化时,就可以触发中断,让CPU来处理任务。
- TIM:分为高级定时器、通用定时器、基本定时器;通用定时器:不仅完成定时中断任务,还可以完成测频率、生成PWM波形、配置成专用的编码器接口等功能。
- ADC:该STM32内置了12位的AD转换器,可以直接读取IO口的模拟电压值,无需外部连接AD芯片。
- DMA:可以帮助CPU完成搬运大量数据这样的繁杂任务
- USART:即支持异步串口,也支持同步串口
- I2C和SPI:STM32也内置了它们的控制器,可以用硬件来输出时序波形
- CAN:
- USB:
- RTC:在STM32内部完成年月日、时分秒的计时功能;可以接外部备用电池,即使掉电也能正常运行;
- CRC:是一种数据的校验方式,用于判断数据的正确性。
- PWR:可以让芯片进入睡眠模式等状态,来达到省电的目的;
- BKP:是一段存储器,当系统掉电时,仍可由备用寄存器保持数据,这个根据需要,可以完成一些特殊功能;
- IWDG和WWDG:当单片机因为电磁干扰死机或者程序设计不合理出现死循环时,看门狗可以及时复位芯片,保证系统的稳定;
- DAC:可以在IO口直接输出模拟电压;
- SDIO:可以用来读取SD卡;
- FSMC:可变静态存储控制器,可以用于扩展内存,或者配置成其他总线协议,用于某些硬件的操作;
- USB OTG:用OTG功能,可以让STM32作为USB主机去读取其他USB设备
1.5 STM32命名规则
1.6 STM32F013C8T6引脚定义
-
类型中:
- S代表电源,I代表输入,O代表输出,IO代表输入输出
-
I/O口电平:代表IO口所能容忍的电压;有FT代表能容忍5V的电压,没有FT只能容忍3.3V的电压。如果没有FT的需要接5V的电平,就需要加装电平转换电路了
-
主功能:上电后默认的功能,一般和引脚名称相同。如果不同的话,引脚的实际功能是主功能而不是引脚名称的功能。
-
默认复用功能:是IO口上同时连接的外设功能引脚。配置IO口的时候可以选择是通用IO口还是复用功能。
-
重定义功能:如果有两个功能同时复用在了一个IO口上,而你确实需要用到这两个功能,那么可以把其中一个复用功能重映射到其他端口上。当然前提是,这个重定义功能的表里有对应的端口。
-
1号VBAT:是备用电池供电的引脚,可以接一个3.3V的电池。当系统电源断电时,备用电池可以给内部的RTC时钟和备份寄存器提供电源。
-
2号引脚:是IO口或侵入检测或RTC。
- IO口可以根据程序输出或读取高低电平,是最基本的也是最常用的功能。
- 侵入检测TAMPER:可以用来做安全保障的功能。比如你的产品安全性比较高,可以在外壳加一些防拆的触点,然后接上电路到该引脚。若有人强行拆开设备,那触点断开,这个引脚的电平变化就会触发STM32的侵入信号,然后就会清空数据来保证安全。
- RTC引脚:可用来输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲
-
3、4号引脚:是IO口或者接32.768KHz的RTC晶振
-
5、6号引脚:接系统的主晶振,一般是8MHz的。芯片内部有锁相环电路,可以对这个8MHz的频率进行倍频,最终产生72MHz的频率,作为系统的主时钟
-
7号NRST:是系统复位引脚,N代表低电平复位
-
8、9号引脚:是内部模拟部分的电源,如ADC、RC震荡器。VSS是负极,接GND,VDD是正极,接3.3V。
-
10~19号引脚:都是IO口。PA0兼具了WKUP的功能,可以用于唤醒处于待机模式的STM32。
-
20号引脚:IO口或BOOT1引脚。BOOT1是用来配置启动模式的。
-
21、22号引脚:IO口
-
23、24号引脚:VSS_1和VDD_1是系统的主电源口。另外VSS_2、VDD_2、VSS_3、VDD_3,都是系统的主电源口。这里STM32内部采用了分区供电的方式。
-
25~33号引脚:都是IO口
-
34、37~40号引脚:都是IO口或者调试端口。默认的主功能是调试端口。调试端口是用来调试程序和下载程序的。支持SWD和JTAG两种调试方法。SWD需要两根线,分别是SWDIO和SWCLK。JTAG需要5根线,分别是JTMS、JTCK、JTDI、JTDO、NJTRST。当采用SWD方式时,其他的端口可以当做普通的IO口,但要在程序中进行配置,否则还是当作调试端口
-
41-43、45-46号引脚:都是IO口;
-
44号引脚 :BOOT0,也是用来做启动配置的。
1.7 STM32最小系统板
- 滤波电容: 在3.3V和GND之间接一个滤波电容,来保证供电电压的稳定
- 晶振电路 :接了一个8MHz的主时钟晶振,STM32的主晶振一般都是8MHz。
晶振电路的两根引脚分别通过两个网络标号,接到STM32的5、6号引脚。还需要接两个20pF的电容,作为起振电容,电容的另一端接地
如果需要RTC功能,则需要接一个32.768KHz的晶振,电路和这个一样,接在3、4号引脚。32768是2的15次方,内部RTC电路经过2的15次方分频,就可以生成1秒的时间信号了。 - 复位电路:由一个10k的电阻和0.1uF的电容组成,用来给单片机提供复位信号。NRST接在STM32的7号引脚。该复位电路在上电的瞬间,电容是没有电的。电源通过电阻开始向电容充电,并且此时电容呈现的是短路状态,NRST引脚就会产生低电平。当电容逐渐充满电时,电容就相当于断路,此时NRST就会被R1上拉为高电平。则上电瞬间的波形就是先低电平,然后逐渐高电平。该低电平就可以提供STM32的上电复位信号。按键是提供了一个手动复位的功能,当我们按下按键时,电容被放电,并且NRST引脚也通过按键被直接接地了,相当于手动产生了低电平复位信号。按键松手后,NRST又回归高电平,此时单片机就从复位状态转为工作状态。
- 启动配置:H1相当于开关,拨动开关,就可以让BOOT引脚选择接3.3V还是GND了。
- 下载端口:如果用STLINK下载程序的话,需要把SWDIO和SWCLK这两个引脚引出来方便接线。另外再把3.3V和GND引出来,这个GND是必须引出来的,3.3V如果板子自己有供电的话,可以不引
1.8 STM32开发方式
STM32的开发有基于寄存器、基于标准库也就是库函数的方式和基于HAL库的方式。
- 基于寄存器:是用程序直接配置寄存器,来达到我们想要的功能。
- 基于库函数:是使用ST官方提供的封装好的函数。通过调用这些函数来间接地配置寄存器。
- 基于HAL库:可以用图形化界面快速配置STM32,可以快速上手STM32,但隐藏了底层逻辑。
基于寄存器:
c
// 配置寄存器,点灯
// 1. RCC寄存器,来使能GPIOC的时钟,GPIO都是APB2的外设,
// 因此APB2外设时钟使能寄存器RCC_APB2ENR里面配置
// IOPCEN是使能GPIOC的时钟
// 2. 配置PC13口的模式
// 配置高寄存器GPIOx_CRH,x对应A~E中任意一个字母,
// CNF13和MODE13用来配置13号口
// CNF13配置为00和MODE13配置为11
// 3. 端口输出数据寄存器GPIOx_ODR,低电平亮,高电平灭。
RCC->APB2ENR = 0x00000010;
GPIOC->CRH = 0x00300000;
GPIOC->ODR = 0x00002000;
基于库函数:
c
// 使用库函数来点灯
// 1. 使能时钟,第一个参数选择外设,第二个选择新的状态
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
// 2. 配置端口模式,GPIO_Init
// 第一个参数是选择哪个GPIO,第二个是参数的结构体
// 是PC13口的LED,所以第一个参数写GPIOC
// 先定义一个结构体GPIO_InitStructure,有三个参数,
// 分别是GPIO模式、GPIO端口、GPIO速度
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
// 点灯,GPIO_SetBits将端口设置为高电平
GPIO_SetBits(GPIOC,GPIO_Pin_13);
// 点灯,GPIO_ResetBits将端口设置为低电平
// GPIO_ResetBits(GPIOC,GPIO_Pin_13);
1.9 STM32F103C8T6工程模板创建
|------|---------------------------------------|--------------------|
| STM32F10x固件库文件分析 |||
| 启动文件 | startup_stm32f10x_md.s | 汇编编写的启动文件 |
| 外设相关 | stm32f10x.h | 外设寄存器定义;针对片上的外设 |
| 外设相关 | stm32f10x_xxx.c | 外设固件库源文件 |
| 外设相关 | stm32f10x_xxx.h | 外设固件库头文件 |
| 内核相关 | core_cm3.h | 内核寄存器定义;针对内核的外设 |
| 内核相关 | core_cm3.c | 控制内核外设的相关函数 |
| 内核相关 | system_stm32f10x.c和system_stm32f10x.h | 用于系统初始化和配置系统时钟 |
| 内核相关 | misc.c和misc.h | 与NVIC和SysTick相关的函数 |
| 用户相关 | main.c | main函数 |
| 用户相关 | stm32f10x_conf.h | 软件库配置头文件 |
| 用户相关 | stm32f10x_it.c和stm32f10x_it.h | 中断服务函数 |
启动文件 | 区别 |
---|---|
startup_stm32f10x_ld.s | ld: low_density 小容量,Flash容量在16-32K之间 |
startup_stm32f10x_md.s | md: medium_density 中容量,Flash容量在64-128K之间 |
startup_stm32f10x_hd.s | hd: high_density 大容量,Flash容量在256-512K之间 |
startup_stm32f10x_xl.s | xl: 超大容量,Flash容量在512-1024K之间 |
库函数工程模板中建立3个文件夹:
1. Start文件夹
2. Library文件夹
3. User文件夹
1.10 stm32启动流程
1.10.1 启动配置
-
微控制器(单片机)上电后,是如何寻找到并执行main函数的呢?-----启动文件(Bootloader)
很显然微控制器无法从硬件上定位main函数的入口地址,因为使用C语言作为开发语言后,变量/函数的地址便由编译器在编译时自行分配,这样一来main函数的入口地址在微控制器的内部存储空间中不再是绝对不变的。
每一种微控制器(处理器)都必须有启动文件,启动文件的作用便是负责执行微控制器从"复位"到"开始执行main函数"中间这段时间(称为启动过程)所必须进行的工作。
-
启动模式:
根据选定的启动模式,主闪存存储器、系统存储器或SRAM可以按照以下方式访问:
- 从主闪存存储器(Flash)启动(启动方式):主闪存存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x0000 0000或0x0800 0000。
- 从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(互联型产品原有地址为0x1FFF B000,其它产品原有地址为0x1FFF F000)访问它。
- 从内置SRAM启动:只能在0x2000 0000开始的地址区访问SRAM。
注意: 当从内置SRAM启动,在应用程序的初始化代码中,必须使用NVIC的异常表和偏移寄存器,重新映射向量表至SRAM中。
1.10.2 启动流程
Cortex-M3内核规定,向量表的起始地址必须存放栈顶指针MSP的地址,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。
- 上电复位,硬件设置SP、PC的值
- SP:在内存划出一块区域为栈,这块空间的高地址放在了
__initial_sp
,存放的是栈顶指针MSP的地址。
- PC:PC == Reset_Handler,跳转到
Reset_Handler
执行,
- 跳转到
Reset_Handler
开始执行
- 调用
SystemInit
函数,设置系统时钟 - 调用
__main
函数,完成某些初始化,调用main函数。