
这次我们来看一个很典型的嵌入式开源项目基于 STM32 的红外遥控多路开关控制系统。这类项目在高校课程设计、电子设计竞赛、个人智能家居 DIY 里出现频率很高它不涉及复杂的 AI 模型也不需要高算力硬件但能把 STM32 的 GPIO、外部中断、定时器、串口、NEC 红外解码、继电器驱动这些基础外设全部串起来。如果你正在学 STM32或者想做一个能实际控制灯、风扇、插座的多路开关这个项目值得仔细拆解。项目最核心的几个特点使用 STM32 作为主控通过红外接收头解析遥控器按键码再驱动多个继电器实现开关控制支持多路通道独立控制也可以扩展联动逻辑采用 NEC 红外协议是消费级遥控器最常用的协议整体工程代码量不大适合从零开始复刻。本文会从硬件选型、红外解码原理、软件框架、功能测试、常见问题排查这几个方面展开目标是让读者看完后能自己搭一套可运行的红外遥控多路开关系统而不是只停留在“看原理图”的阶段。适合阅读这篇内容的读者有两类一类是刚入门 STM32想把中断、定时器、串口这些知识点综合起来做一个小项目的学生另一类是准备做智能家居改造、想用红外遥控控制多个电器的 DIY 爱好者。文章会以 STM32F103C8T6 最小系统板为例讲解红外接收头使用常见的 HS0038 / VS1838B继电器模块使用多路低电平触发的光耦隔离继电器板。1. 核心能力速览能力项说明项目类型嵌入式开源项目 / 红外遥控多路开关控制器主控芯片STM32F103C8T6以常见最小系统板为例可移植到其他 STM32 型号红外接收方案HS0038 / VS1838B一体化红外接收头NEC 协议解码方式外部中断 定时器计时测量脉冲宽度开关通道以 8 路继电器为例可裁剪为 4 路 / 单路继电器触发方式低电平触发 / 高电平触发可选需根据模块实际电路配置开发环境Keil MDK 或 STM32CubeIDE配合 STM32CubeMX 初始化工程开发库标准外设库 / HAL 库均可本文示例以 HAL 库思路为主调试接口串口打印解码结果方便验证红外数据是否正确扩展能力可增加 OLED 显示当前状态、ESP8266 网络控制、按键本地控制适用场景智能家居灯光控制、实验室设备开关、课程设计、红外协议学习从能力表可以看出这个项目不需要太高的硬件成本。一块 STM32F103C8T6 核心板、一个红外接收头、一个多路继电器模块、若干杜邦线再加一个旧遥控器就能跑通整个流程。不需要示波器串口调试助手配合逻辑分析仪更好用没有逻辑分析仪也可以通过串口打印验证。2. 适用场景与使用边界这个项目适合解决什么问题第一它适合做“遥控集中控制”的小型场景。比如桌面上的台灯、风扇、显示器电源统一用一个遥控器控制不需要起身去按开关。第二它适合做 STM32 的综合练习因为红外解码涉及外部中断、定时器、GPIO 输入输出、串口通信几乎是 STM32 基础外设的集大成者。第三它可以作为智能家居网关的本地控制层后续加 ESP8266 或 ESP32 后就能通过 Wi-Fi 远程控制。不适合什么场景首先是高功率电器直接控制。继电器模块的触点电流一般只有 10A 左右直接控制空调、热水器这类大功率设备有安全隐患需要增加交流接触器或中间继电器。其次如果是想用手机 App 远程控制、语音控制那需要额外加上网络模块单纯的红外遥控方案满足不了。最后如果项目目的是学习 RTOS 或复杂状态机这个项目相对简单可能不太够。合规和安全边界要重点提醒。红外遥控本质上会发送按键码使用这个项目时需要注意只能对自己合法拥有的遥控器设备进行解码和学习不能用于复制他人设备遥控器、破解门禁遥控码等非授权用途。电路调试时要注意电源隔离继电器控制 220V 交流电器时必须确认接线正确、线径足够、外壳绝缘最好在断电状态下完成接线。嵌入式开发中安全永远排在功能前面。3. 环境准备与前置条件3.1 硬件清单硬件型号 / 规格数量作用STM32 最小系统板STM32F103C8T6 蓝色板1主控红外接收头HS0038 或 VS1838B1接收红外信号并解调为电平脉冲遥控器任意 NEC 协议红外遥控器1发送红外指令多路继电器模块8 路低电平触发 / 光耦隔离1控制负载开关面包板 / 杜邦线公对公、公对母若干搭建电路电源5V 2A 适配器供继电器1继电器模块供电串口工具USB-TTL如 CH3401调试串口打印解码结果ST-Link / J-Link下载调试器1烧录程序3.2 软件环境Windows / Linux 均可。Keil MDK 或 STM32CubeIDE。STM32CubeMX可选用于生成初始化代码。STM32F1xx 芯片支持包在 Keil Pack Installer 或 STM32CubeMX 中下载。串口调试助手如 SSCOM、XCOM。如果是标准库工程可以不用 CubeMX但需要自己手动配置工程模板。这里提一下库的选择。HAL 库的特点是代码可读性好CubeMX 配置外设方便适合快速验证功能标准外设库的特点是与底层寄存器更接近资料老但稳定。对于红外解码这类对时序敏感的操作两种库都能实现关键是用外部中断捕获边沿用定时器或 DWT 计数器测量脉冲宽度。3.3 端口准备调试时会用到串口和下载器。ST-Link 烧录一般占用 SWDIO、SWCLK 两个引脚串口调试占用一个 USART 的 TX、RX。如果和继电器控制引脚冲突需要调整引脚分配。本文示例中红外接收头接到 PA0串口使用 PA9TX、PA10RX继电器控制引脚使用 PC0~PC7这样基本不冲突。4. 硬件设计与接线4.1 引脚规划功能引脚说明红外接收头 DATAPA0设置为外部中断输入下降沿触发红外接收头 VCC3.3VHS0038 工作电压 2.7V~5.5V红外接收头 GNDGND共地继电器 IN1PC0第一路开关控制继电器 IN2PC1第二路开关控制继电器 IN3PC2第三路开关控制继电器 IN4PC3第四路开关控制继电器 IN5~IN8PC4~PC7第五至第八路开关控制LED 指示灯可选PB12接收红外信号时闪烁串口 TXPA9连接 USB-TTL 的 RX串口 RXPA10连接 USB-TTL 的 TX4.2 接线要点红外接收头是三个引脚的一体化元件正面凸起朝向自己时从左到右一般是 OUT、GND、VCC不同品牌可能有差异接线前要看数据手册或用万用表确认。OUT 引脚接 PA0VCC 接 3.3VGND 接 GND。这里建议给红外接收头并接一个 0.1uF 的退耦电容能减少电源噪声干扰提高遥控距离。继电器模块要特别注意供电。很多 8 路继电器模块需要 5V 甚至更高的驱动电压信号端通过光耦隔离输入为低电平时继电器吸合。如果你的继电器是低电平触发那么 STM32 引脚的默认输出要么设成高电平要么在初始化时把引脚置为高否则上电瞬间继电器会全部吸合。这是一个非常容易踩的坑。如果使用高电平触发的继电器模块需要在代码里把控制逻辑反过来。最稳妥的做法是先用一个 LED 串联电阻代替继电器做测试验证引脚输出状态正确后再接继电器避免调试过程中继电器频繁通断造成触点损坏。4.3 电源设计STM32 最小系统板一般通过 USB 供电即可。继电器模块需要单独供电尤其是多路同时吸合时电流可能到几百毫安。用同一个 USB 口同时给 STM32 和 8 路继电器供电容易导致电压跌落出现红外解码不稳定或继电器吸合不牢固的问题。建议用 5V 2A 适配器给继电器模块供电STM32 和继电器模块共地但电源分开。安全方面继电器模块的高压侧如果连接 220V 交流负载必须确保接线端子牢固、无裸露铜线并在调试阶段使用低压直流负载如 12V 灯泡代替交流负载测试。5. 软件设计与代码实现5.1 总体软件框架软件流程按以下顺序组织系统时钟初始化。GPIO 初始化红外接收引脚、继电器控制引脚、LED 指示灯。外部中断初始化PA0 下降沿触发。定时器初始化用基本定时器计时或者使用 SysTick 计数。串口初始化打印调试信息。主循环等待红外解码结果解析按键码执行开关动作。代码并不复杂核心难点在红外解码部分。NEC 协议要求测量脉冲宽度所以解码函数会频繁进入外部中断在中断里记录两次边沿之间的时间差然后根据时间差判断是引导码、逻辑 0 还是逻辑 1。5.2 NEC 红外协议原理NEC 协议是红外遥控最常见的协议之一多数国产遥控器和部分日系遥控器都使用它。NEC 协议的数据帧结构如下引导码9ms 高电平 4.5ms 低电平。地址码8 位大多数遥控器是 0x00。地址反码8 位。数据码8 位表示按键编号。数据反码8 位用于校验。结束位560us 高电平。数据位中的逻辑 0 和逻辑 1 通过低电平持续时间区分逻辑 0560us 高电平 560us 低电平。逻辑 1560us 高电平 1.68ms 低电平。还有一个特殊的是重复码。如果按住遥控器按键不放会每隔 110ms 发送一次重复码重复码的结构是 9ms 高电平 2.25ms 低电平 560us 高电平。代码中需要识别重复码并选择是否重复执行开关动作。对于开关控制来说通常忽略重复码只在第一次按下时切换状态。5.3 红外解码实现思路红外接收头输出的是反向电平空闲时为高电平收到信号时输出低电平脉冲。因此外部中断可以配置为下降沿触发在下降沿中断中读取当前定时器计数值再和上一次下降沿的计数值做差得到脉冲宽度。一个常用的解码状态机状态 0等待引导码。如果测量到约 9ms 高电平和 4.5ms 低电平时序进入数据接收状态。状态 1接收 32 位数据。每一位通过判断低电平持续时间是 560us 还是 1.68ms 来赋值 0 或 1。状态 2校验。检查地址反码和数据反码是否正确或者检查地址码是否匹配。状态 3输出数据到主循环。这种状态机可以用一个uint8_t变量表示步数用一个uint32_t变量保存接收到的数据。使用 HAL 库的HAL_GPIO_EXTI_Callback回调函数或者标准库的中断服务函数在其中完成计时和状态切换。5.4 示例代码框架下面给出一个简化版的红外解码边沿计时思路基于 HAL 库使用 SysTick 提供毫秒计数使用一个微秒级延时函数测量脉冲宽度。实际项目中更推荐使用硬件定时器的计数器精度更高。// 红外解码数据使用联合体方便按字节访问 typedef union { uint32_t value; struct { uint8_t addr; uint8_t addr_inv; uint8_t cmd; uint8_t cmd_inv; } byte; } IR_Data; volatile IR_Data ir_data; volatile uint8_t ir_step 0; volatile uint8_t ir_bit_count 0; volatile uint32_t ir_data_buffer 0; volatile uint32_t last_edge_time 0; volatile uint8_t ir_repeat 0; volatile uint8_t ir_ok 0;// 假设已经在外部中断回调中调用该函数 void IR_Decode_Edge(void) { uint32_t now Get_Tick_us(); uint32_t diff now - last_edge_time; last_edge_time now; switch (ir_step) { case 0: // 检测引导码9ms 高 4.5ms 低 // 这里简化处理实际需判断高低电平和时间窗口 if (diff 12000 diff 15000) { ir_step 1; ir_bit_count 0; ir_data_buffer 0; } else if (diff 11000 diff 12000) { // 重复码 ir_repeat 1; ir_ok 1; } break; case 1: // 数据位判断低电平时间 if (diff 1000 diff 1800) { ir_data_buffer (ir_data_buffer 1) | 1; // 逻辑 1 } else if (diff 400 diff 900) { ir_data_buffer (ir_data_buffer 1) | 0; // 逻辑 0 } ir_bit_count; if (ir_bit_count 32) { ir_data.value ir_data_buffer; ir_step 0; ir_ok 1; } break; default: break; } }上面的代码是示意性质实际工程中需要处理引导码的高低电平判断、边缘触发方向和脉冲宽度阈值。有一点必须指出NEC 解码对时间精度要求并不极端宽容范围比较大但如果在中断里做大量计算会影响其他外设的响应所以推荐“中断计时 主循环处理”的结构中断里只保存时间戳主循环完成解码判断。5.5 多路开关控制逻辑多路开关的逻辑可以设计为按键码映射表把遥控器上的数字键 1~8 映射到继电器通道 1~8。每个通道有一个状态变量channel_state[8]值为 0 或 1。按一下对应按键翻转该通道状态并更新 GPIO 输出。遥控器上的“*”键设计为全开“#”键设计为全关。映射表可以用switch-case实现也可以用查表法。这里给出一个简单的控制示例const uint8_t key_channel_map[8] { 0x45, 0x46, 0x47, 0x44, // 遥控器按键码需要根据实际遥控器修改 0x40, 0x41, 0x42, 0x43 }; void IR_Handle_Command(uint8_t cmd) { for (int i 0; i 8; i) { if (cmd key_channel_map[i]) { channel_state[i] !channel_state[i]; HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0 i, channel_state[i] ? GPIO_PIN_RESET : GPIO_PIN_SET); break; } } }注意这里使用了低电平触发继电器所以状态为 1 时输出低电平让继电器吸合。如果你的继电器是高电平触发代码里的GPIO_PIN_RESET和GPIO_PIN_SET需要互换。5.6 串口调试输出解码完成后通过串口打印地址码、数据码和校验结果。这是验证红外解码是否正确的关键手段。void IR_Handle_Data(void) { if (ir_ok) { ir_ok 0; if (ir_repeat) { printf([IR] repeat code\r\n); ir_repeat 0; return; } printf([IR] addr0x%02X, cmd0x%02X\r\n, ir_data.byte.addr, ir_data.byte.cmd); IR_Handle_Command(ir_data.byte.cmd); } }如果串口打印的地址码和数据码与你按下的遥控器按键一致说明解码链路是通的。如果完全没输出优先检查中断是否进入、引脚是否接对、串口波特率是否一致。6. 烧录与启动运行6.1 编译下载在 Keil 中完成编译后通过 ST-Link 下载程序到 STM32F103C8T6。下载设置里选择 SWD 模式如果板载了 ST-Link 就不需要额外接线。烧录完成后按复位键程序开始运行。6.2 启动过程观察程序上电后串口调试助手会输出一条初始化信息例如[SYSTEM] IR relay control started. [SYSTEM] Waiting for IR command...此时用遥控器对着红外接收头按下按键串口会打印对应的地址码和数据码。如果按下按键后串口没有反应按下面的步骤排查确认红外接收头的 OUT 引脚确实接在 PA0 上。确认外部中断初始化成功进入中断后 LED 指示灯是否有翻转。确认遥控器是 NEC 协议部分遥控器使用的是 RC5 协议时序不同。用手机摄像头对准红外接收头按下遥控器按键如果能看到遥控器发射管亮紫光说明遥控器本身在发送。6.3 控制继电器解码成功并完成按键映射后接上继电器模块和负载。按下遥控器数字键 1第一路继电器吸合LED 灯点亮再按一次继电器断开。这里的核心判断标准是解码正确、映射正确、继电器动作正确。7. 功能测试与效果验证7.1 红外解码验证测试目的确认 STM32 能正确解析 NEC 红外协议。操作步骤打开串口调试助手波特率 115200。遥控器对准红外接收头按下数字键 1。观察串口输出是否有 addr 和 cmd 打印。预期结果串口输出类似[IR] addr0x00, cmd0x45。同一个按键多次按下输出的 cmd 值稳定。判断标准如果连续按 5 次5 次 cmd 值都相同说明解码稳定。如果 cmd 值偶发错误可能是供电不稳或遥控器电池电压低。7.2 单路开关控制验证测试目的验证单路继电器动作。操作步骤代码中把按键码映射到通道 0。按下对应按键观察继电器是否吸合。再按一次观察是否释放。预期结果继电器每次切换LED 灯或万用表能观察到通断变化。7.3 多路开关联动验证测试目的验证多路独立控制和全开全关。操作步骤连续按下数字键 1~8观察 8 路继电器是否依次动作。按下“*”键观察所有继电器是否吸合。按下“#”键观察所有继电器是否释放。预期结果每一路都能独立翻转全开全关功能有效。如果某一路没有响应检查该路的 GPIO 引脚号和继电器模块的 IN 序号是否对应。7.4 快速按键与重复码验证测试目的验证连续快速按键时系统不卡死。操作步骤快速连续按同一个按键 10 次。观察继电器状态是否正确切换 10 次。按住按键不放 3 秒观察是否触发重复码重复码是否会导致状态连续翻转。预期结果快速按键时系统不崩溃每次按键都正确翻转一次。按住不放时只需处理第一次按键动作重复码不重复翻转继电器状态。如果在重复码阶段也翻转了状态需要在代码里增加重复码过滤。7.5 上电状态验证测试目的确认系统上电时继电器不会误吸合。操作步骤全部继电器接线完成后给系统上电。观察上电瞬间是否有继电器吸合声。预期结果上电后所有继电器保持断开状态。如果你在串口打印初始化信息之前继电器就吸合了说明 GPIO 默认电平没设置正确。解决方法是把继电器控制引脚初始化代码提前并在初始化完成前保持高电平输出或者干脆修改为高电平触发并默认输出低电平。8. 接口与批量任务这个项目本身不涉及 HTTP API 或 RESTful 接口。但从“多路开关控制系统”的角度看可以理解成两个层面的“批量任务”一是单次红外指令触发多路开关联动二是通过串口下发指令批量控制多个通道。8.1 红外联动指令在代码中增加一个联动映射表例如按下遥控器“播放/暂停”键同时切换第 1、3、5 路继电器。这种用法在场景控制里比较实用比如一键切换“电影模式”关闭主灯、打开氛围灯。void IR_Scene_Movie(void) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // 第1路开 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // 第3路关 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET); // 第5路开 }8.2 串口指令控制串口可以做成一个简单的指令控制接口。例如上位机发送ON,1开启第一路发送OFF,2关闭第二路发送ALL,ON全开。这种设计方便后续接入 ESP8266 或 Python 脚本进行自动化控制。void UART_Command_Parse(char *cmd) { if (strncmp(cmd, ON, 2) 0) { int ch cmd[3] - 0; if (ch 1 ch 8) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0 (ch - 1), GPIO_PIN_RESET); } } else if (strncmp(cmd, OFF, 3) 0) { int ch cmd[4] - 0; if (ch 1 ch 8) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0 (ch - 1), GPIO_PIN_SET); } } }8.3 扩展为网络控制如果后续想接入智能家居系统可以增加一个 ESP8266 模块通过串口与 STM32 通信。上位机或云平台下发指令到 ESP8266ESP8266 再通过 UART 转发给 STM32STM32 执行继电器动作。这个方案不需要改动已有的红外控制逻辑只需要在串口解析部分增加网络指令分支。9. 资源占用与性能观察9.1 存储资源占用STM32F103C8T6 有 64KB Flash 和 20KB SRAM。一个包含红外解码、串口打印、8 路继电器控制的基础工程使用 HAL 库编译后Flash 占用大约在 15KB~25KB 之间RAM 占用通常在 1KB 以内。如果使用标准库占用会更小一些。如果代码超过 64KB说明工程里加入了大量不必要的组件需要检查是否有重复编译或未用到的中间层。9.2 中断响应与实时性NEC 解码过程中外部中断会频繁触发每收到一帧数据大约触发 70 多次中断。如果系统里同时运行着定时器中断、串口中断红外解码的精度可能受到影响。改善方法外部中断回调中只更新时间戳不做解码。解码状态机放在主循环中运行。关闭不需要的中断或者降低其他中断的频率。9.3 继电器吸合功耗继电器线圈在吸合瞬间电流较大多路同时吸合时模块的功耗明显增加。实测中普通 5V 继电器单路吸合电流在 60mA~100mA 左右8 路同时吸合可能达到 500mA 以上。如果把 8 路继电器全部接到 STM32 的 3.3V 或 USB 5V 上会导致电压明显跌落导致红外接收头灵敏度下降。解决方法是给继电器模块单独供电并确保 5V 电源输出能力在 1A 以上。9.4 降低功耗与误动作如果系统长期待机可以在无红外信号时让 STM32 进入睡眠模式通过外部中断唤醒。但这种设计会增加代码复杂度课程设计阶段不建议优先实现。更实用的做法是加上电指示灯、按键防抖、继电器动作延时避免继电器在信号不稳定时高频通断。10. 常见问题与排查方法问题现象可能原因排查方式解决方案红外接收完全无反应红外接收头引脚接错、供电不足、遥控器不匹配检查 OUT 引脚是否接对用手机摄像头确认遥控器是否发射对照数据手册重新接线更换红外接收头串口输出乱码波特率不匹配、系统时钟不对核对串口配置与调试助手波特率统一设置为 115200 8N1检查外部晶振频率解码数据不稳定电源电压跌落、红外接收头离干扰源太近示波器观察接收头输出波形单独供电红外接收头并联 0.1uF 退耦电容继电器上电就吸合引脚默认电平不对、继电器触发方式判断错误上电瞬间观察 GPIO 电平先把继电器控制引脚初始化为非触发电平或改用相反的触发方式某一两路继电器不动作GPIO 引脚序号错误、继电器模块对应通道损坏用万用表测量引脚电平变化核对代码中 GPIO_PIN_0 左移位数和硬件接线按住按键状态反复切换重复码没有过滤串口打印是否出现 repeat code检测到重复码时不处理开关动作遥控距离特别短红外接收头供电不足、接收头朝向不对、环境光干扰减小距离测试观察接收头供电电压加退耦电容调整接收头方向避免阳光直射程序跑飞 / 死机供电不稳、看门狗未配置但程序卡死复位后观察串口打印检查电源、减少主循环阻塞、增加异常打印11. 最佳实践与使用建议第一先验证解码再控制继电器。很多初学者一上来就接继电器解码还没跑通就怀疑继电器模块坏了最后发现是红外接收头根本没接对。建议分三步走先用串口打印解码结果再用 LED 模拟继电器输出最后再接入真实继电器模块。第二保持一套最小可运行配置。把红外解码、串口、继电器控制写成独立文件比如ir_decode.c、relay_ctrl.c方便后续移植到其他 STM32 型号。不要把所有代码堆在main.c里否则排查问题时会非常痛苦。第三预留扩展引脚。在规划引脚时不要把 STM32 的 PA1、PA2、PB0、PB1 全部占用至少留出几个空闲引脚后续加 OLED、按键、ESP8266 时不需要重新布线。第四注意继电器模块的触发方式。不同厂家甚至同一厂家不同批次的继电器模块原理图可能不同有的低电平触发有的高电平触发。必须用万用表测量 IN 脚悬空时的电平或者直接查看模块原理图。接反了会出现“上电全开”或“怎么都吸合不了”的怪问题。第五版权与授权意识。红外解码本身是标准协议研究但如果你要复制某个品牌遥控器的完整按键码表要确认用途合法不能用于仿冒或绕过授权控制。调试时使用自己购买的设备遥控器不针对他人设备进行破解。第六安全用电。所有与 220V 交流电相关的接线必须在断电状态下操作继电器输出端要使用合格的接线端子不能裸露铜线负载功率不能超过继电器标称值。建议在课程设计或个人 DIY 阶段使用 12V 低压灯泡或 LED 灯带做测试负载。12. 总结与下一步这个项目最值得尝试的点是把 STM32 的多个基础外设综合到了一起。红外解码看起来玄学实际核心就是测量脉冲宽度一旦用串口打印出稳定的地址码和数据码你对中断和定时器的理解会上一个台阶。先验证红外解码这是整个系统的地基。串口能打印出按键码后面的继电器控制就只是简单的 GPIO 操作了。如果串口没有输出不要急着改继电器代码优先检查接线、电源和协议类型。最容易踩的坑有两个一是继电器触发方式的判断错误二是把多路继电器和 STM32 用同一个 USB 口供电导致复位。这两个坑踩过之后你会对嵌入式电源设计有更深的体会。下一步的扩展方向也很多增加 OLED 显示当前开关状态通过 ESP8266 接入 Home Assistant 或巴法云做远程控制把红外接收改成多协议解码支持 RC5、Sony 协议或者加入定时开关功能。如果准备参加比赛或完成课程设计可以把“红外遥控 手机 APP 网络控制”做成三合一方案功能完整度会更高。这个项目的代码量不大但涉及的链路很完整作为 STM32 入门到综合实战的过渡项目非常合适。建议收藏备用直接对照着搭一套硬件环境跑起来。