1. 课程导学与开发环境搭建

各位同学好,我是你们的嵌入式系统讲师。做嵌入式开发十几年了,从最早的8051一路做到现在的Cortex-M4,踩过的坑确实不少。今天咱们开始《STM32L4低功耗RTOS外设管理实战》的第一章。

这一章说白了就是热身。我会带大家了解STM32L4系列到底强在哪,RTOS该怎么选,以及怎么把开发环境搭起来。嗯,最后咱们还会跑两个点灯程序——一个裸机版,一个RTOS版。对比着看,你就能直观感受到RTOS带来的变化。

1.1 STM32L4系列低功耗特性概述

先聊聊STM32L4这个系列。我当年第一次拿到L476的样片时,第一反应是:这玩意儿真能跑RTOS?结果测下来,功耗表现让我挺意外的。

STM32L4基于ARM Cortex-M4内核,带FPU(浮点运算单元)。主频最高80MHz,性能跑到了100 DMIPS左右。但它的核心卖点不是性能,而是——低功耗。

核心低功耗特性:

  • 多种低功耗模式:Sleep、Low-power Sleep、Stop 0/1/2、Standby、Shutdown
  • FlexPowerControl:独立电压域管理,外设可以按需供电
  • LPUART + LPTIM:低功耗串口和定时器,Stop模式下仍可工作
  • SMPS(可选):内部降压转换器,进一步降低运行功耗
  • 快速唤醒:从Stop模式唤醒只需几微秒

我个人的习惯是,做低功耗项目时优先看Stop 2模式。为什么?因为Stop 2下大部分SRAM和寄存器都能保持,唤醒时间也短。我在一个智能传感器项目里,用Stop 2配合LPTIM定时唤醒,整机平均电流做到了10µA以下。

低功耗模式 典型电流 唤醒时间 保留内容
Sleep ~100 µA/MHz 立即 全部
Low-power Sleep ~8 µA/MHz ~5 µs 全部
Stop 0 ~40 µA ~5 µs SRAM全部保留
Stop 1 ~20 µA ~5 µs SRAM全部保留
Stop 2 ~3 µA ~7 µs SRAM全部保留
Standby ~0.3 µA ~50 µs 仅备份寄存器
Shutdown ~0.02 µA ~200 µs 无

避坑提醒:我曾经在一个项目中,为了省电直接用了Shutdown模式。结果发现RTC备份寄存器全丢了,每次唤醒都要重新校准时间。后来改成了Standby + 备份寄存器,才解决问题。选模式时一定要想清楚:你到底需要保留哪些数据?

1.2 RTOS选型:FreeRTOS vs RT-Thread

RTOS选型这事儿,说实话没有绝对的对错。我两种都用过,各有各的适用场景。

先看FreeRTOS。它是个轻量级RTOS,内核极小,ROM占用大概6-12KB。移植简单,资料多,生态成熟。我最早接触RTOS就是从FreeRTOS入门的。

再看RT-Thread。它更像一个物联网操作系统,除了内核还带了文件系统、网络协议栈、设备驱动框架。功能丰富,但体积也大——完整版要100KB以上。

对比项 FreeRTOS RT-Thread
内核大小 6-12 KB 3-10 KB(nano版)
任务数量 无限制 无限制
调度方式 抢占式 + 协作式 抢占式 + 时间片
IPC机制 队列、信号量、互斥量 邮箱、消息队列、信号量、事件集
内存管理 heap_1~5可选 静态/动态 + memheap
组件生态 较少(需自行移植) 丰富(文件系统、网络、GUI)
商业许可 MIT(无商业限制) Apache 2.0(无商业限制)

我个人建议:如果你的项目只是简单的传感器采集、电机控制,FreeRTOS完全够用。但如果项目需要文件系统、网络通信、甚至GUI,RT-Thread能省很多事。

咱们这门课选的是FreeRTOS。原因很简单:轻量、易学、适合低功耗场景。而且FreeRTOS在STM32上的移植非常成熟,CubeMX直接支持一键生成。

我的经验:做低功耗项目时,FreeRTOS的tickless模式特别好用。它能在空闲时自动进入低功耗模式,配合STM32L4的Stop模式,能把功耗压到极低。这个咱们后面会专门讲。

1.3 开发板介绍:NUCLEO-L476RG

咱们课程用的是NUCLEO-L476RG。这块板子我用了好几年,性价比很高。

板载资源一览:

  • 主控:STM32L476RG(Cortex-M4, 80MHz, 1MB Flash, 128KB SRAM)
  • 板载ST-LINK/V2-1调试器(支持虚拟串口、拖拽下载)
  • Arduino Uno V3兼容接口
  • ST Morpho扩展接口
  • 3个LED(LD1~LD3)、1个用户按键、1个复位按键
  • 32.768kHz RTC晶振

这块板子最大的好处是——你不用额外买调试器。一根USB线就能供电、调试、串口通信。我出差做现场调试时经常只带一块NUCLEO板加一根线,轻便得很。

1.4 STM32CubeMX与Keil/IAR环境搭建

环境搭建这块,我踩过的坑比较多,所以给大家整理了一个清晰的步骤。

1.4.1 安装STM32CubeMX

  1. 去ST官网下载STM32CubeMX(需要注册账号)
  2. 安装时选默认路径,注意勾选Java运行环境(CubeMX基于Java)
  3. 安装完成后,打开CubeMX,它会自动检查更新

我曾经踩过的坑:CubeMX的版本一定要和固件包匹配。有一次我用了新版CubeMX配旧版固件包,结果生成的代码死活编译不过。后来发现是HAL库API变了。建议用CubeMX自带的固件包管理功能下载对应版本。

1.4.2 安装Keil MDK或IAR

Keil和IAR二选一就行。我个人习惯用Keil,因为它的调试界面更直观。但IAR的编译优化确实更好。

工具 优点 缺点
Keil MDK 界面友好、调试方便、中文资料多 代码大小限制(免费版32KB)
IAR EWARM 编译优化强、代码密度高 界面稍复杂、价格较高

1.4.3 生成第一个工程

  1. 打开CubeMX,选择New Project
  2. 在Board Selector里搜索NUCLEO-L476RG
  3. 双击选中,CubeMX会自动加载板级配置
  4. 配置时钟:HSE + PLL,主频80MHz
  5. 配置GPIO:PA5(板载LED)设为Output
  6. Project Manager里设置工程名、IDE类型(选MDK-ARM或IAR)
  7. 点击Generate Code

嗯,这里要注意:生成代码时CubeMX会提示是否打开工程。选是就行。

1.5 第一个点灯程序:裸机 vs RTOS

终于到了动手环节。咱们先写一个裸机点灯,再写一个RTOS点灯。对比着看,你就能理解RTOS到底带来了什么。

1.5.1 裸机点灯(轮询方式)

#include "main.h"

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    while (1)
    {
        HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
        HAL_Delay(500);  // 阻塞延时500ms
    }
}

这段代码很简单。但问题也很明显:HAL_Delay(500)这行是阻塞的。在这500ms里,CPU什么都干不了。如果我要同时处理按键扫描、串口通信、传感器读取……代码会变得非常复杂。

1.5.2 RTOS点灯(任务方式)

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"

void vLEDTask(void *pvParameters)
{
    while (1)
    {
        HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
        vTaskDelay(pdMS_TO_TICKS(500));  // 非阻塞延时
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    xTaskCreate(vLEDTask, "LED", 128, NULL, 1, NULL);
    vTaskStartScheduler();  // 启动调度器

    while (1);  // 不会执行到这里
}

看到区别了吗?vTaskDelay不会阻塞CPU。在LED任务等待的500ms里,调度器可以切换到其他任务去执行。比如我可以再创建一个按键扫描任务、一个串口发送任务——它们互不干扰。

核心差异总结:

  • 裸机:顺序执行,一个延时卡住全部
  • RTOS:任务独立,延时期间CPU干别的
  • 裸机:代码简单,但扩展性差
  • RTOS:代码结构清晰,适合复杂项目

你想想看,如果你的项目只有点灯这一个功能,裸机完全够用。但现实中的嵌入式项目往往要同时处理多个任务——采集数据、处理算法、通信上报、响应按键……这时候RTOS的价值就体现出来了。

裸机 vs RTOS 执行流程对比 裸机:顺序执行 任务A:点灯 延时500ms(CPU空转) 任务B:按键扫描(等待中) 任务C:串口发送(等待中) RTOS:任务切换 任务A:点灯 → 延时 调度器切换 任务B:按键扫描(执行中) 调度器切换 任务C:串口发送(执行中) 关键区别 裸机:一个任务延时,所有任务都得等 RTOS:延时期间自动切换其他任务,CPU利用率更高

小提示:第一次跑RTOS程序时,如果LED不闪,先检查vTaskStartScheduler()是否被调用了。我遇到过好几次,都是因为忘了启动调度器。

好了,第一章的内容就到这里。环境搭好了,点灯程序也跑了,接下来咱们就可以正式开始RTOS外设管理的学习了。