【嵌入式八股11】STM32

发布于:2025-04-20 ⋅ 阅读:(58) ⋅ 点赞:(0)

一、STM32 启动流程

  1. 启动区域选择:STM32 依据 boot 引脚的设置来确定启动区域,具体如下:

引脚状态 启动方式 描述

x 0 片内 Flash 从代码区启动,支持 ICP 下载方式(如 SWD、JTAG 烧录),这是最常用的启动方式,代码存储在片内 Flash 中,稳定可靠。
0 1 系统存储器 通过内置 ROM 启动,采用 ISP 下载(出厂预置代码,常见的如使用 UART 烧录)。此方式一般用于出厂时的程序烧录或者在没有 SWD、JTAG 接口的情况下进行程序更新。
1 1 SRAM 从 RAM 启动,但数据在掉电后会丢失。这种启动方式常用于一些调试场景,方便快速测试代码,不过由于数据易失性,不适用于正式的产品运行。
  1. 运行 bootloader:当确定启动区域后,处理器开始运行 bootloader,主要包括以下几个步骤:
    • 初始化寄存器:处理器会将各个寄存器的值初始化为默认值,为后续的程序运行做好准备。
    • 硬件设置 SP、PC,进入复位中断函数 Rest_Hander()
      • 从 0x0800 0000 读取数据赋值给栈指针 SP(MSP),并设置为栈顶指针 0x2000 0000 + RAM_Size。这一步确定了栈的起始位置,为函数调用等操作提供了空间。
      • 从 0x0800 0004 读取数据赋值给 PC(指向 Reset_Handler 中断服务函数)。通过以下代码实现:
LDR R0, = SystemInit
BLX R0 

 - **设置系统时钟,进入 SystemInit()**:
    - 设置 RCC 寄存器各位,配置系统的时钟源、分频系数等,以确保系统能够稳定运行在合适的时钟频率下。
    - 设置中断向量表偏移地址,根据启动区域的不同,使用以下代码进行设置:

#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 

- **软件设置 SP,__main 入栈(系统初始化函数)**:通过以下代码将 __main 函数入栈,进一步进行系统的初始化操作:
 

LDR R0,=__main
BX R0

- **加载 data、bss 段并初始化_main 栈区**:由于哈弗体系结构决定了数据与代码分开存储,所以需要将 Flash 中的数据拷贝进入 SRAM,完成数据段和 bss 段的初始化。
 

3. 跳转到 main():完成上述一系列初始化操作后,程序跳转到 main() 函数,开始执行用户编写的应用程序代码。

二、OTA(Over-The-Air)的情况

在 FLASH 中添加引导程序后,引导程序与 APP 程序将各自对应一个中断向量表。假设引导程序占用 N + M Byte 的 FLASH 空间。

  1. 上电启动流程:上电后,单片机从复位中断向量表处获取地址,并跳转执行复位中断服务函数,执行完毕后执行主函数。随后执行 Bootloader 中程序跳转的相关代码跳转至 APP,即地址 0x08000004 + N + M 处。进入主函数的步骤与 Bootloader 函数一致。
  2. 中断处理流程:当运行在主函数时,若有中断请求被响应,此时 PC 指针本应当指向位于地址 0x08000004 处的中断向量表,但由于程序预先通过“SCB->VTOR = 0x08000000 | ADDR_OFF;”这一语句,使得中断向量表偏移 ADDR_OFF(N + M)地址,因此 PC 指针会跳转到 0x08000004 + N + M 处所存放的中断向量表处,随后执行本应执行的中断服务函数,在跳出函数后再进入主函数运行。 以下是实现程序跳转至 APP 的示例代码:
void iapLoadApp(uint32_t appxAddr)
{
    iapfun jumptoapp;
    // 检查 appxaddr 处存放的数据(栈顶地址 0x2000****)是不是在 RAM 的地址范围内
    if( 0x20000000 == ( (*(vu32*)appxAddr) & 0x2FFE0000) )
    { 
        // 拷贝 APP 程序的复位中断函数地址,用户代码区第二个字为程序开始地址(复位地址)(强制跳转到函数地址处执行,函数指针的方式)
        jumptoapp = (iapfun)*(vu32*)(appxAddr + 4);
        // 初始化 APP 堆栈指针(用户代码区的第一个字用于存放栈顶地址),重新分配 RAM
        MSR_MSP(*(vu32*)appxAddr); 
        // 执行 APP 的复位中断函数,跳转到 APP
        jumptoapp(); 
    }
}

三、中断相关知识

  1. 中断的过程
    • 中断初始化
      • 设置中断源,使某个外设具备产生中断的能力,例如配置 GPIO 引脚为外部中断模式。
      • 设置中断控制器,对某个外设的中断通道进行使能或屏蔽操作,同时设置中断优先级,以确定多个中断同时发生时的处理顺序。
      • 使能 CPU 中断总开关,允许 CPU 响应中断请求。
    • CPU 运行与中断响应:CPU 在运行正常程序的过程中,每执行完一条指令(指令的执行包含多个时钟周期,如取指、译码、执行等)都会检查是否有异常或中断产生。当产生中断(如用户按下按键)时,中断信号先经过中断控制器,然后传递给 CPU。
    • 中断处理步骤
      • 保存现场:将 PC、LR、MSP、通用寄存器、FPU 等相关寄存器的值压栈,保存当前程序的运行状态,以便中断处理完成后能够恢复继续执行。
      • 分辨异常/中断,调用对应的异常/中断处理函数:根据中断源的类型,找到对应的中断向量表中的地址,跳转到相应的中断处理函数进行处理。
      • 恢复现场:中断处理完成后,将之前压栈的寄存器值出栈,恢复 PC 的值,使程序继续执行原来的任务。
    • 中断优先级处理:在执行高优先级中断时,如果低优先级中断到来,低优先级中断不会被丢失,而是会等待高优先级中断处理完毕后再进行处理。
    • 中断向量表:当中断发生时,PC 设置为一个特定地址,这些地址按优先级排列就构成了异常向量表,它存储了各个中断处理函数的入口地址。
  2. 中断的定义与分类
    • 定义:中断是指正在执行某事件时,被另一个事件打断,从而造成任务切换的过程。
    • 分类:分为内核异常和外部中断。内核异常通常由 CPU 内部的一些错误或特殊情况引起,如复位、硬件故障等;外部中断则由外部设备(如按键、传感器等)产生的信号触发。
  3. 嵌套向量中断控制器 NVIC:NVIC 用于处理多个优先级中断到来后的处理顺序。当多个中断同时发生时,NVIC 根据预先设置的中断优先级,先处理优先级高的中断,处理完后再处理优先级低的中断。

四、STM32 定时器

  1. 定时器分类
    • 系统滴答定时器 SysTick:并非外设,而是 CM3 内核的一部分,主要用于产生系统时钟节拍,为操作系统提供基本的时间管理功能。
    • 看门狗定时器 WatchDog:包括 IWDG 独立看门狗和 WWDG 窗口看门狗。IWDG 采用独立时钟,主要用于监视硬件错误,当在规定时间内没有喂狗操作时,会触发系统复位;WWDG 采用系统时钟,用于监视软件错误,必须在规定时间窗口内刷新,否则也会触发系统复位,并且在进入 WWDG 中断时,可以保存复位前的数据,防止跑飞后跳过某些代码段。
    • 基本定时器 TIM6、TIM7:具有预分频和重装载寄存器功能,可用于简单的定时任务,如定时触发 ADC 转换等。
    • 通用定时器 TIM2、TIM3、TIM4、TIM5:除了基本定时器的功能外,还支持输出比较、输入捕获、PWM 输出、单脉冲等功能,应用较为广泛,如电机控制、PWM 调光等场景。
    • 高级定时器 TIM1、TIM8:在通用定时器的基础上,增加了死区控制功能,常用于需要控制功率器件(如 MOSFET)的场合,以避免上下桥臂同时导通造成短路。
  2. 基本定时与 PWM 原理
    • 基本定时:通过设置预分频寄存器和重装载寄存器的值,来确定定时器的定时周期。预分频器用于对定时器的时钟进行分频,重装载寄存器则存储定时器的计数值。
    • PWM:除了预分频和重装载寄存器外,还需要设置比较寄存器。比较寄存器的值决定了 PWM 波形的占空比,通过改变比较寄存器的值,可以实现对 PWM 波形的调整。

五、STM32 ADC

  1. 基本特性:STM32F1 的 ADC 精度为 12 位,每个 ADC 最多有 16 个外部通道。各通道的 A/D 转换可以单次、连续扫描或间断执行,ADC 转换的结果(6 - 12 位)可以左对齐或右对齐储存在 16 位数据寄存器中。ADC 的输入时钟不得超过 14MHz,其时钟频率由 PCLK2 分频产生。
  2. 数据处理与通道特性:一个 ADC 的不同通道读取的值在共用的 DR 寄存器中,因此在进行下一个通道采集前需要将数据取走,否则数据会丢失。此外,ADC 还具有注入通道,它可以在规则通道转换时,强行插入转换,用于处理一些优先级较高的模拟信号采集。
  3. 参考电压与采集精度:参考电压一般为 3.3V,采集精度与位数相关,计算公式为最大测量电压 / 2^采样位数,例如 3.3V / 2^12,采样方式采用逐次逼近法。

六、STM32 DMA

  1. DMA 作用:当外部设备(如硬盘、显卡、网络适配器等)需要与主存储器进行数据交换时,传统方式需要通过中央处理器(CPU)作为中介来完成数据传输操作。但在大量数据传输的情况下,这种方式会使 CPU 过多地参与数据传输,降低整体性能。而 DMA 可以在 CPU 不介入的情况下,将数据在外设与内存中进行传递,从而提高系统的运行效率。
  2. CPU 搬运数据与 DMA 传输对比
    • CPU 搬运数据顺序
      • 外设设置状态寄存器置位。
      • CPU 读取外设数据寄存器到 CPU 通用寄存器。
      • CPU 将通用寄存器数据写入内存。
    • DMA 传输优势:DMA 可以独立完成数据传输,不需要 CPU 频繁参与,节约了 CPU 的资源。
  3. DMA 配置
    • 配置 DMA 控制器:设置 DMA 通道、数据传输方向(外设到存储器或存储器到外设)、传输模式(单次传输、循环传输等)、数据宽度、传输计数等参数。
    • 分配内存:如果是外设到存储器的数据传输,需要分配一块足够大小的缓冲区。
    • 配置 DMA 通道:将外设和 DMA 通道连接起来,通常需要配置外设的 DMA 请求触发方式和 DMA 通道的优先级等参数。
    • 触发 DMA 传输:启动数据的传输,DMA 控制器将自动执行数据的传输,而不需要 CPU 的干预。
  4. DMA 工作模式
    • 循环模式:单轮传输结束后,重置传输计数器,重置传输地址为初始值,再次开始新一轮循环,适用于需要不断重复传输相同数据的场景。
    • 双缓冲区:一个缓冲区传输完成中断触发后,缓存地址乒乓交换,同时触发回调函数,常用于处理连续的数据传输,提高数据处理的效率。
  5. 实际应用:在实际应用中,需要分析性能瓶颈是数据频率还是数据量过大。如果是数据频率问题,可以采用双 DMA BUF 的方式来提高数据的处理速度;如果是数据量过大,则可以使用单个大 DMA BUF 来一次性传输更多的数据。

七、STM32 看门狗

  1. IWDG 独立看门狗:采用独立时钟,不受系统时钟的影响,主要用于监视硬件错误。在正常运行时,程序需要定期进行喂狗操作(即向看门狗计数器写入特定值),如果在规定时间内没有喂狗,看门狗计数器会溢出,从而触发系统复位,保证系统在硬件出现异常时能够恢复正常运行。
  2. WWDG 窗口看门狗:采用系统时钟,用于监视软件错误。它要求程序必须在规定的时间窗口内进行刷新操作,否则会触发系统复位。窗口看门狗的优势在于可以防止程序跑飞后跳过某些关键代码段,并且在进入 WWDG 中断时,可以保存复位前的数据,以便后续分析问题。

八、IO 口类型

分类 电平特性 用途 备注

上拉输入 常态为高电平(通过上拉电阻连接 VCC) 主要用于 IO 读取操作,当外部设备没有连接时,IO 口保持高电平状态 在一些按键输入电路中常用,按键按下时拉低电平,松开时恢复高电平
下拉输入 常态为低电平(通过下拉电阻连接 GND) 同样用于 IO 读取操作,当外部设备没有连接时,IO 口保持低电平状态
推挽输出 可以输出高电平和低电平,且都有较强的驱动能力,IO 输出 0 时接 GND,IO 输出 1 时接 VCC 一般用于 IO 输出操作,如控制 LED 灯的亮灭、驱动小型继电器等 驱动负载能力强,能够直接驱动一些简单的外部设备
开漏输出 只能输出低电平,高电平没有驱动能力,需要外部上拉电阻才能真正输出高电平 常用于实现线与功能,如在 IIC 总线中,只要有一个设备给低电平,那么总线都会被拉低,从而实现线与逻辑 在一些需要多个设备共享总线的场景中非常有用

九、STM32 主频、Flash、SRAM 大小

类型 主频 Flash 容量 RAM 容量 内核

STM32F407IGH6 168M 1024KB 192KB M4
STM32L151RET6 32M 512KB 80KB M3
STM32F103C8T6 72M 64KB 20KB M3
HC32L130E8PA 48M 64KB 8KB M0+

十、ADC 采样原理

ADC(Analog-to-Digital Converter)采样原理采用逐次逼近法,这一过程和用天平称物重非常相似。具体来说,天平称重物时,从最重的砝码开始试放,与被称物体进行比较,若物体重于砝码,则该砝码保留,否则移去。然后再加上第二个次重砝码,同样根据物体与砝码重量的比较结果决定第二个砝码的去留,如此一直加到最小一个砝码为止。最后将所有留下的砝码重量相加,就得到了物体的重量。

仿照这一思路,逐次比较型 A/D 转换器将输入模拟信号与不同的参考电压作多次比较,使转换所得的数字量在数值上逐次逼近输入模拟量对应值。通过不断地比较和调整,最终得到与输入模拟信号相对应的数字量输出。


网站公告

今日签到

点亮在社区的每一天
去签到