嵌入式系统概述与 HAL 库
介绍嵌入式系统的基本概念、MCU 的运作方式,以及 STM32 HAL 库在开发体系中的位置与设计思想。
1. 什么是嵌入式系统
1.1 类比:单片机 vs PC
一台 PC 上运行着操作系统(Windows / Linux),可以同时打开浏览器、写代码、听音乐——它是一个通用计算平台。
嵌入式系统则不同:它只做一件事,但要做到极致——实时、可靠、低功耗。你的微波炉、无人机飞控、汽车 ECU 都是嵌入式系统。
┌──────────────────────────────────────────────────────┐
│ PC (通用计算) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 浏览器 │ │ VS Code │ │ 播放器 │ ← 多任务 │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Windows / Linux 操作系统 │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Intel/AMD CPU + 内存 + 硬盘 │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────┐
│ 嵌入式系统 (专用) │
│ ┌──────────────────────────────────────┐ │
│ │ FreeRTOS (轻量实时操作系统) │ ← 可选 │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ STM32F407 (ARM Cortex-M4, 168MHz) │ │
│ │ 192KB RAM, 512KB Flash │ │
│ └──────────────────────────────────────┘ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ GPIO │ │ UART │ │ CAN │ │ SPI │ ← 外设直连 │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
└──────────────────────────────────────────────────────┘
1.2 本质
嵌入式系统的核心是一块微控制器(MCU, Microcontroller Unit)。MCU 将 CPU、内存(RAM/Flash)、外设(GPIO、UART、SPI 等)集成在同一块芯片上,形成一个自给自足的计算单元。
GSRL 项目所用的 STM32F407 基于 ARM Cortex-M4 内核,主频 168MHz,属于中高性能 MCU。GSRL_H7 所用的 STM32H7 系列则基于 Cortex-M7,主频可达 480MHz。
2. MCU 的运作方式
2.1 三大核心组成
┌─────────────────────────────────────────┐
│ STM32 MCU │
│ ┌───────────┐ ┌─────────────────────┐ │
│ │ Cortex-M4 │ │ Flash (512KB) │ │
│ │ 内核 │ │ 程序存储 │ │
│ └─────┬─────┘ └─────────────────────┘ │
│ │ │
│ ┌─────┴─────────────────────────────┐ │
│ │ 总线矩阵 (Bus Matrix) │ │
│ └─────┬─────────────────────────────┘ │
│ │ │
│ ┌─────┴─────┐ ┌──────────┐ ┌───────┐ │
│ │ RAM 192KB │ │ GPIO×N │ │ UART │ │
│ │ 数据存储 │ │ 引脚控制 │ │ 串口 │ │
│ └───────────┘ └──────────┘ └───────┘ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ SPI │ │ I2C │ │ CAN │ │ TIM │ │
│ │ ... │ │ ... │ │ ... │ │ ... │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────────┘
- 内核(Core):执行指令,处理运算。Cortex-M4 支持 DSP 指令和单精度浮点(FPU),这对机器人控制中的 PID 计算、姿态解算至关重要。
- 内存:Flash 存程序,RAM 存运行时数据。嵌入式系统内存极度受限(192KB RAM),需要精打细算。
- 外设(Peripheral):MCU 与外部世界交互的桥梁。GPIO 控制引脚电平,UART/SPI/I2C/CAN 负责通信,TIM 产生 PWM 驱动电机。
2.2 启动流程
上电 → 复位向量 → SystemInit() → main()
│
├─ 初始化时钟树(配置 HSE/PLL,产生 168MHz 系统时钟)
├─ HAL_Init()
├─ SystemClock_Config()
├─ MX_XXX_Init() ← 逐个初始化外设
├─ osKernelInitialize()
├─ MX_FREERTOS_Init()
└─ osKernelStart() ← 调度器接管,不再返回
对应工程中的 CubeMX_BSP/Src/main.c:
int main(void)
{
HAL_Init(); // 初始化 HAL 库
SystemClock_Config(); // 配置系统时钟 168MHz
MX_GPIO_Init(); // 初始化 GPIO
MX_DMA_Init();
MX_CAN1_Init(); // 初始化 CAN1
MX_SPI1_Init(); // 初始化 SPI1
// ... 其他外设初始化
osKernelInitialize(); // FreeRTOS 内核初始化
MX_FREERTOS_Init(); // 创建任务
osKernelStart(); // 启动调度器
while (1) {} // 永远不会执行到这里
}
2.3 代码如何变成运行的程序
源文件 (.c/.cpp) → 交叉编译 → .elf → Flash 烧录
│ │
│ arm-none-eabi-gcc
│ 生成 ARM 机器码
│
└── 注意:不是用 PC 上的 gcc,而是交叉编译器
因为目标 CPU 是 ARM 架构,不是 x86
3. HAL 库是什么
3.1 问题的提出
直接操作 STM32 的寄存器可以控制外设,例如让 PA5 引脚输出高电平:
// 寄存器方式——直接操作地址
*(volatile uint32_t *)0x40020014 |= (1 << 5); // GPIOA BSRR 寄存器
这种方式的问题:
- 不可读:0x40020014 是什么?不查手册完全不知道。
- 不可移植:STM32F4 和 STM32H7 的寄存器地址不同,同样的功能需要写两份代码。
- 容易出错:位操作稍有不慎就会影响其他引脚。
3.2 HAL 的解决方案
HAL(Hardware Abstraction Layer,硬件抽象层)是 ST 官方提供的一套函数库,为所有 STM32 外设提供统一的 API:
// HAL 方式——语义清晰
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // PA5 输出高电平
// 同样的 API 在 STM32F4、STM32H7 上都可用(重新编译即可)
3.3 HAL 库的层次化设计
┌───────────────────────────────────────────┐
│ 用户应用程序 (Task/) │ ← 你的业务逻辑
├───────────────────────────────────────────┤
│ GSRL 设备层 (Device/) │ ← 电机、IMU、遥控器对象
├───────────────────────────────────────────┤
│ GSRL 驱动层 (Driver/) │ ← CAN/UART/SPI 封装
├───────────────────────────────────────────┤
│ STM32CubeMX 生成代码 (CubeMX_BSP/) │ ← HAL 初始化代码
├───────────────────────────────────────────┤
│ HAL 库 (stm32f4xx_hal_*.c) │ ← ST 官方 HAL API
├───────────────────────────────────────────┤
│ CMSIS (Cortex 微控制器软件接口标准) │ ← ARM 统一标准
├───────────────────────────────────────────┤
│ 硬件寄存器 │ ← 芯片物理层
└───────────────────────────────────────────┘
3.4 HAL 的核心设计模式
HAL 库围绕两个核心概念组织 API:
| 概念 | 含义 | 示例 |
|---|---|---|
| 句柄(Handle) | 代表一个外设实例的结构体,包含配置和状态 | CAN_HandleTypeDef hcan1 |
| 回调(Callback) | 外设事件发生时 HAL 自动调用的函数 | HAL_CAN_RxFifo0MsgPendingCallback() |
初始化外设的典型模式:
// 1. 声明句柄(通常在 CubeMX 生成的代码中)
CAN_HandleTypeDef hcan1;
// 2. CubeMX 生成初始化函数,配置句柄的参数
void MX_CAN1_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 7;
hcan1.Init.Mode = CAN_MODE_NORMAL;
// ... 更多配置
HAL_CAN_Init(&hcan1); // 调用 HAL API 完成初始化
}
// 3. 用户代码中使用句柄操作外设
HAL_CAN_AddTxMessage(&hcan1, &txHeader, txData, &mailbox);
4. CubeMX 的角色
STM32CubeMX 是一个图形化配置工具,通过它你可以:
- 选引脚:指定 PA9 做 USART1_TX,PA10 做 USART1_RX
- 配时钟:设定 HSE → PLL → 168MHz 的时钟路径
- 配外设:设定 CAN 的波特率、UART 的波特率、SPI 的模式
- 配 FreeRTOS:创建任务、队列、信号量
CubeMX 最终生成一整套初始化代码,放在 CubeMX_BSP/ 目录下。这些代码不应手动修改,因为重新生成会覆盖你的改动。所有用户自定义代码应写在 /* USER CODE BEGIN */ 和 /* USER CODE END */ 之间。
5. FreeRTOS 概述
GSRL 使用 FreeRTOS 作为实时操作系统。相对于裸机编程(Bare Metal),FreeRTOS 提供了:
- 任务调度:多个任务按优先级轮流执行,看起来像"同时运行"
- 任务间通信:队列、信号量、互斥锁
- 软件定时器:不占用硬件定时器资源
裸机(Bare Metal):
┌──────────────────────────────────┐
│ while(1) { │
│ 读取传感器(); │
│ 控制电机(); │
│ 发送数据(); │ ← 顺序执行,一个慢了全卡住
│ } │
└──────────────────────────────────┘
FreeRTOS:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 传感器任务 │ │ 控制任务 │ │ 通信任务 │ ← 调度器切换
│ (10ms) │ │ (1ms) │ │ (100ms) │
└──────────┘ └──────────┘ └──────────┘
↓ ↓ ↓
┌──────────────────────────────────────┐
│ FreeRTOS 调度器 │
│ 按优先级+时间片切换 │
└──────────────────────────────────────┘
GSRL 中的任务定义在 CubeMX_BSP/Src/freertos.c 中:
osThreadId_t testHandle;
const osThreadAttr_t test_attributes = {
.name = "test",
.stack_size = 128 * 4, // 栈大小 512 字节
.priority = (osPriority_t) osPriorityNormal, // 优先级
};
// 在 MX_FREERTOS_Init() 中创建:
testHandle = osThreadNew(test_task, NULL, &test_attributes);
6. 总结
| 要点 | 说明 |
|---|---|
| MCU | CPU + 内存 + 外设 集成在单芯片上 |
| STM32F407 | Cortex-M4 内核,168MHz,192KB RAM |
| HAL 库 | ST 提供的硬件抽象层,屏蔽寄存器细节 |
| 句柄 | 代表外设实例的结构体,HAL API 的核心参数 |
| CubeMX | 图形化配置工具,生成初始化代码 |
| FreeRTOS | 轻量实时操作系统,负责任务调度 |
| 启动流程 | 上电 → 时钟初始化 → 外设初始化 → FreeRTOS 接管 |
与 GSRL 的关系
GSRL 正是基于 HAL 库分层构建的:Driver 层封装 HAL API,Device 层使用 Driver 层的接口控制具体设备,Algorithm 层提供数学和控制算法。理解 HAL 库的句柄与回调机制,是理解整个 GSRL 代码运转方式的基础。
下一篇:时钟树与总线架构
作者: Qing | 修改日期: 2026-07-18