认识HAL库

一、为什么需要 HAL:从寄存器到 CMSIS 到 HAL

问题起点:C 代码本来就能直接读写硬件寄存器(靠内存映射),但写法五花八门、无法移植。

ARM 的解法 ------ CMSIS 标准(Cortex Microcontroller Software Interface Standard),把代码分成三层:

层 谁负责 内容
内核层 ARM 统一的寄存器定义、内核操作函数(NVIC、SysTick、__WFI 等)
外设层 各芯片厂商(ST / GD / NXP...) 按统一格式定义自家外设寄存器和中断号
高级库层 ST 在 CMSIS 之上再封一层:HAL 库

收益:同一套内核代码可跨厂商复用,外设代码换芯片时改动量大幅下降。

二、HAL / 标准库 / LL 三者对比

特点 代价
HAL 统一 API、带参数检查、回调机制、DMA 封装 代码量约为标准库的 1.5~2 倍,多几层函数调用,稍慢
标准库(SPL) 紧贴寄存器,精简、快 绑死单个系列;已停止维护,新芯片不再提供
LL(Low-Layer) 代码量接近标准库,命名风格与 HAL 一致 覆盖的外设不如 HAL 全
  • LL 可以和 HAL 混用 (例如 GPIO 用 LL、USART 用 HAL),但同一个外设不要混用。

  • 选 HAL 的现实理由不只是"可移植":ST 新芯片只出 HAL/CubeMX,标准库已是历史。

三、内核级 API(CMSIS 提供,HAL 不封装的那一层)

3.1 关 / 开总中断

复制代码
 __disable_irq();   /* PRIMASK = 1 */
 ​
 /* 临界区:这几行必须一口气执行完,不能被中断打断 */
 ​
 __enable_irq();    /* PRIMASK = 0 */
  • "总中断"= Cortex-M 内核的 PRIMASK 寄存器 。它为 1 时,除 NMI 和 HardFault 外,所有可屏蔽中断全部关闭。

  • 用途:进入临界区。

__enable_irq() 是"无条件开门"。如果临界区里又嵌了一层临界区,内层的 __enable_irq() 会在外层还没执行完时就提前开门。正确写法是保存并恢复:

复制代码
 uint32_t pm = __get_PRIMASK();
 ​
 __disable_irq();
 ​
 ...
 ​
 __set_PRIMASK(pm);   /* 恢复到进入前的状态,而不是无条件开 */

RTOS 里另外用 BASEPRI(__set_BASEPRI)只屏蔽低于某优先级的中断,让高优先级中断仍能响应。

3.2 NVIC:使能与优先级

复制代码
 HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);   /* 抢占优先级 2,子优先级 0 */
 ​
 HAL_NVIC_EnableIRQ(USART1_IRQn);           /* 内部即 CMSIS 的 NVIC_EnableIRQ */

配置完中断触发条件后,必须调 NVIC_EnableIRQ 开这个门,NVIC 才会真的响应。

函数 说明
NVIC_EnableIRQ(IRQn) CMSIS 原版,按中断号使能
NVIC_SetPriority(IRQn, priority) CMSIS 原版,只收一个拼好的数值(需自己算分组),不直观
HAL_NVIC_SetPriority(IRQn, 抢占, 子) 实际用的是它,两个参数分开传,内部做分组换算
HAL_NVIC_SetPriorityGrouping(group) 设优先级分组

优先级规则:

  • 抢占优先级:数字越小越优先,高的能打断低的(中断嵌套)

  • 子优先级 :抢占相同时决定谁先响应,不能互相打断

  • STM32F4 只实现 4 位优先级 (__NVIC_PRIO_BITS = 4),所以每档取值 0~15

3.3 SysTick

复制代码
 SysTick_Config(ticks);

HAL_Delay() 和 HAL_GetTick() 背后就是它。

  • 链路:HAL_Init() → HAL_InitTick() 配置 SysTick 为 1ms → SysTick_Handler()(在 stm32f4xx_it.c)调 HAL_IncTick() → 累加 uwTick → HAL_GetTick() 读它。
  1. SysTick 优先级默认是最低的 (TICK_INT_PRIORITY = 0x0F),所以 在中断服务函数里调 HAL_Delay() 会死等 ------SysTick 抢不进来,uwTick 不增加。

  2. 自己调 SysTick_Config() 会覆盖 HAL 的配置,导致 HAL_Delay() 失效。要用就确认没冲突。

3.4 低功耗与空指令

复制代码
 while (1) {
 ​
     /* 处理事件 */
 ​
     __WFI();   /* 没事就睡觉,等按键/串口中断唤醒 */
 ​
 }
  • __WFI():进入睡眠,低功耗产品(尤其电池供电)的标配。

  • __NOP():一个时钟周期什么都不做。不跟 HAL_Delay() 竞争 (一个是 ns 级,一个是 ms 级)。用途:模拟 I2C / OLED / SD 卡这类软件时序,用 NOP 凑周期最精确。

四、CubeMX 标准工程的文件地图

4.1 目录结构

复制代码
 工程根/
 ​
 ├── .ioc                          ← 配置真源,必须进 git
 ​
 ├── Core/
 ​
 │   ├── Inc/     main.h  stm32f4xx_hal_conf.h  stm32f4xx_it.h
 ​
 │   └── Src/     main.c  stm32f4xx_hal_msp.c  stm32f4xx_it.c  system_stm32f4xx.c
 ​
 ├── Drivers/
 ​
 │   ├── CMSIS/                    ← 内核 + 器件头文件(ARM + ST)
 ​
 │   └── STM32F4xx_HAL_Driver/     ← HAL 源码(Inc + Src)
 ​
 └── MDK-ARM/                      ← .uvprojx + startup_stm32f4xxxx.s

4.2 各文件职责

文件 位置 职责
main.c / main.h Core main()、SystemClock_Config()、MX_xxx_Init();引脚宏定义
stm32f4xx_hal_conf.h Core/Inc HAL 配置:外设模块开关 、HSE_VALUE(晶振值)、TICK_INT_PRIORITY
stm32f4xx_it.h Core/Inc 中断服务函数的声明
stm32f4xx_it.c Core/Src 中断服务函数实现 :SysTick_Handler、USART1_IRQHandler 等
stm32f4xx_hal_msp.c Core/Src 外设底层初始化 :GPIO 复用、时钟使能、NVIC 优先级配置------CubeMX 自动生成骨架
system_stm32f4xx.c Core/Src SystemInit(),上电时初始化系统时钟、向量表;一般不用改
stm32f4xx_hal.c Drivers HAL_Init、HAL_Delay、HAL_GetTick、弱定义的 HAL_MspInit

外设中断的优先级和使能,是在 stm32f4xx_hal_msp.c 里生成的

4.3 HAL 头文件索引

功能 头文件
HAL 总入口(HAL_Init / HAL_Delay) stm32f4xx_hal.h
GPIO(点灯、读引脚) stm32f4xx_hal_gpio.h
时钟配置 stm32f4xx_hal_rcc.h
串口 stm32f4xx_hal_uart.h / stm32f4xx_hal_usart.h
外部中断 stm32f4xx_hal_exti.h
定时器 stm32f4xx_hal_tim.h
SPI stm32f4xx_hal_spi.h
I2C stm32f4xx_hal_i2c.h
DMA stm32f4xx_hal_dma.h
NVIC / SysTick 的 HAL 封装 stm32f4xx_hal_cortex.h
ADC stm32f4xx_hal_adc.h
低功耗 stm32f4xx_hal_pwr.h
Flash 读写 stm32f4xx_hal_flash.h··
相关推荐
Zhao1368245539128 分钟前
DP4330A 与DP4363 测试对比
嵌入式硬件
辛迪聊物业数字化33 分钟前
智慧社区小程序落地避坑指南:3类物业方案选型+成本测算,线上服务零翻车
大数据·嵌入式硬件·百度·系统架构
电子科技圈1 小时前
Arm电机控制开发工具哪家强?
arm开发·单片机·嵌入式硬件·设计模式·软件构建
JasmineX-11 小时前
下位机直接控制57步进电机匀速转动
stm32·单片机·嵌入式硬件
聆思科技AI芯片2 小时前
【AI硬件开发上手教程】怎么使用AI编程实现小聆AI语音控制舵机
人工智能·嵌入式硬件·开源·ai编程·智能硬件
abc light2 小时前
ARM 裸机开发(6)——时钟树与定时器
arm开发·单片机·fpga开发
吠品12 小时前
智谱开源 ZCode 之后,真正的考试才开始
单片机·嵌入式硬件·1024程序员节
Chery114013 小时前
高速ADC与精密DAC怎么选?DP9230D与DP8532D应用解析
嵌入式硬件·物联网·射频工程
小李不想当小白16 小时前
SPI通信外设与W25Q64 (硬件SPI)(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
LCG米16 小时前
STM32驱动W5500以太网模块实测:TCP吞吐瓶颈定位、TX指针回绕陷阱与断线重连保活落地
stm32·单片机·嵌入式硬件·tcp/ip