1. 项目概述一个“民主化”的空调遥控器在开放式的办公空间里空调温度设定常常引发“战争”。有人觉得冷有人觉得热遥控器还经常不知所踪。这个项目就是为了解决这个痛点而生的一个基于STM32微控制器的“民主化”空调遥控系统。它的核心思想很简单——让在场的每个人通过手机App投票决定温度系统根据投票结果比如计算平均值或中位数自动调整空调设定实现“少数服从多数”的温控民主。我选择使用ST的STM32WB5MM-DK开发板作为核心因为它集成了BLE蓝牙低功耗功能非常适合连接多部手机。目标空调是Atlantic Fujitsu的某一型号这意味着我需要先破解它的红外遥控协议。整个系统设计为双模式运行手动模式下它就是一个功能完备的实体遥控器BLE模式下则开启民主投票功能最多支持8部手机同时连接并根据在场人员的投票动态调整温度。这个项目的价值不仅在于解决一个具体的办公环境问题更在于它提供了一个可复用的框架。除了针对特定空调的红外编码部分其多设备连接、投票逻辑、用户界面等模块完全可以移植到其他需要群体决策的物联网控制场景中。2. 核心设计思路与架构解析2.1 为什么选择这样的技术栈选择STM32WB5MM-DK是经过深思熟虑的。首先STM32WB系列是ST推出的双核无线MCU一个Cortex-M4内核处理应用一个Cortex-M0内核专用于处理蓝牙协议栈。这种硬件隔离的设计能确保无线连接的稳定性和实时性不会因为应用层的复杂逻辑而断连对于需要同时连接多部手机的场景至关重要。其次这块开发板自带OLED屏幕、按键、飞行时间ToF距离传感器几乎为我们这个项目量身定做。OLED用于显示状态和菜单按键用于手动操作和导航ToF传感器则被创新性地用作“非接触式旋钮”通过手势距离来精细调节数值这比单纯的加减按键体验好得多。最后使用FreeRTOS实时操作系统是管理多任务的必然选择。系统中有多个需要并行运行的任务处理用户界面HMI、监听按键、读取ToF传感器、测量环境温度、运行BLE服务、生成红外信号等。FreeRTOS的任务调度、消息队列和信号量机制能让这些任务井然有序地协作代码结构也更清晰、易于维护。2.2 系统工作模式详解系统设计了两种核心工作模式以覆盖不同场景的需求手动模式此模式下BLE投票功能被禁用。用户直接通过设备上的物理按键和ToF传感器来设置温度、模式、风速等所有参数就像使用一个普通的智能遥控器。设置完成后设备会立即通过红外发射管将指令发送给空调。这个模式适用于临时单独使用空间或者网络出现问题时作为备用方案。BLE民主模式这是项目的核心模式。设备启动BLE广播附近的同事可以用手机App待开发搜索并连接到名为“Demo_clim”的设备。连接后App上会显示当前环境温度和可设定的温度范围用户可以进行“投票”。设备端会持续扫描周围的蓝牙信号强度RSSI以此粗略判断用户是否在附近例如信号强度低于某个阈值则认为用户已离开。温度设定点Setpoint的计算逻辑是关键目前考虑两种算法平均值计算所有“在场”用户投票温度的平均值。优点是计算简单能反映整体倾向缺点是容易被极端值比如个别人特别怕冷或怕热带偏。中位数将所有“在场”用户的投票温度排序取中间值。优点是对异常值不敏感更能代表大多数人的“舒适区间”。 系统会根据环境温度自动判断空调应处于制冷还是制热模式然后应用计算出的设定温度。2.3 软件架构与任务划分基于FreeRTOS我将系统功能分解为以下几个独立的任务每个任务负责一个明确的职能看门狗任务这是一个系统健康守护者。它定期检查其他所有关键任务是否在正常运行通过接收任务发送的“心跳”信号。如果某个任务卡死无法喂狗看门狗任务会触发系统复位防止设备“死机”。HMI任务人机交互的核心。它管理OLED屏幕的显示、处理两个按键的输入事件、接收来自ToF任务的距离数据。它实现了基于“屏幕”和“控件”的图形界面可以在不同设置页面间切换并处理数值的编辑过程。按键任务独立扫描两个物理按键消抖后将按键事件如按下、释放、长按通过消息队列发送给HMI任务实现响应式交互。ToF任务负责初始化并周期性地读取VL53L0X等ToF传感器的距离值。在非编辑模式下这个数据可能用于判断用户是否靠近在编辑模式下精确的距离值被映射为进度条用于无接触调节数值。温度传感器任务周期性地读取环境温度传感器如ST的HTS221的数据并进行简单的软件滤波例如移动平均滤波以消除抖动然后将稳定的温度值发送给主控任务。红外任务这是与具体空调型号强相关的部分。它接收来自主控任务的指令温度、模式等按照逆向工程得到的Atlantic空调协议组装数据帧、计算校验和并调制生成对应的38kHz载波红外信号通过GPIO驱动红外发射管发出。BLE任务负责初始化和管理蓝牙协议栈广播设备信息创建GATT服务如环境温度读取服务并处理来自手机App的连接、数据读写请求。目前该任务仅实现了温度上报完整的投票指令接收功能是下一步开发重点。主控任务系统的“大脑”。它接收来自HMI任务的用户设定值或来自BLE任务的投票计算结果结合温度任务提供的环境温度进行逻辑判断例如决定制冷/制热模式然后将最终的执行指令分发给红外任务。同时它也将系统状态反馈给HMI任务进行显示。这种模块化、任务化的设计使得代码耦合度低调试方便未来增加新功能如定时开关、场景模式也只需新增或修改特定任务即可。3. 关键实现细节与实操要点3.1 红外协议逆向工程全记录这是项目中最具挑战性也最有乐趣的部分。要让STM32板子控制空调首先得学会说它的“语言”——即红外遥控协议。3.1.1 信号捕获选择合适的“窃听”工具有两种主流方法捕获红外信号使用一体化红外接收头模块这种模块三根线VCC GND OUT价格低廉使用方便。它内部已经完成了对38kHz载波的解调输出的是纯净的数字信号高低电平可以直接接入单片机的IO口或逻辑分析仪。缺点是你看不到原始的载波波形无法直接得知载波频率。直接探测红外LED引脚拆开原装遥控器用逻辑分析仪的探头直接夹在红外发射LED的两个引脚上。这样能看到包含载波的原始信号。你需要自己从调制信号中解析出数据位。如果条件允许可以同时接上接收头模块和LED对比着看理解会更深刻。注意如果使用两个独立的设备如逻辑分析仪和遥控器主板务必用导线将它们的“地”连接在一起确保共地否则信号可能会乱跳或无法捕获。我手头有一台DSLogic逻辑分析仪通道数多适合这种多线测量。但对于这个任务一个8通道、24MHz采样率的廉价逻辑分析仪完全够用配合开源的PulseViewSigrok软件即可。3.1.2 捕获设置与技巧在逻辑分析仪软件中关键要平衡采样率和缓冲区大小。红外载波通常在38kHz左右根据奈奎斯特定理采样率至少需要76kHz。为了留有余量并看清细节我设置为1MHz或更高。缓冲区要能容纳一次完整的按键发射序列。Atlantic遥控器在按键后约有1-2秒的延迟才发射所以我设置了10秒的捕获时间确保能抓到完整信号。3.1.3 协议解码从波形到字节捕获到一堆高低电平的脉冲后手动解码是噩梦。幸运的是PulseView和DSView这类软件支持用Python编写解码器。我观察波形发现它很像索尼的SIRC协议但时序不同。于是我在SIRC解码器的基础上修改了时序参数成功将脉冲流解码成了看得懂的字节数据。Atlantic协议的一帧数据以一个长的起始信号开始载波3.8ms 停顿1.5ms。每个数据位由一段固定长度的载波400us和一段不同长度的停顿来表示逻辑“0”停顿400us逻辑“1”停顿1ms。这就是典型的“脉冲距离编码”。3.1.4 数据映射与校验和破解解码出字节后下一步是找出每个字节对应的功能。方法是控制变量法固定其他所有设置只改变一个参数比如温度然后对比多次捕获的数据帧。例如我分别捕获了设定温度为21°C、22°C、23°C时的信号。对比解码后的数据发现某一字节的高4位bit7-bit4依次是5 6 7。这显然与温度相关。进一步测试发现当设定为16°C时这个值是0。于是规律就出来了发送值 设定温度 - 16。这样21°C就对应发送值5。更棘手的是校验和。数据帧的末尾通常有1-2个字节用于校验确保传输无误。我尝试使用reveng这类CRC逆向工具但没能匹配出标准算法。于是转而进行人工分析观察当数据部分微小变化时校验字节的变化规律。我发现Atlantic协议使用了两个独立的4位校验和分别保护数据帧的高4位部分和低4位部分。它们的初始值都是0b111115算法是递减式校验和 15 - (所有被保护数据位的和)。如果结果小于0则循环回15继续减。通过大量数据验证后这个算法被确认。3.2 用户界面设计与交互逻辑HMI人机界面是用户与设备直接交互的窗口设计需要直观且高效。3.2.1 屏幕组件化设计我没有使用复杂的GUI库而是自己实现了一个轻量级的控件系统。屏幕由几个基本部分组成标题栏顶部区域显示当前屏幕的名称如“温度设置”。状态栏底部区域固定显示关键信息当前控制模式MANUAL/BLE、空调运行状态OFF/COOL/HEAT、以及当前温度设定点。这让用户在任何界面下都能一眼看到核心状态。内容区中间大部分区域根据不同的设置页面动态加载不同的控件如数值显示框、进度条、选项列表等。3.2.2 创新的交互方式按键手势设备只有两个按键B1 B2和一个ToF距离传感器却要完成复杂的设置。B1左键在浏览模式下用于在多个设置屏幕间循环切换在编辑模式下则用于取消当前编辑并跳转到下一个屏幕。B2右键在浏览模式下按下即进入当前焦点控件的编辑状态如果该控件允许编辑被编辑的控件会有边框高亮在编辑模式下按下则确认当前修改的值。ToF传感器这是交互的亮点。进入编辑模式后例如编辑温度屏幕下方会出现一个水平进度条。用户无需触摸设备只需将手在传感器上方前后移动改变手与传感器的距离进度条就会随之变化从而连续、无级地调整数值。这比反复按按键“加一减一”要快捷和精准得多。3.3 蓝牙多设备连接管理STM32WB的蓝牙协议栈已经处理了底层的连接管理。我们的任务是在应用层实现多设备连接和简单的在场判断。连接管理协议栈支持多个并发连接通常8个。我们需要维护一个连接句柄列表。当手机App发起连接时BLE任务会收到回调将新设备的句柄加入列表断开时则移除。在场判断这是一个简化设计。我们通过读取每个已连接设备的接收信号强度指示来粗略估计距离。在App端可以设计为当用户打开App并进入投票界面时才认为该用户“在场”。或者在设备端设置一个RSSI阈值只有当信号强度高于此阈值意味着设备在较近距离内才将该用户的投票计入有效票。这种方法不精确但对于办公室场景设备固定人员活动范围有限是一个低成本、可用的方案。数据同步设备端需要定义一个GATT特征Characteristic用于接收投票数据。手机App以“写”的方式将用户选择的温度值发送过来。同时设备可以定义另一个特征以“通知”的方式主动向所有已连接的手机推送当前的环境温度、投票结果或系统模式保持多端信息同步。4. 开发环境搭建与代码结构导读4.1 开发工具链准备项目基于STM32CubeIDE V1.13.2构建。这是一款ST官方推出的免费集成开发环境基于Eclipse集成了CubeMX配置工具、编译器、调试器对STM32开发非常友好。安装STM32CubeIDE从ST官网下载并安装。导入项目在IDE中选择“File - Import - Existing Projects into Workspace”然后定位到项目根目录下的Sources/MCU/BLE_Freertos文件夹。这个文件夹结构是CubeIDE的标准项目结构。解决可能的编译问题项目说明中特别提到由于手动修改了spi.c和i2c.c以移除自动生成的初始化函数MX_SPI1_InitMX_I2C3_Init如果重新用CubeMX生成代码需要注意不要覆盖这些修改或者确保HAL库文件被正确链接。4.2 项目代码目录结构解析清晰的目录结构是大型项目可维护性的基础。本项目结构如下Elektor_Demo_Clim/ ├── Documentation/ # 项目文档 │ ├── Datasheets/ # STM32等芯片的数据手册 │ ├── Internal_Documentation/ # 内部编码规范与模板 │ ├── Reverse_atlantic_protocol/# 红外协议逆向工程的所有捕获数据和解析笔记 │ └── Technical_Documentation/ # 软件架构设计文档含PlantUML图 ├── Sources/ │ ├── MCU/ │ │ └── BLE_Freertos/ # 主工程目录STM32CubeIDE项目 │ │ ├── Core/ │ │ │ ├── Inc/ # 头文件 │ │ │ ├── Src/ # 主循环、硬件初始化等 │ │ │ └── task/ # **核心**所有FreeRTOS任务源码 │ │ │ ├── tsk_hmi.c # HMI任务 │ │ │ ├── tsk_ir_atl.c # Atlantic红外协议任务 │ │ │ ├── tsk_ble.c # BLE任务 │ │ │ └── ... # 其他任务 │ │ ├── 3rdparty/ # 第三方库单色OLED图形库和控件库 │ │ └── STM32_WPAN/ # STM32无线协议栈中间件 │ └── tools/ # 实用工具如为DSView写的红外解码器脚本 └── Bin/ └── MCU/ # 存放编译好的.hex固件文件重点关注的目录Core/task/这里是所有业务逻辑所在。每个.c文件对应一个FreeRTOS任务职责单一通过消息队列和事件标志组进行通信。3rdparty/里面的图形库是针对小内存、单色屏优化的比通用的LVGL或emWin更轻量适合本项目。Documentation/Reverse_atlantic_protocol/如果你要适配其他品牌空调这里的逆向工程方法论和原始数据将是宝贵参考。4.3 系统初始化与任务启动流程理解启动流程对调试至关重要。在main.c的main()函数中顺序大致如下HAL初始化HAL_Init()初始化硬件抽象层。系统时钟配置SystemClock_Config()确保CPU和外围总线运行在正确频率。外设初始化通过CubeMX生成的代码初始化GPIO、I2C连接OLED和温度传感器、SPI可能连接ToF、定时器用于红外载波生成等。FreeRTOS初始化创建任务所需的内存管理、队列等。创建所有应用任务按优先级从低到高或按依赖关系创建看门狗、HMI、按键、温度、红外、BLE等任务。优先级需要仔细设计例如处理用户输入的HMI任务和红外发送任务需要较高响应优先级。启动调度器osKernelStart()之后FreeRTOS接管CPU开始在多任务间调度。5. 调试心得与常见问题排查在实际开发中我遇到了不少坑这里分享一些典型的排查思路和解决方法。5.1 红外发射无反应或空调不识别这是最可能遇到的问题。检查硬件连接首先确认红外发射管的正负极没有接反限流电阻值合适通常100-330欧姆。用手机摄像头对准发射管按下按键时能看到闪烁的紫光说明硬件通路基本正常。验证载波频率空调遥控常用38kHz但可能是36kHz 40kHz等。用逻辑分析仪或示波器测量驱动红外管的PWM输出频率。STM32的定时器PWM输出精度很高重点检查定时器分频和自动重载值的计算是否正确。核对协议细节起始码长度是否精确我遇到的Atlantic协议起始码是3.8ms高1.5ms低误差太大空调可能不认。逻辑电平定义“0”和“1”的高低电平时间是否与解码时的一致常见错误是弄反了。重复码长按按键时原装遥控器是连续发送完整帧还是只发送一个简短的重复码需要模拟这个行为。校验和这是最大的坑。务必用多个不同的数据样本验证你的校验和算法。一个字节算错整个帧都会被空调丢弃。可以先将捕获到的原装遥控器数据帧含校验和硬编码到程序里发送如果空调能响应再切换到动态计算校验和。5.2 FreeRTOS任务卡死或系统重启堆栈溢出这是多任务系统最常见的崩溃原因。在STM32CubeIDE中可以在FreeRTOSConfig.h中开启configCHECK_FOR_STACK_OVERFLOW选项。当检测到溢出时会触发钩子函数方便定位是哪个任务出了问题。适当增加该任务的堆栈大小。看门狗复位如果开启了硬件看门狗IWDG确保每个需要监控的任务都能定期“喂狗”。在我的设计中由独立的看门狗任务统一管理。检查是否所有任务都正确地向看门狗任务发送了存活信号。资源竞争如果多个任务如HMI和BLE同时访问同一个硬件外设如I2C必须使用互斥锁Mutex。我修改了HAL I2C驱动在其内部加入了RTOS互斥锁确保线程安全。优先级反转如果高优先级任务等待一个低优先级任务占有的资源如信号量而该低优先级任务又被中优先级任务抢占就会导致高优先级任务无限期等待。合理设置优先级或使用优先级继承互斥锁。5.3 BLE连接不稳定或手机搜不到设备广播参数检查广播间隔Advertising Interval。间隔太短如20ms耗电间隔太长如几秒则手机扫描时可能错过。100ms到1s是常用范围。确保广播数据包中包含了完整的设备名称和需要的服务UUID。连接参数连接建立后主设备手机和从设备STM32会协商连接参数包括连接间隔、从设备延迟、监督超时。STM32WB作为从设备可以提出连接参数更新请求。如果连接间隔设得太长数据传输会不实时太短则增加功耗。需要根据应用需求在功耗和响应速度间权衡。内存不足每个BLE连接都会消耗RAM。如果计划连接8个设备需要在FreeRTOSConfig.h中为BLE任务分配足够的堆栈和堆内存。同时检查协议栈配置中定义的最大连接数是否足够。天线与干扰确保开发板上的蓝牙天线区域没有被金属遮挡。2.4GHz频段容易受到Wi-Fi、微波炉等干扰尽量远离强干扰源。5.4 ToF传感器读数不准或跳动大电源噪声ToF传感器对电源纹波敏感。确保其供电引脚有足够的去耦电容通常手册会推荐一个10uF和一个0.1uF的电容并联。I2C上拉电阻STM32开发板上的I2C总线通常已接上拉电阻如4.7kΩ。如果自己布线必须接上拉电阻阻值根据总线速度和线长选择通常在2.2kΩ到10kΩ之间。软件滤波传感器原始数据难免有跳动。在任务中不要直接使用单次读数而应采用软件滤波。最简单有效的是移动平均滤波维护一个包含最近N次读数的小数组每次取平均值输出。N的大小根据采样周期和响应速度要求调整。环境光干扰强光特别是阳光可能会干扰ToF传感器的红外光测量。在传感器窗口上方加一个短的遮光罩如一小段黑色热缩管可以有效改善。5.5 功耗优化考虑虽然目前是插电演示但若未来改为电池供电功耗至关重要。动态频率调整在系统空闲或仅运行后台任务如看门狗时可以通过HAL_RCC_ClockConfig降低系统主频。外设时钟门控不使用的串口、SPI、ADC等外设及时关闭其时钟__HAL_RCC_XXX_CLK_DISABLE()。低功耗模式在BLE模式下当没有手机连接且处于非投票时段可以让STM32WB进入低功耗的停止模式Stop Mode此时BLE协议栈由协处理核维持主核暂停功耗可降至微安级。有连接事件或按键中断时再唤醒。屏幕与传感器管理OLED屏幕在无操作一段时间后可以关闭。ToF传感器可以设置为间歇性测量而不是持续测量。6. 项目总结与未来演进方向经过一段时间的开发这个民主空调遥控器的核心骨架已经搭建完成红外协议成功逆向并实现、多任务系统稳定运行、基础HMI和BLE框架就绪。它已经可以作为一个功能强大的万能红外遥控器来使用。我个人在实际操作中的体会是嵌入式物联网项目的难点往往不在于单一技术的深度而在于多种技术的集成与稳定协作。FreeRTOS是多任务管理的利器但必须对任务优先级、同步通信有清晰的设计。无线通信BLE的调试比有线复杂需要更多的耐心和工具如手机端BLE调试App、空中抓包器。而逆向工程则像侦探破案需要细致的观察、合理的假设和反复的验证。最后再分享一个小技巧在开发类似项目时建立一个清晰的“调试输出”系统非常重要。我利用STM32的串口UART定义了几个不同等级的调试信息宏如DEBUG_ERROR DEBUG_INFO DEBUG_RAW可以方便地在不同开发阶段打开或关闭特定模块的日志这对定位跨任务、跨模块的问题有奇效。这个项目还有很大的演进空间也是我下一步计划手机App开发这是实现“民主”功能的关键一环。计划使用Flutter或React Native开发一个跨平台App界面简洁主要功能就是显示当前环境温度、进行温度投票、查看实时投票结果。智能在场判定目前的RSSI方案比较粗糙。可以结合手机App当用户打开App并进入办公室地理围栏Geofencing时自动标记为“在场”或者利用BLE的定向功能如果手机和硬件支持进行更精准的接近判断。数据持久化与场景化将用户偏好、定时任务如工作日9点自动开启空调保存到STM32的Flash或外置EEPROM中实现断电记忆。甚至可以创建“会议模式”、“午休模式”等场景一键切换。云端同步与远程管理增加Wi-Fi模块或利用STM32WB的某些型号将数据同步到云端。管理员可以远程查看办公室温度状况、能耗统计甚至在特殊情况下进行远程干预。支持更多空调品牌将红外协议编码部分设计成插件化结构。通过配置文件或学习功能让这个设备能够控制市面上绝大多数品牌的空调真正成为一个通用的“智能红外网关”。
基于STM32与FreeRTOS的智能空调遥控系统设计与实现
发布时间:2026/5/26 1:11:13
1. 项目概述一个“民主化”的空调遥控器在开放式的办公空间里空调温度设定常常引发“战争”。有人觉得冷有人觉得热遥控器还经常不知所踪。这个项目就是为了解决这个痛点而生的一个基于STM32微控制器的“民主化”空调遥控系统。它的核心思想很简单——让在场的每个人通过手机App投票决定温度系统根据投票结果比如计算平均值或中位数自动调整空调设定实现“少数服从多数”的温控民主。我选择使用ST的STM32WB5MM-DK开发板作为核心因为它集成了BLE蓝牙低功耗功能非常适合连接多部手机。目标空调是Atlantic Fujitsu的某一型号这意味着我需要先破解它的红外遥控协议。整个系统设计为双模式运行手动模式下它就是一个功能完备的实体遥控器BLE模式下则开启民主投票功能最多支持8部手机同时连接并根据在场人员的投票动态调整温度。这个项目的价值不仅在于解决一个具体的办公环境问题更在于它提供了一个可复用的框架。除了针对特定空调的红外编码部分其多设备连接、投票逻辑、用户界面等模块完全可以移植到其他需要群体决策的物联网控制场景中。2. 核心设计思路与架构解析2.1 为什么选择这样的技术栈选择STM32WB5MM-DK是经过深思熟虑的。首先STM32WB系列是ST推出的双核无线MCU一个Cortex-M4内核处理应用一个Cortex-M0内核专用于处理蓝牙协议栈。这种硬件隔离的设计能确保无线连接的稳定性和实时性不会因为应用层的复杂逻辑而断连对于需要同时连接多部手机的场景至关重要。其次这块开发板自带OLED屏幕、按键、飞行时间ToF距离传感器几乎为我们这个项目量身定做。OLED用于显示状态和菜单按键用于手动操作和导航ToF传感器则被创新性地用作“非接触式旋钮”通过手势距离来精细调节数值这比单纯的加减按键体验好得多。最后使用FreeRTOS实时操作系统是管理多任务的必然选择。系统中有多个需要并行运行的任务处理用户界面HMI、监听按键、读取ToF传感器、测量环境温度、运行BLE服务、生成红外信号等。FreeRTOS的任务调度、消息队列和信号量机制能让这些任务井然有序地协作代码结构也更清晰、易于维护。2.2 系统工作模式详解系统设计了两种核心工作模式以覆盖不同场景的需求手动模式此模式下BLE投票功能被禁用。用户直接通过设备上的物理按键和ToF传感器来设置温度、模式、风速等所有参数就像使用一个普通的智能遥控器。设置完成后设备会立即通过红外发射管将指令发送给空调。这个模式适用于临时单独使用空间或者网络出现问题时作为备用方案。BLE民主模式这是项目的核心模式。设备启动BLE广播附近的同事可以用手机App待开发搜索并连接到名为“Demo_clim”的设备。连接后App上会显示当前环境温度和可设定的温度范围用户可以进行“投票”。设备端会持续扫描周围的蓝牙信号强度RSSI以此粗略判断用户是否在附近例如信号强度低于某个阈值则认为用户已离开。温度设定点Setpoint的计算逻辑是关键目前考虑两种算法平均值计算所有“在场”用户投票温度的平均值。优点是计算简单能反映整体倾向缺点是容易被极端值比如个别人特别怕冷或怕热带偏。中位数将所有“在场”用户的投票温度排序取中间值。优点是对异常值不敏感更能代表大多数人的“舒适区间”。 系统会根据环境温度自动判断空调应处于制冷还是制热模式然后应用计算出的设定温度。2.3 软件架构与任务划分基于FreeRTOS我将系统功能分解为以下几个独立的任务每个任务负责一个明确的职能看门狗任务这是一个系统健康守护者。它定期检查其他所有关键任务是否在正常运行通过接收任务发送的“心跳”信号。如果某个任务卡死无法喂狗看门狗任务会触发系统复位防止设备“死机”。HMI任务人机交互的核心。它管理OLED屏幕的显示、处理两个按键的输入事件、接收来自ToF任务的距离数据。它实现了基于“屏幕”和“控件”的图形界面可以在不同设置页面间切换并处理数值的编辑过程。按键任务独立扫描两个物理按键消抖后将按键事件如按下、释放、长按通过消息队列发送给HMI任务实现响应式交互。ToF任务负责初始化并周期性地读取VL53L0X等ToF传感器的距离值。在非编辑模式下这个数据可能用于判断用户是否靠近在编辑模式下精确的距离值被映射为进度条用于无接触调节数值。温度传感器任务周期性地读取环境温度传感器如ST的HTS221的数据并进行简单的软件滤波例如移动平均滤波以消除抖动然后将稳定的温度值发送给主控任务。红外任务这是与具体空调型号强相关的部分。它接收来自主控任务的指令温度、模式等按照逆向工程得到的Atlantic空调协议组装数据帧、计算校验和并调制生成对应的38kHz载波红外信号通过GPIO驱动红外发射管发出。BLE任务负责初始化和管理蓝牙协议栈广播设备信息创建GATT服务如环境温度读取服务并处理来自手机App的连接、数据读写请求。目前该任务仅实现了温度上报完整的投票指令接收功能是下一步开发重点。主控任务系统的“大脑”。它接收来自HMI任务的用户设定值或来自BLE任务的投票计算结果结合温度任务提供的环境温度进行逻辑判断例如决定制冷/制热模式然后将最终的执行指令分发给红外任务。同时它也将系统状态反馈给HMI任务进行显示。这种模块化、任务化的设计使得代码耦合度低调试方便未来增加新功能如定时开关、场景模式也只需新增或修改特定任务即可。3. 关键实现细节与实操要点3.1 红外协议逆向工程全记录这是项目中最具挑战性也最有乐趣的部分。要让STM32板子控制空调首先得学会说它的“语言”——即红外遥控协议。3.1.1 信号捕获选择合适的“窃听”工具有两种主流方法捕获红外信号使用一体化红外接收头模块这种模块三根线VCC GND OUT价格低廉使用方便。它内部已经完成了对38kHz载波的解调输出的是纯净的数字信号高低电平可以直接接入单片机的IO口或逻辑分析仪。缺点是你看不到原始的载波波形无法直接得知载波频率。直接探测红外LED引脚拆开原装遥控器用逻辑分析仪的探头直接夹在红外发射LED的两个引脚上。这样能看到包含载波的原始信号。你需要自己从调制信号中解析出数据位。如果条件允许可以同时接上接收头模块和LED对比着看理解会更深刻。注意如果使用两个独立的设备如逻辑分析仪和遥控器主板务必用导线将它们的“地”连接在一起确保共地否则信号可能会乱跳或无法捕获。我手头有一台DSLogic逻辑分析仪通道数多适合这种多线测量。但对于这个任务一个8通道、24MHz采样率的廉价逻辑分析仪完全够用配合开源的PulseViewSigrok软件即可。3.1.2 捕获设置与技巧在逻辑分析仪软件中关键要平衡采样率和缓冲区大小。红外载波通常在38kHz左右根据奈奎斯特定理采样率至少需要76kHz。为了留有余量并看清细节我设置为1MHz或更高。缓冲区要能容纳一次完整的按键发射序列。Atlantic遥控器在按键后约有1-2秒的延迟才发射所以我设置了10秒的捕获时间确保能抓到完整信号。3.1.3 协议解码从波形到字节捕获到一堆高低电平的脉冲后手动解码是噩梦。幸运的是PulseView和DSView这类软件支持用Python编写解码器。我观察波形发现它很像索尼的SIRC协议但时序不同。于是我在SIRC解码器的基础上修改了时序参数成功将脉冲流解码成了看得懂的字节数据。Atlantic协议的一帧数据以一个长的起始信号开始载波3.8ms 停顿1.5ms。每个数据位由一段固定长度的载波400us和一段不同长度的停顿来表示逻辑“0”停顿400us逻辑“1”停顿1ms。这就是典型的“脉冲距离编码”。3.1.4 数据映射与校验和破解解码出字节后下一步是找出每个字节对应的功能。方法是控制变量法固定其他所有设置只改变一个参数比如温度然后对比多次捕获的数据帧。例如我分别捕获了设定温度为21°C、22°C、23°C时的信号。对比解码后的数据发现某一字节的高4位bit7-bit4依次是5 6 7。这显然与温度相关。进一步测试发现当设定为16°C时这个值是0。于是规律就出来了发送值 设定温度 - 16。这样21°C就对应发送值5。更棘手的是校验和。数据帧的末尾通常有1-2个字节用于校验确保传输无误。我尝试使用reveng这类CRC逆向工具但没能匹配出标准算法。于是转而进行人工分析观察当数据部分微小变化时校验字节的变化规律。我发现Atlantic协议使用了两个独立的4位校验和分别保护数据帧的高4位部分和低4位部分。它们的初始值都是0b111115算法是递减式校验和 15 - (所有被保护数据位的和)。如果结果小于0则循环回15继续减。通过大量数据验证后这个算法被确认。3.2 用户界面设计与交互逻辑HMI人机界面是用户与设备直接交互的窗口设计需要直观且高效。3.2.1 屏幕组件化设计我没有使用复杂的GUI库而是自己实现了一个轻量级的控件系统。屏幕由几个基本部分组成标题栏顶部区域显示当前屏幕的名称如“温度设置”。状态栏底部区域固定显示关键信息当前控制模式MANUAL/BLE、空调运行状态OFF/COOL/HEAT、以及当前温度设定点。这让用户在任何界面下都能一眼看到核心状态。内容区中间大部分区域根据不同的设置页面动态加载不同的控件如数值显示框、进度条、选项列表等。3.2.2 创新的交互方式按键手势设备只有两个按键B1 B2和一个ToF距离传感器却要完成复杂的设置。B1左键在浏览模式下用于在多个设置屏幕间循环切换在编辑模式下则用于取消当前编辑并跳转到下一个屏幕。B2右键在浏览模式下按下即进入当前焦点控件的编辑状态如果该控件允许编辑被编辑的控件会有边框高亮在编辑模式下按下则确认当前修改的值。ToF传感器这是交互的亮点。进入编辑模式后例如编辑温度屏幕下方会出现一个水平进度条。用户无需触摸设备只需将手在传感器上方前后移动改变手与传感器的距离进度条就会随之变化从而连续、无级地调整数值。这比反复按按键“加一减一”要快捷和精准得多。3.3 蓝牙多设备连接管理STM32WB的蓝牙协议栈已经处理了底层的连接管理。我们的任务是在应用层实现多设备连接和简单的在场判断。连接管理协议栈支持多个并发连接通常8个。我们需要维护一个连接句柄列表。当手机App发起连接时BLE任务会收到回调将新设备的句柄加入列表断开时则移除。在场判断这是一个简化设计。我们通过读取每个已连接设备的接收信号强度指示来粗略估计距离。在App端可以设计为当用户打开App并进入投票界面时才认为该用户“在场”。或者在设备端设置一个RSSI阈值只有当信号强度高于此阈值意味着设备在较近距离内才将该用户的投票计入有效票。这种方法不精确但对于办公室场景设备固定人员活动范围有限是一个低成本、可用的方案。数据同步设备端需要定义一个GATT特征Characteristic用于接收投票数据。手机App以“写”的方式将用户选择的温度值发送过来。同时设备可以定义另一个特征以“通知”的方式主动向所有已连接的手机推送当前的环境温度、投票结果或系统模式保持多端信息同步。4. 开发环境搭建与代码结构导读4.1 开发工具链准备项目基于STM32CubeIDE V1.13.2构建。这是一款ST官方推出的免费集成开发环境基于Eclipse集成了CubeMX配置工具、编译器、调试器对STM32开发非常友好。安装STM32CubeIDE从ST官网下载并安装。导入项目在IDE中选择“File - Import - Existing Projects into Workspace”然后定位到项目根目录下的Sources/MCU/BLE_Freertos文件夹。这个文件夹结构是CubeIDE的标准项目结构。解决可能的编译问题项目说明中特别提到由于手动修改了spi.c和i2c.c以移除自动生成的初始化函数MX_SPI1_InitMX_I2C3_Init如果重新用CubeMX生成代码需要注意不要覆盖这些修改或者确保HAL库文件被正确链接。4.2 项目代码目录结构解析清晰的目录结构是大型项目可维护性的基础。本项目结构如下Elektor_Demo_Clim/ ├── Documentation/ # 项目文档 │ ├── Datasheets/ # STM32等芯片的数据手册 │ ├── Internal_Documentation/ # 内部编码规范与模板 │ ├── Reverse_atlantic_protocol/# 红外协议逆向工程的所有捕获数据和解析笔记 │ └── Technical_Documentation/ # 软件架构设计文档含PlantUML图 ├── Sources/ │ ├── MCU/ │ │ └── BLE_Freertos/ # 主工程目录STM32CubeIDE项目 │ │ ├── Core/ │ │ │ ├── Inc/ # 头文件 │ │ │ ├── Src/ # 主循环、硬件初始化等 │ │ │ └── task/ # **核心**所有FreeRTOS任务源码 │ │ │ ├── tsk_hmi.c # HMI任务 │ │ │ ├── tsk_ir_atl.c # Atlantic红外协议任务 │ │ │ ├── tsk_ble.c # BLE任务 │ │ │ └── ... # 其他任务 │ │ ├── 3rdparty/ # 第三方库单色OLED图形库和控件库 │ │ └── STM32_WPAN/ # STM32无线协议栈中间件 │ └── tools/ # 实用工具如为DSView写的红外解码器脚本 └── Bin/ └── MCU/ # 存放编译好的.hex固件文件重点关注的目录Core/task/这里是所有业务逻辑所在。每个.c文件对应一个FreeRTOS任务职责单一通过消息队列和事件标志组进行通信。3rdparty/里面的图形库是针对小内存、单色屏优化的比通用的LVGL或emWin更轻量适合本项目。Documentation/Reverse_atlantic_protocol/如果你要适配其他品牌空调这里的逆向工程方法论和原始数据将是宝贵参考。4.3 系统初始化与任务启动流程理解启动流程对调试至关重要。在main.c的main()函数中顺序大致如下HAL初始化HAL_Init()初始化硬件抽象层。系统时钟配置SystemClock_Config()确保CPU和外围总线运行在正确频率。外设初始化通过CubeMX生成的代码初始化GPIO、I2C连接OLED和温度传感器、SPI可能连接ToF、定时器用于红外载波生成等。FreeRTOS初始化创建任务所需的内存管理、队列等。创建所有应用任务按优先级从低到高或按依赖关系创建看门狗、HMI、按键、温度、红外、BLE等任务。优先级需要仔细设计例如处理用户输入的HMI任务和红外发送任务需要较高响应优先级。启动调度器osKernelStart()之后FreeRTOS接管CPU开始在多任务间调度。5. 调试心得与常见问题排查在实际开发中我遇到了不少坑这里分享一些典型的排查思路和解决方法。5.1 红外发射无反应或空调不识别这是最可能遇到的问题。检查硬件连接首先确认红外发射管的正负极没有接反限流电阻值合适通常100-330欧姆。用手机摄像头对准发射管按下按键时能看到闪烁的紫光说明硬件通路基本正常。验证载波频率空调遥控常用38kHz但可能是36kHz 40kHz等。用逻辑分析仪或示波器测量驱动红外管的PWM输出频率。STM32的定时器PWM输出精度很高重点检查定时器分频和自动重载值的计算是否正确。核对协议细节起始码长度是否精确我遇到的Atlantic协议起始码是3.8ms高1.5ms低误差太大空调可能不认。逻辑电平定义“0”和“1”的高低电平时间是否与解码时的一致常见错误是弄反了。重复码长按按键时原装遥控器是连续发送完整帧还是只发送一个简短的重复码需要模拟这个行为。校验和这是最大的坑。务必用多个不同的数据样本验证你的校验和算法。一个字节算错整个帧都会被空调丢弃。可以先将捕获到的原装遥控器数据帧含校验和硬编码到程序里发送如果空调能响应再切换到动态计算校验和。5.2 FreeRTOS任务卡死或系统重启堆栈溢出这是多任务系统最常见的崩溃原因。在STM32CubeIDE中可以在FreeRTOSConfig.h中开启configCHECK_FOR_STACK_OVERFLOW选项。当检测到溢出时会触发钩子函数方便定位是哪个任务出了问题。适当增加该任务的堆栈大小。看门狗复位如果开启了硬件看门狗IWDG确保每个需要监控的任务都能定期“喂狗”。在我的设计中由独立的看门狗任务统一管理。检查是否所有任务都正确地向看门狗任务发送了存活信号。资源竞争如果多个任务如HMI和BLE同时访问同一个硬件外设如I2C必须使用互斥锁Mutex。我修改了HAL I2C驱动在其内部加入了RTOS互斥锁确保线程安全。优先级反转如果高优先级任务等待一个低优先级任务占有的资源如信号量而该低优先级任务又被中优先级任务抢占就会导致高优先级任务无限期等待。合理设置优先级或使用优先级继承互斥锁。5.3 BLE连接不稳定或手机搜不到设备广播参数检查广播间隔Advertising Interval。间隔太短如20ms耗电间隔太长如几秒则手机扫描时可能错过。100ms到1s是常用范围。确保广播数据包中包含了完整的设备名称和需要的服务UUID。连接参数连接建立后主设备手机和从设备STM32会协商连接参数包括连接间隔、从设备延迟、监督超时。STM32WB作为从设备可以提出连接参数更新请求。如果连接间隔设得太长数据传输会不实时太短则增加功耗。需要根据应用需求在功耗和响应速度间权衡。内存不足每个BLE连接都会消耗RAM。如果计划连接8个设备需要在FreeRTOSConfig.h中为BLE任务分配足够的堆栈和堆内存。同时检查协议栈配置中定义的最大连接数是否足够。天线与干扰确保开发板上的蓝牙天线区域没有被金属遮挡。2.4GHz频段容易受到Wi-Fi、微波炉等干扰尽量远离强干扰源。5.4 ToF传感器读数不准或跳动大电源噪声ToF传感器对电源纹波敏感。确保其供电引脚有足够的去耦电容通常手册会推荐一个10uF和一个0.1uF的电容并联。I2C上拉电阻STM32开发板上的I2C总线通常已接上拉电阻如4.7kΩ。如果自己布线必须接上拉电阻阻值根据总线速度和线长选择通常在2.2kΩ到10kΩ之间。软件滤波传感器原始数据难免有跳动。在任务中不要直接使用单次读数而应采用软件滤波。最简单有效的是移动平均滤波维护一个包含最近N次读数的小数组每次取平均值输出。N的大小根据采样周期和响应速度要求调整。环境光干扰强光特别是阳光可能会干扰ToF传感器的红外光测量。在传感器窗口上方加一个短的遮光罩如一小段黑色热缩管可以有效改善。5.5 功耗优化考虑虽然目前是插电演示但若未来改为电池供电功耗至关重要。动态频率调整在系统空闲或仅运行后台任务如看门狗时可以通过HAL_RCC_ClockConfig降低系统主频。外设时钟门控不使用的串口、SPI、ADC等外设及时关闭其时钟__HAL_RCC_XXX_CLK_DISABLE()。低功耗模式在BLE模式下当没有手机连接且处于非投票时段可以让STM32WB进入低功耗的停止模式Stop Mode此时BLE协议栈由协处理核维持主核暂停功耗可降至微安级。有连接事件或按键中断时再唤醒。屏幕与传感器管理OLED屏幕在无操作一段时间后可以关闭。ToF传感器可以设置为间歇性测量而不是持续测量。6. 项目总结与未来演进方向经过一段时间的开发这个民主空调遥控器的核心骨架已经搭建完成红外协议成功逆向并实现、多任务系统稳定运行、基础HMI和BLE框架就绪。它已经可以作为一个功能强大的万能红外遥控器来使用。我个人在实际操作中的体会是嵌入式物联网项目的难点往往不在于单一技术的深度而在于多种技术的集成与稳定协作。FreeRTOS是多任务管理的利器但必须对任务优先级、同步通信有清晰的设计。无线通信BLE的调试比有线复杂需要更多的耐心和工具如手机端BLE调试App、空中抓包器。而逆向工程则像侦探破案需要细致的观察、合理的假设和反复的验证。最后再分享一个小技巧在开发类似项目时建立一个清晰的“调试输出”系统非常重要。我利用STM32的串口UART定义了几个不同等级的调试信息宏如DEBUG_ERROR DEBUG_INFO DEBUG_RAW可以方便地在不同开发阶段打开或关闭特定模块的日志这对定位跨任务、跨模块的问题有奇效。这个项目还有很大的演进空间也是我下一步计划手机App开发这是实现“民主”功能的关键一环。计划使用Flutter或React Native开发一个跨平台App界面简洁主要功能就是显示当前环境温度、进行温度投票、查看实时投票结果。智能在场判定目前的RSSI方案比较粗糙。可以结合手机App当用户打开App并进入办公室地理围栏Geofencing时自动标记为“在场”或者利用BLE的定向功能如果手机和硬件支持进行更精准的接近判断。数据持久化与场景化将用户偏好、定时任务如工作日9点自动开启空调保存到STM32的Flash或外置EEPROM中实现断电记忆。甚至可以创建“会议模式”、“午休模式”等场景一键切换。云端同步与远程管理增加Wi-Fi模块或利用STM32WB的某些型号将数据同步到云端。管理员可以远程查看办公室温度状况、能耗统计甚至在特殊情况下进行远程干预。支持更多空调品牌将红外协议编码部分设计成插件化结构。通过配置文件或学习功能让这个设备能够控制市面上绝大多数品牌的空调真正成为一个通用的“智能红外网关”。