Embedded Processors / Exam revision

EP Exam

从 Notion 长笔记整理出的网页复习版。重点内容被分组为速记表、概念对比、代码模板和考试答题框架。

整理时间:2026-06-22 · 查看 Notion 原页
没有匹配的章节,请换一个关键词。

01 · 考前速记

变量读入ADR + LDR:先找地址,再从内存读进寄存器。
结果写回ADR + STR:先找变量地址,再把寄存器写回内存。
函数调用BL FUNCTION 调用,BX LR 返回。
SPI 读取发送读命令后持续写 dummy byte,才能产生时钟并读回数据。
I2C 读取先写 register pointer,再 repeated start 读取数据。
外部中断ISR 只设置 volatile flag,复杂任务放回 main loop。
核心记忆:低级语言更快、更靠近硬件、能直接控制寄存器和内存;高级语言更容易编写、阅读、调试和维护。

02 · ARM 汇编

指令含义快速理解
LDRLoad Register从内存读取到寄存器
STRStore Register把寄存器数据写入内存
ADRAddress把变量或标签地址放进寄存器
AND按位与两个 bit 都为 1 才为 1
ORR按位或有一个 bit 为 1 就为 1
EOR按位异或不同为 1,相同为 0
BICBit ClearRn AND NOT Operand2,用 1 清除对应 bit
MVNMove Not按位取反后写入目标寄存器
LSL / LSR逻辑左移 / 右移按指定 bit 数移动
CMPCompare执行减法但不保存结果,只更新 N/Z/C/V
B / BLBranch / Branch Link跳转 / 保存返回地址后调用函数

条件判断:C 转汇编

// C
if (i == j)
    f = g + h;
f = f - i;

; ARM
CMP R3, R4
BNE L1
ADD R0, R1, R2
L1:
SUB R0, R0, R3

; 使用条件执行的版本
CMP R3, R4
ADDEQ R0, R1, R2
SUB R0, R0, R3

函数调用

BL FUNCTION       ; LR 保存返回地址
ADD R0, R1, R2    ; 函数返回后继续

FUNCTION:
    SUB R0, R0, R1
    BX LR          ; 返回调用点

循环题:找 1 到 9 中的 4 的倍数

unsigned R0 = 0;
unsigned R1 = 1;
unsigned R2 = 10;
unsigned R3 = 3;   // 二进制 0011,用作 mask
unsigned R4 = 1;
unsigned R5 = 0;
unsigned R6;

while (R1 != R2) {
    R6 = R1 & R3;
    if (R6 == R5) {
        R0 = R0 + R1;
    }
    R1 = R1 + R4;
}
最终结果:R0 = 12,因为 4 + 8 = 12;循环结束时 R1 = 10

03 · 数据流图

Data Flow Graph 不表达普通程序流程,而是表达数据依赖:数据从哪里进入、经过哪些运算、最后形成什么结果。

a + t1 × z
口诀:变量进圆圈,结果出圆圈;圆圈是运算,箭头是依赖;谁先算出来,谁才能往下走。

04 · 嵌入式系统基础

开发生命周期

  1. Requirement analysis:明确精度、采样周期、通信、功耗和成本约束。
  2. System design:选择 MCU、传感器、无线模块和接口。
  3. Prototyping:搭建硬件原型并编写 firmware。
  4. Testing and verification:验证精度、时序、可靠性和通信。
  5. Deployment and maintenance:部署到现场,持续更新和修复。
  6. Feedback and iteration:根据实际使用继续改进。

Embedded firmware

Firmware 是存储在嵌入式系统程序存储器中的内置控制软件,包含控制算法和配置设置,用于启动硬件、控制外设并响应输入。

英文答题句:Embedded firmware is the built-in control software stored in the memory of an embedded system. It provides the instructions and configuration required to control hardware, peripherals and inputs.

05 · 质量属性

Operational Quality Attributes

英文中文记忆
Response time响应时间快不快
Throughput吞吐量单位时间处理得多不多
Reliability可靠性稳不稳定
Maintainability可维护性好不好修
Security信息安全会不会被攻击
Safety功能安全会不会伤人或造成危险

Non-operational Quality Attributes

英文中文记忆
Testability / Debuggability可测试 / 可调试性好不好测和 debug
Scalability可扩展性以后能不能增加功能
Time to market上市时间能不能快速做出来
Portability可移植性能否迁移到其他平台
Per-unit cost and revenue单位成本和收益成本和盈利能力

06 · 调度与 RTOS

方式优点缺点
Super loop无需 OS、结构简单、内存占用低实时性不稳定;一个任务阻塞会影响整个系统
Embedded OS / RTOS多任务、优先级、可预测时序、扩展性强需要更多内存和处理器资源,设计复杂

Scheduler 决定下一个获得 CPU 的任务;dispatcher 实际完成上下文切换并把处理器控制权交给该任务。

刹车任务题:如果低优先级或非抢占任务阻塞了紧急刹车,应该使用 preemptive priority scheduling / preemptive HPF,把 braking task 设置为最高优先级,并保证响应时间满足 1 秒要求。

07 · 处理器与存储

RISC 与 CISC

对比RISCCISC
指令数量少、格式较固定、单条简单数量多、格式复杂、单条功能强
执行适合流水线,通常执行周期更可预测单条指令可能需要多个周期
硬件控制逻辑相对简单控制逻辑更复杂
例子ARM、MIPSx86

Memory-mapped I/O

代码、SRAM、外设寄存器、外部存储器和系统控制区域占据不同地址范围。处理器可以用普通 load/store 指令访问外设寄存器,因此程序不需要单独的 I/O 指令。

08 · SPI 与 I2C

项目SPII2C
信号线MOSI、MISO、SCLK、每个 slave 的 CSSDA、SCL
寻址使用独立 CS 片选使用 7-bit / 10-bit 地址
传输全双工,速度高半双工,两线节省引脚
多设备设备越多,CS 引脚越多多个设备可共享总线
典型选择高速传感器、显示、存储器低速传感器、配置设备
SPI 写寄存器模板
cs = 0;                       // 选中 slave
spi.write(register_address);
spi.write(value);
cs = 1;                       // 结束通信
SPI 连续读取模板
cs = 0;
spi.write(READ_BIT | MULTI_BIT | start_register);

for (int i = 0; i < length; i++) {
    buffer[i] = spi.write(0x00); // dummy byte 产生时钟
}
cs = 1;
I2C 读写寄存器模板
// Read
char reg = start_register;
i2c.write(address, ®, 1, true); // repeated start
i2c.read(address, buffer, length);

// Write
char data[2];
data[0] = register_address;
data[1] = value;
i2c.write(address, data, 2);

09 · 传感器代码

ADXL345:SPI 初始化

SPI adxl_spi(A6, A5, A4);   // MOSI, MISO, SCLK
DigitalOut adxl_cs(D12);

void write_register(uint8_t reg, uint8_t value) {
    adxl_cs = 0;
    adxl_spi.write(reg);
    adxl_spi.write(value);
    adxl_cs = 1;
}

void initialise() {
    adxl_cs = 1;
    adxl_spi.format(8, 3);        // 8-bit, mode 3
    adxl_spi.frequency(2000000);  // 2 MHz
    write_register(0x31, 0x0B);   // FULL_RES, +/-16g
    write_register(0x2D, 0x08);   // measurement mode
}

TMP102:读取温度

float read_temperature() {
    char reg = 0x00;
    char data[2];

    if (i2c.write(0x90, ®, 1, true) != 0) return 999.0f;
    if (i2c.read(0x90, data, 2) != 0) return 999.0f;

    uint8_t msb = (uint8_t)data[0];
    uint8_t lsb = (uint8_t)data[1];
    int16_t raw = (int16_t)((msb << 4) | (lsb >> 4));

    if (raw & 0x0800) raw |= 0xF000; // 负温度符号扩展
    return raw * 0.0625f;
}
TMP102 重点:读 temperature register 前先写 pointer;12-bit 数据合并后,1 LSB = 0.0625°C;负数需要 sign extension。

10 · 外部中断模板

InterruptIn button(A6);
volatile bool request_flag = false;

void button_isr() {
    request_flag = true; // ISR 只设置 flag
}

int main() {
    button.rise(&button_isr);

    while (1) {
        if (request_flag) {
            request_flag = false;
            // 在 main 中执行 I2C、printf 等复杂任务
        }
        ThisThread::sleep_for(20ms);
    }
}

volatile 告诉编译器:这个变量可能被正常程序流程之外的中断突然修改,每次使用时都必须重新从内存读取。

不要在 ISR 中:执行 I2C 读写、长时间循环、阻塞等待或复杂的 printf

11 · 模块化编程

头文件负责声明模块对外提供的接口,.cpp 文件负责真正实现。其他文件只需要知道函数原型,不需要了解内部细节,这对应 interface、abstraction 和 encapsulation。

文件应该放避免放
.h函数声明、类声明、宏、类型定义、extern 声明普通全局变量定义、普通函数体
.cpp函数实现、变量定义、模块内部逻辑把所有接口隐藏而不提供头文件

Header guard

#ifndef LED_H
#define LED_H

void LED_Init();
void LED_On();
void LED_Off();

#endif

#include 本质上会把头文件内容插入当前位置。Header guard 可防止同一头文件被间接包含多次,避免 redefinition error。

标准答题句:Header guards prevent a header file from being included multiple times in the same translation unit, avoiding redefinition errors caused by repeated inclusion.