1. 嵌入式系统概述
嵌入式系统(Embedded System)是为执行特定功能而将硬件与软件结合在一起的专用计算系统。洗衣机、汽车发动机控制单元(ECU)、智能温控器、医疗设备等,我们身边无数的设备中都内置着它。
微控制器(MCU)与微处理器(MPU)
| 项目 | MCU | MPU |
|---|---|---|
| CPU | 简单、低功耗 | 高性能、复杂 |
| 内存 | 内置 Flash/RAM | 需要外部 DRAM |
| 操作系统 | 无或 RTOS | Linux、Android 等 |
| 功耗 | 数 mW | 数 W |
| 示例 | STM32、AVR、ESP32 | Raspberry Pi、i.MX8 |
主要 MCU 平台
- STM32(ST Microelectronics):基于 ARM Cortex-M,广泛用于工业领域。提供 HAL 库与 CubeMX 开发工具。
- AVR(Microchip/Atmel):Arduino UNO 的基础 MCU。对初学者友好的平台。
- ESP32(Espressif):双核 Xtensa LX6,内置 WiFi+BLE。最适合 IoT 项目。
- RP2040(Raspberry Pi):双核 ARM Cortex-M0+,PIO(可编程 I/O)功能独具特色。
- PIC(Microchip):在工业现场拥有悠久历史的 MCU。
开发环境
- IDE:STM32CubeIDE、MPLAB X、Arduino IDE、PlatformIO
- 编译器:GCC(arm-none-eabi-gcc)、LLVM/Clang
- 调试器:JTAG、SWD(Serial Wire Debug)、OpenOCD、J-Link
2. 用 C 语言控制硬件
嵌入式 C 编程的核心,在于直接操作硬件寄存器,或是利用 HAL(硬件抽象层)库。
GPIO 控制
GPIO(通用输入输出)是控制数字输入输出最基本的接口。
// 使用 STM32 HAL 库控制 GPIO
#include "stm32f4xx_hal.h"
// LED 翻转(引脚 PA5)
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(500);
// 读取按钮(引脚 PC13,低电平有效)
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) {
// 按钮被按下时的处理
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}
直接操作寄存器
不使用 HAL、直接操作寄存器的方式更快、代码体积也更小。
// 直接操作寄存器(STM32F4)
// 启用 GPIOA 时钟
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
// 将 PA5 设置为输出(MODER 寄存器)
GPIOA->MODER &= ~(0x3 << (5 * 2)); // 清除对应位
GPIOA->MODER |= (0x1 << (5 * 2)); // 设置为输出模式
// PA5 输出 HIGH
GPIOA->BSRR = (1 << 5);
// PA5 输出 LOW
GPIOA->BSRR = (1 << (5 + 16));
volatile 关键字的重要性
由于编译器优化,对硬件寄存器的访问可能被忽略。用 volatile 来防止这种情况。
// 错误示例:编译器可能会将其优化掉
uint32_t *reg = (uint32_t *)0x40020000;
*reg = 0x01;
// 正确示例:使用 volatile
volatile uint32_t *reg = (volatile uint32_t *)0x40020000;
*reg = 0x01;
// ISR 中使用的全局变量也需要 volatile
volatile uint8_t button_pressed = 0;
3. 中断与定时器
中断服务例程(ISR)
中断是一种机制:当硬件事件(按钮输入、定时器溢出、通信接收等)发生时,CPU 中断当前工作、执行 ISR。
// EXTI 中断回调(HAL 方式)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_13) {
button_pressed = 1;
// ISR 内只做最小限度的工作
// 禁止使用 HAL_Delay() 等阻塞函数
}
}
// 定时器中断回调(每 1ms 调用一次)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
system_tick++;
}
}
PWM 输出
利用定时器的 PWM(脉宽调制)功能,实现伺服电机、LED 亮度调节、电机转速控制。
// 启动 PWM(TIM3 通道 1)
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
// 设置占空比 50%(若 ARR = 999,则 CCR = 500)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 500);
// 伺服电机角度控制函数(0~180 度)
void servo_set_angle(uint8_t angle) {
// 将 1ms~2ms 脉宽转换为定时器计数值
uint32_t pulse = 500 + (angle * 1000 / 180);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pulse);
}
4. 串行通信协议
UART/USART
异步串行通信。主要用于调试输出、GPS 模块、蓝牙模块的连接。
// 通过 UART 发送字符串
char msg[] = "Hello, UART!\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 100);
// UART 接收(中断方式)
uint8_t rx_byte;
HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART2) {
rx_buffer[rx_index++] = rx_byte;
HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
}
}
SPI 通信
主从式同步通信。用于需要高速数据传输的显示器、SD 卡、ADC。
// 通过 SPI 收发数据
uint8_t tx_data[] = {0x9F, 0x00}; // 读取 Flash ID 命令
uint8_t rx_data[2];
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); // CS LOW
HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, 2, 100);
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); // CS HIGH
I2C 通信
双线(SDA、SCL)总线通信。可在同一总线上连接多个设备。主要用于各类传感器。
// 通过 I2C 读取 MPU6050 加速度计
#define MPU6050_ADDR 0xD0 // 7 位地址 0x68,写地址 0xD0
#define ACCEL_XOUT_H 0x3B
uint8_t data[6];
HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, ACCEL_XOUT_H,
I2C_MEMADD_SIZE_8BIT, data, 6, 100);
int16_t accel_x = (data[0] << 8) | data[1];
int16_t accel_y = (data[2] << 8) | data[3];
int16_t accel_z = (data[4] << 8) | data[5];
// 实际加速度(g 单位) = raw / 16384.0(设为 ±2g 时)
float ax = accel_x / 16384.0f;
CAN 总线
汽车与工业设备中使用的坚固差分串行通信协议。
// 发送 CAN 消息(STM32 HAL)
CAN_TxHeaderTypeDef tx_header;
uint8_t tx_data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint32_t tx_mailbox;
tx_header.StdId = 0x123; // CAN ID
tx_header.IDE = CAN_ID_STD; // 标准帧
tx_header.RTR = CAN_RTR_DATA; // 数据帧
tx_header.DLC = 8; // 数据长度
HAL_CAN_AddTxMessage(&hcan1, &tx_header, tx_data, &tx_mailbox);
5. RTOS(实时操作系统)
RTOS 是能够保证确定性(Deterministic)时序的操作系统。它按优先级调度多个任务,对要求实时响应的系统必不可少。
FreeRTOS 基础
FreeRTOS 是应用最广泛的开源 RTOS。由 Amazon 维护,支持 STM32、ESP32、Arduino 等多种平台。
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"
// 任务函数定义
void vTaskLED(void *pvParameters) {
while(1) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
vTaskDelay(pdMS_TO_TICKS(500)); // 等待 500ms(让出 CPU)
}
}
void vTaskSensor(void *pvParameters) {
QueueHandle_t xQueue = (QueueHandle_t)pvParameters;
float temperature;
while(1) {
temperature = read_temperature_sensor();
xQueueSend(xQueue, &temperature, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
QueueHandle_t xTempQueue = xQueueCreate(10, sizeof(float));
// 创建任务(函数名、任务名、栈大小、参数、优先级、句柄)
xTaskCreate(vTaskLED, "LED", 128, NULL, 1, NULL);
xTaskCreate(vTaskSensor, "Sensor", 256, xTempQueue, 2, NULL);
vTaskStartScheduler(); // 启动 RTOS 调度器(此行之后不再返回)
while(1);
}
信号量与互斥锁
SemaphoreHandle_t xMutex;
SemaphoreHandle_t xSemaphore;
// 用互斥锁保护共享资源
xMutex = xSemaphoreCreateMutex();
void vTaskA(void *pvParameters) {
while(1) {
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 临界区:访问共享资源
shared_data++;
xSemaphoreGive(xMutex);
}
}
}
// 用二值信号量实现 ISR-任务同步
xSemaphore = xSemaphoreCreateBinary();
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
6. Arduino 生态系统
Arduino 是面向嵌入式入门者的开源平台。特点是简单的 API 与庞大的库生态系统。
Arduino 开发板比较
| 开发板 | MCU | 时钟 | Flash | RAM | 特点 |
|---|---|---|---|---|---|
| UNO R3 | ATmega328P | 16MHz | 32KB | 2KB | 基础入门款 |
| Nano | ATmega328P | 16MHz | 32KB | 2KB | 小型封装 |
| Mega 2560 | ATmega2560 | 16MHz | 256KB | 8KB | 引脚数量多 |
| Due | SAM3X8E | 84MHz | 512KB | 96KB | 32 位 ARM |
| UNO R4 | RA4M1 | 48MHz | 256KB | 32KB | 最新版本 |
DHT22 + I2C LCD 示例
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
Serial.begin(9600);
dht.begin();
lcd.init();
lcd.backlight();
lcd.print("IoT Weather Box");
delay(2000);
lcd.clear();
}
void loop() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (isnan(temp) || isnan(hum)) {
Serial.println("DHT read error!");
return;
}
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temp, 1);
lcd.print(" C ");
lcd.setCursor(0, 1);
lcd.print("Hum: ");
lcd.print(hum, 1);
lcd.print(" % ");
Serial.print("T="); Serial.print(temp);
Serial.print(" H="); Serial.println(hum);
delay(2000);
}
7. ESP32 & WiFi/BLE IoT
ESP32 是 Espressif Systems 出品的强大 IoT MCU。内置双核 240MHz、WiFi 802.11 b/g/n、BLE 4.2/5.0,性价比出众。
用 MicroPython 实现 MQTT IoT
# MicroPython ESP32 通过 MQTT 发送传感器数据
import time
import network
from umqtt.simple import MQTTClient
from machine import Pin, ADC
# WiFi 连接
def connect_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
wlan.connect(ssid, password)
while not wlan.isconnected():
time.sleep(0.5)
print('WiFi connected:', wlan.ifconfig())
# MQTT 消息接收回调
def on_message(topic, msg):
print('Topic:', topic, 'Message:', msg)
if topic == b'device/led' and msg == b'on':
led.value(1)
connect_wifi('MySSID', 'MyPassword')
# 用 ADC 读取温度传感器(NTC 热敏电阻)
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)
client = MQTTClient('esp32_sensor', 'broker.hivemq.com', port=1883)
client.set_callback(on_message)
client.connect()
client.subscribe(b'device/led')
while True:
raw = adc.read()
voltage = raw * 3.3 / 4095
# 简易温度转换(实际需要 NTC 特性曲线)
temp_approx = (voltage - 0.5) * 100
payload = '{:.1f}'.format(temp_approx)
client.publish(b'sensor/temperature', payload.encode())
client.check_msg()
time.sleep(5)
ESP-IDF(基于 C/C++)
// ESP-IDF WiFi 连接示例
#include "esp_wifi.h"
#include "esp_event.h"
#include "nvs_flash.h"
#define WIFI_SSID "MyNetwork"
#define WIFI_PASS "MyPassword"
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI("WiFi", "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
}
}
void wifi_init_sta(void) {
nvs_flash_init();
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL);
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL);
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
},
};
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_wifi_start();
}
8. Raspberry Pi 与 Linux 嵌入式
Raspberry Pi 是运行完整 Linux 操作系统的单板计算机(SBC)。它是处于嵌入式与通用计算交界处的强大平台。
Raspberry Pi 系列比较
| 型号 | CPU | RAM | 特点 |
|---|---|---|---|
| Pi Zero 2W | ARM Cortex-A53 quad 1GHz | 512MB | 超小型,WiFi/BLE |
| Pi 4 Model B | ARM Cortex-A72 quad 1.8GHz | 1~8GB | 通用高性能 |
| Pi 5 | ARM Cortex-A76 quad 2.4GHz | 4~8GB | 最新高性能 |
| Pi Pico 2 | RP2350 dual Cortex-M33 | 520KB | 微控制器 |
GPIO 控制与伺服电机
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM) # 使用 BCM 引脚编号
GPIO.setup(18, GPIO.OUT) # 将 GPIO18 设置为输出
# 50Hz PWM 伺服电机控制
pwm = GPIO.PWM(18, 50)
pwm.start(7.5) # 中立位置(90 度)
def set_servo_angle(angle):
"""设置伺服电机角度(0~180 度)"""
duty = 2.5 + (angle / 180.0) * 10.0
pwm.ChangeDutyCycle(duty)
time.sleep(0.3)
try:
for angle in [0, 45, 90, 135, 180]:
set_servo_angle(angle)
print(f"Angle: {angle} degrees")
time.sleep(1)
finally:
pwm.stop()
GPIO.cleanup()
gpiozero 库
from gpiozero import LED, Button, Servo, DistanceSensor
from signal import pause
import time
# 连接 LED 和按钮
led = LED(17)
button = Button(4)
# 按钮事件处理器
button.when_pressed = led.on
button.when_released = led.off
# 超声波距离传感器(HC-SR04)
sensor = DistanceSensor(echo=24, trigger=23)
while True:
dist = sensor.distance * 100 # 单位:cm
print(f"Distance: {dist:.1f} cm")
if dist < 20:
led.blink(on_time=0.1, off_time=0.1)
time.sleep(0.5)
使用 Docker 容器
# 面向 Raspberry Pi 的 Python IoT 应用 Dockerfile
FROM python:3.11-slim-bullseye
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "sensor_server.py"]
# docker-compose.yml
version: '3'
services:
sensor-app:
build: .
privileged: true # 需要该权限才能访问 GPIO
volumes:
- /dev:/dev
restart: unless-stopped
influxdb:
image: influxdb:2.7
ports:
- '8086:8086'
volumes:
- influx_data:/var/lib/influxdb2
grafana:
image: grafana/grafana:latest
ports:
- '3000:3000'
volumes:
- grafana_data:/var/lib/grafana
volumes:
influx_data:
grafana_data:
9. 边缘 AI(Edge AI)
边缘 AI 是一种在本地设备而非云端执行 AI 推理的技术。低延迟、离线运行、隐私保护、节省带宽是它的主要优点。
TensorFlow Lite(TFLite)
TFLite 是为移动端及嵌入式设备优化的轻量级 ML 框架。
# TFLite 图像分类推理(Raspberry Pi)
import tflite_runtime.interpreter as tflite
import numpy as np
from PIL import Image
import time
# 加载模型
interpreter = tflite.Interpreter(
model_path='mobilenet_v2_1.0_224_quant.tflite',
num_threads=4 # 多线程推理
)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# 打印输入信息
print("Input shape:", input_details[0]['shape']) # [1, 224, 224, 3]
print("Input dtype:", input_details[0]['dtype']) # uint8(量化模型)
def classify_image(image_path, labels):
img = Image.open(image_path).convert('RGB').resize((224, 224))
input_data = np.expand_dims(np.array(img), axis=0)
# uint8 量化模型无需归一化
interpreter.set_tensor(input_details[0]['index'], input_data)
start = time.time()
interpreter.invoke()
elapsed = (time.time() - start) * 1000
output = interpreter.get_tensor(output_details[0]['index'])
top_idx = np.argmax(output[0])
print(f"Label: {labels[top_idx]}, Score: {output[0][top_idx]}")
print(f"Inference time: {elapsed:.1f}ms")
# 加载标签文件
with open('labels.txt') as f:
labels = [line.strip() for line in f.readlines()]
classify_image('test.jpg', labels)
ONNX Runtime
# 用 ONNX Runtime 运行自定义模型
import onnxruntime as ort
import numpy as np
from PIL import Image
# 创建会话(可选择 CPU/GPU)
session = ort.InferenceSession(
'model.onnx',
providers=['CPUExecutionProvider']
)
# 确认输入输出信息
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name
input_shape = session.get_inputs()[0].shape
print(f"Input: {input_name}, Shape: {input_shape}")
# 图像预处理
img = Image.open('test.jpg').resize((224, 224))
img_array = np.array(img).astype(np.float32) / 255.0
img_array = np.transpose(img_array, (2, 0, 1)) # HWC -> CHW
img_array = np.expand_dims(img_array, axis=0) # 添加批次维度
# 推理
result = session.run([output_name], {input_name: img_array})
print("Output shape:", result[0].shape)
边缘 AI 平台比较
| 平台 | 厂商 | AI 性能 | 功耗 | 特点 |
|---|---|---|---|---|
| Jetson Orin Nano | NVIDIA | 40 TOPS | 7~15W | 内置 CUDA GPU |
| Coral Dev Board | 4 TOPS | ~2W | 专用 Edge TPU | |
| RK3588 | Rockchip | 6 TOPS NPU | ~8W | 性价比出色 |
| Hailo-8 M.2 | Hailo | 26 TOPS | 2.5W | PCIe 扩展模块 |
| Pi 5 + AI HAT+ | RPi Foundation | 26 TOPS | ~5W | 树莓派生态 |
10. IoT 通信协议与云
MQTT
MQTT(Message Queuing Telemetry Transport)是为 IoT 优化的轻量级 pub/sub 消息协议。发布者(Publisher)与订阅者(Subscriber)通过代理(Broker)进行通信。
# Python Paho-MQTT 客户端示例
import paho.mqtt.client as mqtt
import json
import time
BROKER = "broker.hivemq.com"
PORT = 1883
TOPIC_PUB = "home/sensor/living_room"
TOPIC_SUB = "home/control/#"
def on_connect(client, userdata, flags, rc):
print(f"Connected with code: {rc}")
client.subscribe(TOPIC_SUB)
def on_message(client, userdata, msg):
payload = json.loads(msg.payload.decode())
print(f"Topic: {msg.topic}, Payload: {payload}")
client = mqtt.Client("python_sensor_01")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
while True:
data = {
"temperature": 23.5,
"humidity": 60.2,
"timestamp": int(time.time())
}
client.publish(TOPIC_PUB, json.dumps(data))
time.sleep(10)
InfluxDB + Grafana 数据可视化
# 将传感器数据写入 InfluxDB
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
INFLUX_URL = "http://localhost:8086"
INFLUX_TOKEN = "your_token_here"
INFLUX_ORG = "myorg"
INFLUX_BUCKET = "iot_sensors"
client = InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG)
write_api = client.write_api(write_options=SYNCHRONOUS)
# 创建数据点
point = (
Point("environment")
.tag("location", "living_room")
.tag("device", "esp32_01")
.field("temperature", 23.5)
.field("humidity", 60.2)
.field("co2_ppm", 650)
)
write_api.write(bucket=INFLUX_BUCKET, record=point)
AWS IoT Core
AWS IoT Core 是一项完全托管的云服务,能够安全地连接与管理数十亿台 IoT 设备。它通过基于 X.509 证书的 mTLS 保障安全,并与 AWS Lambda、DynamoDB、S3 等 AWS 服务集成。
11. 嵌入式安全
OTA(Over-the-Air)固件更新
安全 OTA 的核心是签名验证。拒绝未签名的固件,防止恶意代码被安装。
// ESP-IDF OTA 更新示例
#include "esp_ota_ops.h"
#include "esp_https_ota.h"
void ota_task(void *pvParameter) {
esp_https_ota_config_t ota_config = {
.http_config = &(esp_http_client_config_t){
.url = "https://myserver.com/firmware.bin",
.cert_pem = server_cert_pem, // 验证服务器证书
},
};
esp_err_t ret = esp_https_ota(&ota_config);
if (ret == ESP_OK) {
esp_restart(); // 成功后重启
} else {
ESP_LOGE("OTA", "Update failed: %s", esp_err_to_name(ret));
}
vTaskDelete(NULL);
}
在 MCU 上进行 AES 加密
// mbedTLS AES-128 CBC 加密(STM32/ESP32)
#include "mbedtls/aes.h"
void aes_encrypt_data(uint8_t *plaintext, uint8_t *ciphertext,
uint8_t *key, uint8_t *iv, size_t len) {
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 128); // 128 位密钥
uint8_t iv_copy[16];
memcpy(iv_copy, iv, 16); // IV 会在加密过程中被修改
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, len,
iv_copy, plaintext, ciphertext);
mbedtls_aes_free(&ctx);
}
安全设计原则
- 最小权限原则:只启用必要功能,禁用未使用的接口
- 安全启动(Secure Boot):启动时验证固件签名
- Flash 加密:对存储在 Flash 中的代码/数据进行加密
- 读出保护(RDP):防止通过 JTAG/SWD 转储固件
- 随机数生成器(TRNG):使用硬件 RNG 生成加密密钥
- 超时与看门狗:自动从无响应状态恢复
12. 测验
Q1. MCU 与 MPU 最大的区别是什么?
答案:MCU(微控制器)将 CPU、内存(Flash、RAM)、外设(UART、SPI、I2C、ADC 等)集成在同一颗芯片上。而 MPU(微处理器)专注于 CPU 核心,需要额外配备外部内存与外设。
说明:MCU 适合要求低功耗、小体积、低成本的嵌入式应用,MPU 则适合需要运行 Linux 等复杂操作系统的高性能应用。
Q2. RTOS 中信号量与互斥锁的区别是什么?
答案:互斥锁(Mutex)具有所有权(Ownership),只有加锁的任务才能解锁,并具备防止优先级反转(Priority Inversion)的优先级继承机制。信号量没有所有权,其他任务或 ISR 也可以发出信号。
说明:互斥锁用于共享资源的互斥(Mutual Exclusion),信号量则用于任务间同步或资源计数。当需要从 ISR 向任务通知事件时,使用二值信号量。
Q3. 比较 I2C 与 SPI 通信方式的优缺点。
答案:
- I2C 优点:只需 2 根线(SDA、SCL),可在同一总线上连接多个设备(以地址区分),布线简单
- I2C 缺点:比 SPI 慢(最高 3.4Mbps),需要上拉电阻,开漏方式不利于高速传输
- SPI 优点:速度非常快(数十 Mbps),全双工通信,硬件实现简单
- SPI 缺点:每个设备都需要 CS 引脚(引脚数增加),没有地址概念
说明:低速传感器(MPU6050、BMP280 等)主要使用 I2C,需要高速传输的显示器、SD 卡、SPI Flash 则主要使用 SPI。
Q4. 在嵌入式系统中,为什么 volatile 关键字很重要?
答案:编译器在优化过程中,会假定变量的值只在代码内部发生变化。但硬件寄存器、在 ISR 中被修改的变量、DMA 缓冲区等,其值可能在程序流程之外发生变化。volatile 关键字会告诉编译器不要优化该变量,每次都从内存中重新读取。
说明:如果没有 volatile,即使在 ISR 中设置了标志位,主循环也可能因为读取到缓存值而无法识别,从而产生 bug。这是一种在没有调试器的情况下很难发现的经典嵌入式 bug。
Q5. 边缘 AI 中为什么要使用模型量化(Quantization)?
答案:量化是一种将模型的权重与激活值从 32 位浮点数(FP32)转换为 8 位整数(INT8)的技术。借此可将模型体积缩小约 4 倍,推理速度提升 2~4 倍,并大幅降低内存占用与功耗。
说明:嵌入式设备的内存(仅数 MB)与算力都很有限。TFLite 的 INT8 量化模型即便在 Raspberry Pi 或 Cortex-M MCU 这类低配置设备上也能实现实时推理。不过精度可能会略有下降(通常在 1~2% 以内)。
参考资料
현재 단락 (1/470)
嵌入式系统(Embedded System)是为执行特定功能而将硬件与软件结合在一起的专用计算系统。洗衣机、汽车发动机控制单元(ECU)、智能温控器、医疗设备等,我们身边无数的设备中都内置着它。