嵌入式通识
作者不保证文档内容的准确性与真实性,请仔细甄别。本文章基于Bilibili-万能工科生炭烤鱼-《单片机学习缺失的第一课!适合小白的嵌入式通识》总结改编。
一、什么是嵌入式系统?
1. 定义是什么?
2. 与我们常见的计算机系统有什么区别?
“嵌入”的意思就是将软件“写入”到硬件设备中,使其在特定的功能需求下稳定运行。
与普通电脑不同,嵌入式设备中的软件通常不能轻易更改。比如微波炉、洗衣机的按钮或汽车的中控系统,它们的功能在设计时就已固定,用户无法随意修改。嵌入式系统通常是专为特定用途设计的,因此修改的需求很少,同时考虑到成本和可靠性等因素,保持固定的软件设计往往是最优选择。
| 特征 | 通用计算机 | 嵌入式系统 |
|---|---|---|
| 外观和类型 | 可以直接看到,比如台式机、笔记本。按性能分为大型机、中型机、小型机和微机。 | 隐藏在设备内部,如家电、汽车系统等,应用范围广,外观各不相同。 |
| 组成 | 使用通用处理器,配有标准的连接接口和外部设备,软件和硬件分开工作。 | 专为特定用途设计,处理器内部集成多种功能,软件与硬件紧密结合。 |
| 开发方式 | 开发和运行都在普通电脑上进行。 | 在普通电脑上开发,但运行在嵌入式设备上。 |
| 功能修改 | 可以随时安装或修改应用程序。 | 一般不能修改或重新编程。 |
二、初步了解嵌入式系统
1. 嵌入式系统的分类(按性能分类)
-
初级嵌入式系统 **代表平台:**MCS51系列 8位MCU **常用芯片:**8051 特点:
- 资源有限,通常无操作系统或使用简单的调度算法。
- 适用于基础控制应用,如温度控制、家电控制等。
- 编程语言主要为C语言或汇编语言。 **示例:**51单片机
-
中级嵌入式系统 **代表平台:**ARM7 / Cortex-M3 / Cortex-M4 系列 32位MCU **常用芯片:**STM32系列 特点:
- 具有较强的处理能力,支持定时、多任务调度等功能。
- 通常配合轻量级实时操作系统(RTOS)如 FreeRTOS。
- 适用于工业自动化、智能家居、医疗设备等。 **示例:**STM32微控制器
-
高级嵌入式系统 代表平台:Cortex-A8 / Cortex-A15 32/64位处理器 **常用芯片:**Raspberry Pi 特点:
- 运行复杂的操作系统,如 Linux、Android。
- 具备丰富的外设接口,适合多任务、多媒体处理等应用。
- 适用于智能终端、机器人、边缘计算等高端应用。 **示例:**树莓派开发版
2. 嵌入式处理器的分类(按功能分类)
-
**微控制器(MCU):**集成了CPU、内存、外设等功能,通常用于控制任务,适合低成本、低功耗应用
-
**微处理器(MPU):**主要包含CPU,适合需要高处理能力的应用,通常需要外接内存和外设
-
**数字信号处理器(DSP):**专门用于高速、实时的信号处理任务,常见于音频、视频等领域
-
**系统级芯片(SoC):**处理器、存储、I/O接口、GPU等的高度集成,适用于智能设备、移动终端等领域
3. 嵌入式系统的组成
| 组成部分 | |
|---|---|
| 微处理器 | 中心处理单元,负责执行任务和控制系统 |
| 输入通道 | 用于接收外部输入信号,例如传感器、按钮等 |
| 输出通道 | 用于输出控制信号,例如驱动马达、显示器等 |
| 存储器 | 存储程序和数据,例如闪存、RAM等 |
| 通信接口 | 用于与其他设备或系统进行数据交换,如USB、I2C、SPI等 |
| 人机接口 | 用户与系统交互的界面,例如显示屏、按钮、触摸屏等 |
| 操作系统(可选) | 管理硬件资源并为应用提供服务的系统 |
| 应用软件 | 实现特定功能的程序,如控制算法、数据处理等 |
特点:
**一切围绕嵌入式处理器。**它相当于集成了计算机系统当中的运算器、控制器、存储器。
三、初步了解嵌入式系统是如何运作的?
1. 芯片里的核心
**“核心(Core)”包含于芯片,是芯片的重要组成部分。**芯片内部还有内存、总线等。
- 芯片核心的构造——冯·诺依曼结构

1.1 安排事件处理顺序 —— 核心的重要任务 1
在嵌入式系统中,任务按处理方式可划分为周期性任务(常规任务)和非周期性任务(突发事件)。
在嵌入式系统中,任务通常可以按执行方式分为周期性任务(常规任务)和非周期性任务(突发事件)。
两者的本质区别在于它们的执行频率、触发机制以及对系统资源的影响。
-
周期性任务
- 定义: 周期性任务是指按照固定的时间间隔或特定条件,定期执行的任务,通常与系统的日常维护或监控相关
- 示例: 传感器数据采集、LCD显示刷新
- 特点**:**
- 执行频率:以固定时间间隔或条件触发,定期执行
- 时间可预测:任务的开始时间和持续时间通常是已知的
- 优先级较低:可以在资源允许的情况下安排执行,通常不会影响系统的关键功能
- 实现方式:轮询、定时器触发
-
非周期性任务
- 定义: 非周期性任务是指随机发生、无法提前预测的任务,通常与外部事件或内部故障相关,需要系统实时响应,并优先处理
- 示例: 用户按下设备按键、串口收到外部数据需要立即处理
- 特点:
- 不可预测性:事件发生的时间和频率不固定
- 实时性要求高:需要系统快速响应,确保正确处
- 优先级较高:突发事件通常需要打断当前任务来处理
- 实现方式:硬件或软件中断、事件触发
在嵌入式系统中,任务不仅需要根据紧急程度进行调度,还应根据任务的来源、优先级以及资源的分配情况进行综合安排。对于突发事件,系统通常会采用中断机制来处理。
“突发情况”的优先级处理逻辑:
什么是“突发情况”? 想象一下,你正在专心做作业。突然,发生了需要你立刻处理的事情,比如有人敲门。这就是一个“突发情况”,在单片机里我们叫它中断。 中断发生了,怎么办?—— NVIC:处理中断的“管家” 在STM32单片机里,有一个叫做 NVIC(嵌套向量中断控制器)的“管家”,专门负责处理这些突发情况。它就像一个指挥中心,告诉单片机:
- 发生了什么事?(有人敲门)
- 该怎么处理?(去开门)
你(单片机CPU)在写作业(执行正常程序);
过了一会有人敲门(外部中断),NVIC告诉你:“有人敲门!去执行开门的程序!”;
你接受了指令,去执行开门的程序(中断处理程序);
这个过程就是中断的基本处理逻辑:发生突发情况,停止当前任务,处理突发情况,然后回到原先的任务。
找到程序才能执行,“开门“程序在哪个位置?—— 中断向量表 NVIC里有一本“中断向量表”,就像一个地址簿,记录了每种突发情况的处理程序在哪里。当敲门(外部中断)发生时,NVIC就会查找这本“地址簿”,找到“开门”程序的地址,然后单片机就会跳过(正在做的事情)去执行这个程序。 正在处理一个中断,此时另一个中断发生了,怎么办?—— 中断嵌套
你(单片机CPU)在写作业(执行正常程序);
过了一会有人敲门(外部中断),NVIC告诉你:“有人敲门!去执行开门的程序!”;
你接受了指令,去执行开门的程序(中断处理程序);
【中断处理】
你正在开门,电话突然响了(另一个中断);
你放下开门的动作去接电话,发现是骚扰电话;
你挂掉电话,继续开门。
这个过程就是中断嵌套:一个中断发生时,可以被另一个更紧急的中断打断。
怎么知道哪个任务更重要?—— 中断优先级
你(单片机CPU)在写作业(执行正常程序);
过了一会有人敲门(外部中断),NVIC告诉你:“有人敲门!去执行开门的程序!”;
你接受了指令,去执行开门的程序(中断处理程序);
【中断处理】
你正在开门,电话突然响了(另一个中断);
你放下开门的动作去接电话,发现是骚扰电话;
你挂掉电话,继续开门;
【中断嵌套】
在你开门的时候,突然番茄钟响了,提醒你该休息了;
但是NVIC告诉你开门更重要,所以你先开门,再休息。
这个过程就是中断优先级:更紧急的,优先级更高,优先处理。
-
NVIC是如何自动判断优先级的?
在STM32等嵌入式系统中,中断优先级是由两个主要部分构成的:注意**“自动”**不等于”智能“
-
抢占优先级: 决定是否能够打断当前正在执行的任务:优先级数值越小,抢占优先级越高,抢占优先级高的中断会打断抢占优先级低的中断或任务。 开发者可以通过
NVIC_SetPriority()手动设置每个中断的抢占优先级。 如果没有手动配置优先级,STM32在启动时会给所有中断分配相同的默认优先级,通常是最低优先级。但这不是“相同优先级”的意思,而是指系统默认配置给所有中断相同的优先级,具体数值可能会有所不同。 -
子优先级: 决定在抢占优先级相同的情况下,哪个中断先执行:抢占优先级相同的中断会根据子优先级决定执行顺序,优先级数值越小,子优先级越高。 如果没有手动配置优先级,STM32会按硬件中断号(IRQ)从小到大的顺序执行中断;但是在手动配置优先级后,执行顺序由已配置的抢占优先级和子优先级决定。
提示硬件中断号的特点
- 预先定义且固定
- 每个 STM32 芯片的外设(如定时器、串口、GPIO 等)都有一个固定的硬件中断号,这些编号在芯片设计时就已经决定,用户无法更改
- 唯一性
- 每个中断源都有一个唯一的中断号,确保 NVIC 可以准确识别并执行相应的中断服务程序(ISR)
- 存储在芯片的中断向量表中
- STM32在启动时,会从中断向量表中读取各个中断号对应的服务程序入口地址

你可以在头文件里找到这些中断号
总的来说,STM32的中断(或中断嵌套)执行规律是:
- 先执行已配置的(抢占优先级或子优先级),再执行未配置的(抢占优先级或子优先级);
- 先执行编号较小【优先级高】的(抢占优先级或子优先级),再执行编号较大【优先级低】的(抢占优先级或子优先级);
- (抢占优先级或子优先级)相同的,先执行中断号较小的,再执行中断号较大的;
提示假设你有以下配置:
-
EXTI0(外部中断):抢占优先级 0,子优先级 1,IRQ号 6
-
USART1(串口中断):抢占优先级 0,子优先级 0,IRQ号 37
-
USART2(串口中断):抢占优先级 1,子优先级 0,IRQ号 29
-
USART3(串口中断):抢占优先级 1,子优先级 0,IRQ号 27
-
TIM2(定时器中断):抢占优先级 1,未配置子优先级,IRQ号 28
-
第一步: 执行所有抢占优先级 0 的中断,按子优先级排序:
- 先执行 USART1(子优先级 0)
- 后执行 EXTI0(子优先级 1)
-
第二步: 执行抢占优先级 1 的中断:
- 先执行已配置子优先级的中断:
- 先执行 USART3(IRQ号 27)
- 后执行 USART2(IRQ号 29)
- 后执行未配置子优先级的中断:
- 执行 TIM2
- 先执行已配置子优先级的中断:
-
处理完了中断,之后该干什么?—— 末尾连锁机制
打开门,发现是来查煤气表的。
你送走了查煤气表的师傅,邻居又来送鸡蛋。
STM32的末尾连锁机制会等你彻底处理完送鸡蛋的事情,再回到你的作业处。保证了中断处理的完整性。
相较而言,C51不存在像 STM32 那样的“末尾连锁机制”。 因此,C51则会回到写作业的地方,再去看门口是否有人送鸡蛋,处理完再回去写作业。这可能导致送鸡蛋的人(突发事件)等待时间变长。
总结: 当发生突发事件(中断)时,NVIC负责:
- 分配中断优先级:决定哪个中断应该先执行。
- 中断嵌套管理:如果在处理一个中断时,另一个更紧急的中断发生,NVIC会决定是否暂停当前中断,转去处理更重要的。
- 中断向量表跳转:找到正确的中断处理程序。
“常规任务“的优先级处理逻辑:
什么是“常规任务”? 在嵌入式系统中,CPU的执行模式通常分为线程模式和中断模式。当CPU执行常规应用程序时,它运行在线程模式下。线程模式下的程序通常是用户代码,例如刷新LCD屏幕显示内容。 常规任务也分轻重缓急,怎么处理? 如果安装了操作系统,在线程模式下,任务的优先级通常是由实时操作系统(RTOS)来管理,而不是直接由硬件(如NVIC)决定。RTOS通过任务调度算法(如抢占式调度)来控制多个任务的执行顺序,确保重要任务得到及时执行。 如果没安装RTOS,STM32仍然可以使用一些手段来管理和调度任务,但这些方法通常比RTOS提供的调度机制简单。以下是一些常见的管理方式:
- 简单的任务轮询 如果系统任务较少且不需要实时任务调度,可以使用轮询方式在主循环中依次执行任务。虽然这种方式没有优先级的概念,但开发者可以通过分配任务的执行顺序来间接安排它们的优先级。
int main() {
while (1) {
task1(); // 执行任务1
task2(); // 执行任务2
task3(); // 执行任务3
}
}
- 使用定时器和软件定时器 STM32可以利用硬件定时器来模拟某些任务的优先级。例如,使用一个定时器每秒触发一次任务,而另一个定时器每5秒触发一次任务。通过调节定时器的触发频率,间接控制任务的执行频率。
void TIM1_IRQHandler(void) {
if (TIM1->SR & TIM_SR_UIF) { // 检查定时器溢出标志
TIM1->SR &= ~TIM_SR_UIF; // 清除溢出标志
task1(); // 每次定时器溢出时执行task1
}
}
void task1() {
// 定时任务1
}
- 使用中断和标志位 开发者可以结合中断处理程序与标志位来控制任务的优先级。比如,系统中某些任务会在中断中执行,而其他任务则依赖于主循环中定期检查标志位。这种方式可以实现任务的间接优先级。
假设你在写作业(相当于你的主要任务)。同时,你家有一个门铃,如果有访客按门铃(中断),你需要暂时停下做作业去开门(执行中断任务)。但是,你不想每一秒都去检查门铃是不是响了,而是希望只在有人按门铃时才去开门。
如何做到这一点?
-
中断(门铃按下):当有人按下门铃时,它发出声音,通知你有访客来访,这就像中断信号。当门铃响时,它会打断你做作业的任务。
-
标志位(门铃响了的标记):当门铃响了,你并不马上去开门,而是把门铃的“响铃状态”记录下来。你可以在做作业时,只是偶尔查看门铃的“响铃状态”。一旦标志位显示门铃响了,你就会去开门(执行中断任务)。
-
开完门后,你再把这个标志位重新设置为“0”,表示“门铃没有响”,然后继续做作业。
代码示例
volatile int doorbell_flag = 0; // 声明一个标志位,表示门铃是否响了
void EXTI0_IRQHandler(void) {
// 中断服务程序:当门铃被按下时,这个函数会被调用
doorbell_flag = 1; // 设置标志位为1,表示门铃响了
}
int main() {
while(1) {
if (doorbell_flag) { // 如果门铃响了(标志位为1)
open_door(); // 去开门
doorbell_flag = 0; // 重置标志位,表示已经处理完门铃事件
}
do_homework(); // 继续做作业
}
}
与上面提到的中断有什么区别? 中断优先级是由硬件控制的,通常通过NVIC来管理。中断优先级决定了系统在多个中断请求发生时,哪个中断应该先被处理。 中断优先级在嵌入式系统中是硬件级别的管理,而线程优先级则是软件级别的调度。硬件中断的执行速度更快,且优先级比软件层面高,会尽早抢占系统资源进行处理。
系统在处理任务时需要管理内存访问,以保证任务间的隔离和稳定。内存保护单元(MPU)作为一种硬件机制,通过控制任务的内存访问权限,防止冲突并提高系统安全性。
MPU是怎么控制权限的?
内存区域划分 MPU允许将物理内存划分为多个区域(通常是按一定大小的块,如1KB、4KB等)。每个区域可以单独配置访问权限,并且每个区域的权限是独立的,可以按任务、用户或内核级别进行设置。 权限配置方式 MPU允许为每个内存区域单独配置不同的权限,通常可以设置如下几种模式:
- 特权模式:**程序可以访问所有内存范围并执行所有指令。**操作系统内核或某些特权任务通常运行在该模式下,有能力配置和管理其他任务的内存权限。
- 用户模式:**任务只能访问其被授权的内存区域,无法访问操作系统或其他任务的内存区域。**这种权限配置常用于保护用户程序和操作系统内核的隔离。
- 执行/非执行权限:有些内存区域可能被设置为只能执行代码(例如代码段),而不能读写,这可以防止代码被非法修改。通常,数据区域被设置为不可执行,而代码区域被设置为可执行。
程序尝试访问不允许访问的内存区域,会发生什么? MPU会触发一个硬件异常,通常是一个中断,操作系统可以通过这个异常来进行错误处理。例如,任务试图写入只读区域时,MPU会立即停止该操作并通知系统。
1.2 从指令到执行 —— 核心的重要任务 2
我写的C语言程序,是如何被转换成指令的?
我们在编程时使用的C语言本质上是对汇编语言的"封装",目的是减少代码量,让编程逻辑更符合人类思维方式。然而,单片机无法直接理解C语言,它需要经历以下转换过程:
编译器
将C语言代码转换为对应架构的汇编语言。例如,
a = b + c;
会被编译成类似以下汇编指令:
LDR R0, [b] ; 将变量b的值加载到寄存器R0
LDR R1, [c] ; 将变量c的值加载到寄存器R1
ADD R2, R0, R1 ; R2 = R0 + R1
STR R2, [a] ; 将R2的值存储到变量a
汇编器
将汇编语言转换为机器指令(二进制码)。例如上面的ADD R2, R0, R1可能会被翻译为0xE0802001(Thumb-2指令的具体编码)。
指令集是CPU能理解和执行的所有指令的集合,就像一本字典。用于帮助汇编器将汇编语言转换为机器指令。不同架构的CPU支持不同的指令集:
-
x86:PC和服务器常用(如Intel、AMD)。
-
ARM:移动设备和嵌入式系统主流架构。
-
Thumb-2:ARM的精简指令集(Cortex-M系列专用),兼顾代码密度和执行效率。
链接器
将多个编译后的目标文件合并,分配内存地址,最终生成单片机能直接执行的二进制文件(.hex或.bin)。
1.3 **实时响应与外设协作 —— 核心的重要任务 3
为什么嵌入式系统要强调“实时性”?
嵌入式系统往往需要在严格的时间限制内响应事件。例如:
-
汽车安全气囊必须在碰撞后10ms内弹出
-
呼吸机的压力传感器数据必须每5ms处理一次
-
无人机陀螺仪数据需要实时更新以保持平衡
若响应超时,轻则功能异常,重则引发安全事故。
实时性的两大核心保障
硬件级快速响应 —— 中断与DMA
-
中断机制 立即暂停当前任务,优先处理紧急事件。
-
直接内存访问(DMA)
DMA(Direct Memory Access,直接内存访问)是一种硬件技术,允许外设(如传感器、存储设备等)与内存之间直接传输数据,无需CPU全程参与。 传统数据传输需要CPU逐字节处理数据,而DMA接管了这一传输任务,使CPU能并行执行其他计算任务。例如,当摄像头采集图像时,DMA直接将数据存入内存,CPU此时可以处理图像识别算法。这样,DMA不仅解放了CPU资源,还提升了系统运行效率并降低了功耗。
DMA的工作流程可分为四个阶段,类似快递员送货的过程:
-
请求阶段(快递员接到订单) 外设或软件触发DMA请求。例如,当UART接收缓冲区满时,硬件自动发送请求信号给DMA控制器。
-
接管总线(快递员拿到车钥匙) DMA控制器向CPU申请总线控制权。CPU暂停当前操作(仅需几个时钟周期),将总线控制权交给DMA控制器。
-
数据传输(快递员运输货物) DMA控制器根据预设的源地址(如外设寄存器)、目标地址(如内存区域)和传输长度,直接操作总线完成数据搬运。
-
释放总线(快递员归还车钥匙) 传输完成后,DMA控制器通知CPU并交还总线控制权。CPU继续执行原有任务,同时可收到完成中断以处理数据。
软件级时间管理 —— 实时操作系统(点击跳转)
2. 核心**之外,芯片之内 —— 片上资源
片上资源是什么?具体有哪些?
片上资源,也称片上外设,是集成在微控制器(MCU)或处理器芯片内部的专用硬件模块,用于扩展核心处理器的功能。这些资源能独立执行硬件级操作(如数据采集、信号生成和协议通信),从而减轻CPU的负担。同时,它们也能与CPU协同工作,触发事件通知内核,共同完成复杂任务,构成完整的嵌入式系统。
-
RCC-复位和时钟控制:对系统的时钟进行配置,使能各模块的时钟(其他外设在上电时默认没有时钟,不给时钟时操作外设将无效,外设不会工作,这样做是为了降低功耗。因此,在操作外设之前,必须先使能它的时钟,这一过程通过RCC完成)。
-
GPIO—通用IO口:可用于点灯、读取按键等(最基本的功能)。
-
AFIO-复用IO口:完成复用功能端口的重定义,还有中断端口的配置。
-
EXTI-外部中断:配置好外部中断后,当引脚检测到电平变化时,会立即触发中断,使CPU暂停当前任务来处理指定的中断服务程序。
-
ADC-模数转换器:STM32配置了12位的AD转换器,可以直接读取IO口的模拟电压值,无需外部连接AD芯片。
-
DMA—直接内存访问:可帮助CPU完成搬运大量数据这样的繁杂任务。
-
USART—同步/异步串口通信:平时用的UART是异步串口的意思;此处USART既支持异步串口,也支持同步串口。
-
I2C—I2C通信:常用的通信协议。STM32中配置了它们的控制器,可以用硬件来输出时序波形,使用起来高效(也可以用通用IO口来模拟时序波形)
-
SPI-SPI通信:同样常用的通信协议。
-
CAN-CAN通信:通信协议,一般用于汽车领域和工业控制领域。
-
USB—USB通信:通信协议,可做模拟鼠标、模拟U盘等设备。
-
RTC-实时时钟:在STM32内部完成年月日、时分秒的计时功能,可接外部备用电池,计时掉电也能正常运行。
-
CRC—CRC校验:一种数据的校验方式,用于判断数据的正确性。
-
PWR-电源控制:可以让芯片进入睡眠模式等状态,达到省电的目的。
-
BKP-备份寄存器:存储器,当系统掉电时仍可由备用电池保持数据(这个根据需要可以完成一些特殊功能)。
-
IWDG-独立看门狗:当单片机因为电磁干扰死机或者程序设计不合理出现死循环时,看门狗可以及时复位芯片,保证系统稳定性。
-
WWDG-窗口看门狗:同上。
-
DAC-数模转换器:可以在IO口直接输出模拟电压,是ADC模数转换的逆过程。
-
SDIO-SD卡接口:可以用来读取SD卡。
-
FSMC-可变静态存储控制器:可以用于扩展内存,或配制成其他总线协议,用于某些硬件的操作。
-
USB OTG-USB主机接口:可以让STM32作为USB主机去读取其他USB设备。