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
- 去ST官网下载STM32CubeMX(需要注册账号)
- 安装时选默认路径,注意勾选Java运行环境(CubeMX基于Java)
- 安装完成后,打开CubeMX,它会自动检查更新
我曾经踩过的坑:CubeMX的版本一定要和固件包匹配。有一次我用了新版CubeMX配旧版固件包,结果生成的代码死活编译不过。后来发现是HAL库API变了。建议用CubeMX自带的固件包管理功能下载对应版本。
1.4.2 安装Keil MDK或IAR
Keil和IAR二选一就行。我个人习惯用Keil,因为它的调试界面更直观。但IAR的编译优化确实更好。
| 工具 | 优点 | 缺点 |
|---|---|---|
| Keil MDK | 界面友好、调试方便、中文资料多 | 代码大小限制(免费版32KB) |
| IAR EWARM | 编译优化强、代码密度高 | 界面稍复杂、价格较高 |
1.4.3 生成第一个工程
- 打开CubeMX,选择New Project
- 在Board Selector里搜索NUCLEO-L476RG
- 双击选中,CubeMX会自动加载板级配置
- 配置时钟:HSE + PLL,主频80MHz
- 配置GPIO:PA5(板载LED)设为Output
- Project Manager里设置工程名、IDE类型(选MDK-ARM或IAR)
- 点击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的价值就体现出来了。
小提示:第一次跑RTOS程序时,如果LED不闪,先检查vTaskStartScheduler()是否被调用了。我遇到过好几次,都是因为忘了启动调度器。
好了,第一章的内容就到这里。环境搭好了,点灯程序也跑了,接下来咱们就可以正式开始RTOS外设管理的学习了。