1. 课程导学与裸机编程的痛点

1.1 课程目标与学习路径

大家好,我是这门课的主讲。在嵌入式这行摸爬滚打了十几年,我见过太多工程师卡在「裸机转 RTOS」这道坎上。

这门课的目标很直接:帮你从裸机思维平滑过渡到事件驱动架构。不是讲一堆理论让你背,而是带着你手写一个轻量级 RTOS 内核,再移植到真实开发板上跑起来。

学习路径我分成了三个阶段:

  • 基础篇(第 1-5 章):认清裸机痛点,建立 RTOS 基本概念
  • 实战篇(第 6-20 章):手写内核核心模块——任务调度、同步机制、中断管理
  • 移植篇(第 21-30 章):把写好的内核移植到 ARM Cortex-M 平台,跑通事件驱动框架

我个人建议:别跳着看。每章的代码示例都环环相扣,跳过一章后面可能就跟不上了。

1.2 什么是裸机编程(前后台系统)

说白了,裸机编程就是没有操作系统的编程方式。你写的代码直接跑在 CPU 上,没有任务调度、没有内存管理、没有中断统一管理——什么都没有。

业内也叫它「前后台系统」:

  • 前台:中断服务程序(ISR),处理紧急事件
  • 后台:主循环(超级循环),处理非紧急任务

我刚开始做项目时,用的就是这种模式。一个 while(1) 循环,里面塞满各种函数调用,中断来了就跳出去处理,处理完再回来继续跑。简单粗暴,但问题也不少。

1.3 裸机编程的典型架构(超级循环)

来看一个典型的超级循环代码:

int main(void) {
    // 硬件初始化
    system_init();
    peripheral_init();
    
    // 超级循环
    while (1) {
        task_led_blink();      // LED 闪烁
        task_key_scan();       // 按键扫描
        task_lcd_display();    // LCD 显示
        task_uart_send();      // 串口发送
        task_sensor_read();    // 传感器读取
        // ... 更多任务
    }
}

这段代码看起来挺清晰对吧?每个任务一个函数,顺序执行。但你想过没有——如果 task_sensor_read() 执行了 500ms,那 task_led_blink() 就得干等着。

这就是超级循环的核心问题:所有任务串行执行,一个卡住,全家遭殃。

我在项目中遇到过:一个温湿度传感器读取函数,因为 I2C 总线偶尔卡死,导致整个系统 LED 都不闪了。客户投诉说「你们的设备死机了」,其实 CPU 还在跑,只是被卡在传感器读取里出不来。

1.4 裸机编程的痛点分析

咱们把痛点掰开揉碎了讲。我总结了三个核心问题:

痛点 表现 后果
实时性差 高优先级事件必须等当前任务执行完 按键响应延迟、通信超时
扩展性差 加一个新功能就要改主循环 代码耦合严重,牵一发动全身
CPU 空转浪费 轮询等待时 CPU 在空跑 功耗高、发热大、电池续航短

实时性差

你想想看,一个紧急的中断事件来了,ISR 确实能立刻响应。但 ISR 只是「打个标记」,真正的处理逻辑还在主循环里。如果主循环正在执行一个耗时 200ms 的 LCD 刷新函数,那这个紧急事件就得等 200ms 才能被处理。

200ms 对人对来说可能没什么感觉,但对一个高速通信协议来说——黄花菜都凉了。

扩展性差

项目初期功能少,超级循环还能应付。但一旦需求增加,主循环就会变成这样:

while (1) {
    task_a();  // 新增功能 A
    task_b();  // 新增功能 B
    task_led_blink();
    task_key_scan();
    task_c();  // 新增功能 C
    task_lcd_display();
    task_d();  // 新增功能 D
    // ... 越来越长
}

我曾经接手过一个项目,主循环里塞了 30 多个函数。每次加功能都要小心翼翼,生怕破坏了某个任务的时序。后来实在受不了,才下定决心转 RTOS。

CPU 空转浪费

这是最隐蔽的问题。裸机编程里,很多任务都是轮询方式:

void task_key_scan(void) {
    if (GPIO_ReadPin(KEY_PIN) == 0) {
        // 处理按键
    }
    // 如果没按键,函数直接返回,CPU 白跑一趟
}

每次循环,CPU 都要执行这个函数。如果 99% 的时间都没有按键按下,那这 99% 的 CPU 时间就全浪费了。在电池供电的设备里,这种浪费直接体现在续航上。

注意:别以为加个 delay() 就能解决问题。delay() 本质也是空转,CPU 照样在跑,只是不干正事而已。

1.5 知识结构总览

下面这张图把本章的核心逻辑串起来了:

裸机编程痛点与 RTOS 过渡知识结构 裸机编程痛点与 RTOS 过渡知识结构 裸机编程(前后台系统) 前台:中断服务程序 后台:超级循环 三大核心痛点 实时性差 扩展性差 CPU 空转浪费 解决方案:RTOS 任务优先级调度 模块化任务设计 事件驱动 + 休眠 课程核心逻辑 1. 认清裸机编程的局限性(本章) 2. 学习 RTOS 核心概念(任务、调度、同步) 3. 手写轻量级内核并移植到真实硬件 4. 最终实现事件驱动架构,告别轮询噩梦

1.6 小结

裸机编程不是不能用。项目简单、功能固定、对实时性要求不高的时候,它完全够用。但一旦系统复杂起来——多个外设、多个通信协议、严格的时序要求——裸机的短板就会暴露无遗。

我见过太多工程师在裸机项目里「打补丁」:加状态机、加定时器轮询、加各种 flag 标记……最后代码变得比 RTOS 还复杂,却连 RTOS 最基本的任务调度能力都没有。