第二层:嵌入式系统基础知识
这一章用于建立嵌入式系统的整体认知。它回答的是“嵌入式系统由什么组成、如何启动、如何调试、如何理解芯片手册与工具链”这些根问题。
建议学习目标:
- 建立 MCU、存储器、外设、传感器、通信模块之间的系统视角。
- 理解从上电、启动到应用运行的基本链路。
- 能读懂基础链接脚本、启动文件和芯片数据手册中的关键字段。
- 对后续驱动开发、RTOS 和 Embedded Linux 学习形成背景认知。
阅读建议:先看系统构成与架构,再看启动流程、工具链和数据手册阅读方法。
嵌入式系统概览
嵌入式系统定义与特点
嵌入式系统是为特定任务设计的专用计算系统,通常集成在设备内部,直接服务于控制、采集、通信、显示或执行等功能。
典型特征:
- 专用性强:面向单一或有限场景优化,而不是做通用计算。
- 资源受限:CPU 主频、内存、存储空间和功耗通常受到严格限制。
- 强调实时性:很多系统要求在确定时间内完成响应。
- 高可靠性:工业、汽车、医疗等场景对稳定性要求极高。
- 软硬件耦合紧密:代码常直接与寄存器、外设和总线交互。
嵌入式系统并不总是“小而简单”。从 8 位 MCU 到运行 Linux 的多核 SoC,都属于嵌入式系统范畴,只是复杂度和工程方法不同。
系统构成(MCU、存储器、传感器、外设)
一个典型嵌入式系统通常由以下模块组成:
| 模块 | 作用 |
|---|---|
| MCU / MPU / SoC | 运算、控制和调度核心 |
| Flash / EEPROM / NAND / NOR | 程序和持久化数据存储 |
| SRAM / DDR | 运行时数据和缓冲区 |
| GPIO / UART / SPI / I2C / ADC / PWM | 与外部设备交互 |
| 传感器 | 采集环境、姿态、位置、电流等数据 |
| 通信模块 | Wi-Fi、BLE、LoRa、CAN、以太网、4G/5G 等 |
| 电源管理 | 稳压、充电、低功耗切换和电池管理 |
可以把它理解为三层结构:
- 计算与控制核心
- 数据采集与通信接口
- 电源与系统支撑部分
MCU(微控制器):嵌入式系统的心脏
MCU 负责执行程序、处理中断、访问外设和调度系统行为。
常见架构:
- ARM Cortex-M:当前 MCU 主流,常见于 STM32、GD32、nRF、NXP 等系列。
- RISC-V:开源指令集,近年来快速增长。
- AVR / 8051:传统 8 位 MCU,适合低成本或教学场景。
选择 MCU 时常看的参数:
- 主频和内核类型
- Flash / SRAM 容量
- 外设数量和种类
- 功耗水平
- 封装、成本和供货情况
- 工具链和社区支持
对于初学者,最重要的不是记住某个型号,而是理解:MCU 的差异主要体现在“算力、存储、外设和功耗”四个维度。
存储器:程序与数据的载体
嵌入式系统中常见的存储器包括以下几类:
1. Flash
- 通常用于存放程序代码和常量数据
- 掉电不丢失
- 可分为片内 Flash 和外部 Flash
2. SRAM
- 用于运行时变量、栈、堆和缓冲区
- 速度快,但容量通常有限
- 掉电后数据丢失
3. EEPROM / FRAM
- 适合存放参数、校准值、设备 ID 等少量关键数据
- 擦写寿命通常比 Flash 更适合做参数存储
4. 外部存储
- NAND Flash、eMMC、SD 卡等,适合较大容量场景
- 常见于 Embedded Linux 或带文件系统的设备
工程上要重点理解三件事:
- 程序通常放在哪
- 变量和栈通常放在哪
- 参数和日志适合放在哪
外设接口:与外部世界的桥梁
外设接口决定了 MCU 如何连接传感器、执行器和其他芯片。
常见接口:
| 接口 | 特点 | 典型用途 |
|---|---|---|
| GPIO | 最基础的数字输入输出 | 按键、LED、中断输入 |
| UART / USART | 点对点异步串口 | 调试输出、模块通信 |
| SPI | 全双工、速度快 | 显示屏、Flash、高速传感器 |
| I2C | 两线总线、便于挂多个设备 | 温湿度、IMU、RTC |
| ADC | 模拟量采样 | 电压、电流、传感器输出 |
| PWM | 占空比控制 | 电机、蜂鸣器、LED 调光 |
| CAN / RS-485 / Ethernet | 工业与网络通信 | 车载、工控、联网设备 |
学习外设时建议始终带着这几个问题:
- 时钟从哪里来
- 引脚如何复用
- 数据如何收发
- 中断或 DMA 怎样配合
- 出错时如何定位
传感器:感知物理世界的窗口
传感器把外部物理量转换成可处理的电信号或数字数据。
常见类型:
- 环境类:温湿度、气压、光照、空气质量
- 运动类:加速度计、陀螺仪、磁力计
- 电气类:电压、电流、功率、霍尔传感器
- 人机类:触摸、红外、人体存在检测
接入方式一般分为两类:
- 数字接口:I2C、SPI、UART
- 模拟接口:通过 ADC 采样
工程重点不只是“接上能读”,还包括:
- 供电与噪声
- 采样频率
- 校准
- 滤波和异常值处理
通信模块:连接万物的纽带
通信模块决定设备如何与外部系统交换数据。
按距离和用途可粗略分为:
- 短距离:UART、SPI、I2C、USB
- 局域无线:Wi-Fi、BLE
- 广域低功耗:LoRa、NB-IoT
- 工业网络:CAN、RS-485、Modbus
- 高带宽网络:以太网、4G/5G
选择通信方式时主要看:
- 数据量大小
- 实时性要求
- 传输距离
- 功耗预算
- 成本和部署环境
电源管理:续航与稳定性的保障
电源管理不仅关系到续航,还直接影响系统稳定性。
典型关注点:
- 电源输入范围
- 稳压方式:LDO 还是 DC-DC
- 峰值电流和压降
- 唤醒源和低功耗模式
- 充电管理和电池保护
很多“软件问题”本质上是电源问题,例如:
- 上电不稳定
- 通信时随机复位
- 电机启动导致掉电
- 休眠功耗异常
系统集成与典型架构
一个常见嵌入式系统通常可抽象为三层:
应用层 -> 业务逻辑、状态机、控制策略
驱动层 -> 外设访问、协议封装、中断处理
硬件层 -> MCU、存储器、传感器、执行器、电源在复杂项目中,还会加入:
- BSP(板级支持包)
- 中间件(文件系统、网络协议栈、GUI、RTOS)
- 生产诊断和升级机制
开发与调试工具
常见工具可以分为四类:
- 开发环境:Keil、STM32CubeIDE、VS Code、CLion
- 配置工具:STM32CubeMX、PinMux、设备树工具
- 下载调试:ST-Link、J-Link、OpenOCD、GDB
- 硬件测量:逻辑分析仪、示波器、电流表
学习时不要把工具当成知识本身,而要关注它们分别解决什么问题。
架构与启动流程
Cortex-M 内核结构
Cortex-M 是最常见的 MCU 内核系列之一。理解其核心结构有助于理解中断、异常和启动流程。
关键组成:
- 通用寄存器:R0-R12
- 栈指针:MSP / PSP
- 链接寄存器:LR
- 程序计数器:PC
- 程序状态寄存器:xPSR
- NVIC:中断控制器
- SysTick:系统节拍定时器
对应用开发最重要的是:
- 中断进入时栈如何保存现场
- 异常向量如何跳转
- 主栈和进程栈的差异
启动文件 Startup.s
启动文件通常由汇编编写,负责完成上电后的最早期初始化。
典型职责:
- 设置初始栈顶
- 定义中断向量表
- 调用系统初始化函数
- 清零
.bss - 拷贝
.data - 最终跳转到
main
示例:
Reset_Handler:
LDR R0, =_estack
MOV SP, R0
BL SystemInit
BL main启动流程简要
一个 MCU 上电后的典型启动顺序如下:
- 上电或复位
- CPU 从固定启动地址取指
- 读取向量表中的栈顶与复位入口
- 执行
Reset_Handler - 初始化内存段和系统时钟
- 调用
main
如果没有理解这条链路,后续学习 Bootloader、RAM 启动、中断重定向时会很吃力。
编译器与链接器
常用嵌入式工具链
嵌入式开发常用的是交叉编译工具链,即“在 PC 上编译,给目标芯片运行”。
常见工具链:
arm-none-eabi-gcc- Keil ARM Compiler
- IAR EWARM
- RISC-V GCC Toolchain
工具链通常包含:
- 编译器
- 汇编器
- 链接器
- 头文件和运行时库
- 调试工具
链接脚本(ld)示例
链接脚本用于告诉链接器:程序的代码段、数据段、栈和堆应放到哪段存储器里。
典型片段:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}它直接决定了:
- 程序是否能放进 Flash
.data/.bss是否落在正确 RAM- 栈和堆是否有足够空间
存储器布局图(STM32 示例)
一个常见 STM32 工程中的布局可以粗略理解为:
Flash:
[向量表][代码段 .text][只读数据 .rodata]
RAM:
[.data][.bss][heap][stack]开发时经常遇到的错误:
- Flash 溢出
- RAM 溢出
- 栈过小导致 HardFault
- 链接地址与实际启动地址不匹配
芯片数据手册阅读方法
典型结构(以 STM32 为例)
一套完整芯片资料通常包括:
- Datasheet:电气参数、封装、引脚定义、工作范围
- Reference Manual:寄存器、外设详细说明
- Programming Manual:内核和编程模型
- Errata:已知问题
- Application Note:应用建议
阅读技巧
建议按问题来读,而不是从头到尾顺序翻。
例如:
- 查引脚复用:看 Datasheet 的 Pinout / Alternate Function 表
- 查 UART 如何初始化:看 Reference Manual 的 USART 章节
- 查中断号:看向量表或 NVIC 对应章节
- 查低功耗模式:看电源管理与功耗章节
高效阅读习惯:
- 先定位章节结构
- 再查寄存器位定义
- 最后对照库函数或初始化代码验证
向量表的定义与重定向
什么是向量表
向量表本质上是一个函数地址表。它记录了复位处理函数和各类异常、中断服务函数的入口地址。
在 Cortex-M 中,向量表开头通常包括:
- 初始栈顶地址
- Reset_Handler
- NMI_Handler
- HardFault_Handler
- 各种外设中断入口
重定向方法(常用于 Bootloader 或自定义中断)
当使用 Bootloader 或多应用布局时,应用程序的向量表往往不在默认地址,需要通过 SCB->VTOR 重定向。
示例:
SCB->VTOR = 0x08010000;常见场景:
- Bootloader 跳转到 App
- 多固件分区
- RAM 启动调试
ROM 启动 vs RAM 启动的差异
ROM 启动(Flash 启动)
这是量产环境下最常见的启动方式。
特点:
- 程序固化在 Flash 中
- 上电即可执行
- 可靠性高
- 适合正式发布版本
RAM 启动
RAM 启动常用于调试、下载器或特定快速加载场景。
特点:
- 程序先被加载到 RAM
- 执行速度可能更高
- 断电即丢失
- 常用于调试或特定自举流程
使用差异
| 项目 | ROM 启动 | RAM 启动 |
|---|---|---|
| 存放位置 | Flash | RAM |
| 掉电保留 | 是 | 否 |
| 常见用途 | 正式固件 | 调试、Bootloader、特殊加载 |
| 向量表位置 | 默认在 Flash | 常需手动重定向 |
链接脚本示例:
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx): ORIGIN = 0x20000000, LENGTH = 64K本章小结
这一章的重点不是背概念,而是建立“系统是如何被组织起来的”这条主线。只要把系统构成、启动流程、向量表、链接脚本和工具链之间的关系理清,后续做驱动、RTOS 和 Bootloader 时会更顺畅。
