这一章在干嘛?
全面认识 STM32 HAL 库:由来、文件夹结构、关键 API(HAL_Init、HAL_GPIO_Init、HAL_UART_Transmit 等)、回调机制、与标准库的差异。后续 22 章实验都是基于 HAL 库写的。
7.1 初识 STM32 HAL 库
HAL = Hardware Abstraction Layer,硬件抽象层。它把寄存器操作封装成「人类语言」函数:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // 点亮 PA5
HAL 库优势:
- 可移植:同一段代码在 F1/F4/F7/H7 间几乎不用改;
- 标准化:函数命名规则一致,学一个会一类;
- 配合 CubeMX:图形化配置自动生成初始化代码。
原书图 7.1.1:寄存器 vs 标准库 vs HAL 库对比
7.2 HAL 库驱动包
STM32Cube_FW_F4 固件包结构:
STM32Cube_FW_F4_V1.x.x/
├── Drivers/
│ ├── BSP/ # 板级支持包(LCD/SDRAM 等)
│ ├── CMSIS/ # ARM 内核头 + 启动文件
│ └── STM32F4xx_HAL_Driver/ # HAL 库主体
│ ├── Inc/ # 头文件
│ └── Src/ # 源文件
├── Middlewares/ # 中间件(FreeRTOS/LwIP/FatFs/USB)
├── Projects/ # 例程
└── Utilities/ # 工具(LCD 字模/PC 测试软件)
7.3 HAL 库框架结构
HAL 库主要文件:
| 文件 | 作用 |
|---|---|
stm32f4xx_hal.h | 包含所有 HAL 头 + 通用宏 |
stm32f4xx_hal.c | HAL_Init / HAL_Delay / HAL_GetTick 等通用函数 |
stm32f4xx_hal_xxx.c | 各外设 HAL 实现(GPIO/USART/SPI/I2C/…) |
stm32f4xx_hal_msp.c | 外设底层回调(GPIO/时钟/DMA 中断初始化) |
原书图 7.3.1:HAL 库架构分层图
分层:
- 应用层:用户 main.c;
- HAL 层:
HAL_GPIO_Init等通用 API; - MSP 层:
HAL_GPIO_MspInit时钟/GPIO/DMA 配置; - 寄存器层:HAL 内部直接写寄存器。
7.4 如何使用 HAL 库
典型流程:
- CubeMX 配置 → 生成
main.c骨架; - 在 MSP 回调
HAL_MspInit()里加硬件相关配置; - 调用 外设初始化函数
HAL_GPIO_Init(); - 在 while 循环或回调里调用 外设操作函数;
- 中断处理统一在
xxx_IRQHandler里调HAL_xxx_IRQHandler+ 用户回调。
例:USART 收发字符串:
HAL_UART_Transmit(&huart1, (uint8_t *)"Hello\n", 6, 100);
HAL_UART_Receive_IT(&huart1, rx_buf, 1); // 启动接收中断
// 中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// 处理 rx_buf[0]
HAL_UART_Receive_IT(&huart1, rx_buf, 1); // 重新开启
}
}
7.5 HAL 库使用注意事项
必须开启 USE_HAL_DRIVER 宏,否则大量符号未定义。
中断回调要重新启动:HAL 的中断只触发一次,处理完必须再调 Receive_IT / Receive_DMA_IT。
阻塞 vs 中断 vs DMA:调试用阻塞(HAL_UART_Transmit),正式项目用中断或 DMA,避免卡死主循环。
原书图 7.5.1:HAL 中断回调机制流程图
HAL 库与标准库的主要差异?
HAL 库跨系列通用,配合 CubeMX;标准库仅 STM32 用,无 CubeMX 支持。
HAL 的 MSP 层是干嘛的?
外设底层回调:配置时钟、GPIO、中断优先级等硬件相关初始化。
HAL 的中断接收为什么处理完要再调
Receive_IT?HAL 中断模式只触发一次,必须手动重启才能继续接收。