嵌入式系统基础:MCU与MPU选型、RTOS基础、中断与任务调度

做嵌入式多传感器融合,第一步不是写代码,而是选芯片。我见过太多项目,代码写到一半发现算力不够,或者外设接口不够用,最后只能推倒重来。说白了,选型就是给整个项目打地基。

MCU vs MPU:你到底需要什么?

很多人分不清MCU和MPU的区别。我简单说:MCU(微控制器)是单片机,芯片内部集成了Flash、RAM和各种外设,适合做控制类任务。MPU(微处理器)更像电脑的CPU,需要外接DDR、Flash等,适合跑Linux这类复杂系统。

举个例子。你做一个温度传感器节点,采集数据然后通过无线发送,MCU就够了。但如果你要做视觉导航的机器人,需要处理摄像头图像、运行SLAM算法,那必须上MPU。

选型核心原则:

  • 算力需求:传感器融合算法复杂度如何?需要浮点运算吗?
  • 外设接口:需要几个SPI、I2C、UART?有没有CAN或以太网需求?
  • 功耗预算:电池供电还是市电?休眠电流能接受多少?
  • 成本控制:MCU通常几块钱到几十块,MPU几十到几百块。

我个人习惯,先列一个外设清单,再估算算法需要的MIPS或DMIPS。比如一个IMU+激光雷达的融合项目,至少需要Cortex-M4以上的MCU,或者直接上Cortex-A系列的MPU。

实时操作系统(RTOS)基础

为什么多传感器融合需要RTOS?你想想看,如果不用操作系统,你只能用超级循环(Super Loop)来轮询所有传感器。一旦某个传感器响应慢了,整个系统就卡住了。

RTOS的核心价值在于:让多个任务看起来在同时运行。每个传感器采集、数据处理、通信都可以独立成一个任务,由调度器统一管理。

常见的RTOS选择

RTOS特点适用场景
FreeRTOS开源、轻量、生态好绝大多数MCU项目
RT-Thread国产、组件丰富、支持设备驱动框架需要快速开发的IoT项目
uC/OS-III商业授权、稳定可靠工业控制、医疗设备
ZephyrLinux基金会、支持蓝牙/WiFi无线传感器网络

我在项目中用得最多的是FreeRTOS。为什么?因为资料多,遇到问题网上基本都能找到答案。而且它很小,一个完整的RTOS内核可能只占几KB的Flash。

小技巧:选RTOS时,除了看功能,还要看它的任务切换时间中断延迟。这两个指标直接影响实时性。我一般要求任务切换时间不超过10微秒,中断延迟不超过5微秒。

中断与任务调度

中断是嵌入式系统的灵魂。没有中断,你只能不停地轮询,CPU资源全浪费了。

中断优先级与嵌套

多传感器系统中,中断优先级设置特别重要。比如,IMU的数据更新频率是1kHz,而温度传感器只有10Hz。显然,IMU的中断优先级应该更高。

我曾经犯过一个错误:把所有传感器中断都设成同一优先级。结果高频率的IMU中断把低优先级的任务饿死了,系统直接崩溃。后来我学乖了,严格按照实时性要求来分配优先级。

注意:中断服务函数(ISR)要尽量短。我见过有人把复杂的卡尔曼滤波算法直接写在ISR里,导致其他中断响应延迟超过100微秒。正确的做法是:ISR只做标记或数据拷贝,真正的处理交给任务。

任务调度策略

RTOS常用的调度策略有三种:

  • 抢占式调度:高优先级任务可以打断低优先级任务。这是最常用的方式。
  • 时间片轮转:同优先级任务轮流执行,每个任务分到固定的时间片。
  • 协作式调度:任务主动让出CPU,否则一直运行。很少用。

多传感器融合场景下,我推荐抢占式调度 + 优先级分配。比如:

  • 最高优先级:IMU数据采集(需要实时响应)
  • 次高优先级:激光雷达数据采集
  • 中等优先级:传感器数据融合计算
  • 低优先级:日志输出、状态显示

任务间通信

传感器数据怎么在不同任务之间传递?RTOS提供了几种机制:

  • 队列(Queue):最常用,一个任务往队列里写数据,另一个任务读数据。适合一对一的通信。
  • 信号量(Semaphore):用于同步,比如通知某个任务数据准备好了。
  • 事件标志组(Event Group):可以等待多个条件同时满足。
  • 消息邮箱(Mailbox):类似队列,但通常只存一条消息。

我个人习惯用队列来传递传感器数据。比如IMU任务每采集到一组数据,就通过队列发送给融合任务。这样两个任务完全解耦,互不干扰。

避坑指南:我曾经在队列深度设置上吃过亏。如果队列太浅,数据会丢失;如果太深,浪费内存。我的经验是:队列深度 = 任务处理周期 × 数据产生频率 × 1.5。比如IMU产生数据频率是1kHz,融合任务处理周期是2ms,那么队列深度至少是 2ms × 1000Hz × 1.5 = 3。实际项目中我一般取5~10,留点余量。

一个简单的多传感器融合任务框架

最后,我分享一个实际项目中的任务框架。假设你有三个传感器:IMU、激光雷达、温度传感器。

// 伪代码示例
void task_imu(void *param) {
    while(1) {
        // 等待IMU中断信号
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        // 读取IMU数据
        imu_read(&data);
        // 发送到融合任务
        xQueueSend(queue_fusion, &data, 0);
    }
}

void task_lidar(void *param) {
    while(1) {
        // 等待激光雷达数据就绪
        xSemaphoreTake(sem_lidar, portMAX_DELAY);
        lidar_read(&data);
        xQueueSend(queue_fusion, &data, 0);
    }
}

void task_fusion(void *param) {
    while(1) {
        // 从队列中获取传感器数据
        if(xQueueReceive(queue_fusion, &data, pdMS_TO_TICKS(10))) {
            // 执行融合算法
            sensor_fusion(&data);
        }
    }
}

嗯,这个框架看起来简单,但实际项目中要考虑的东西很多。比如任务栈大小、优先级反转、死锁预防等等。不过别担心,后面几章我会逐一展开讲。

记住一句话:选型决定上限,调度决定下限。芯片选对了,RTOS调度做好了,你的多传感器融合项目就成功了一半。