资讯动态

STM32+红外模块控制格力空调:从硬件到代码的完整方案

发布时间:2026/10/21 5:01:00 来源:尧图企业网站定制
简介这份资源面向嵌入式开发初学者与智能家居DIY爱好者提供基于STM32微控制器驱动红外模块控制格力空调的完整工程实践。内容围绕STM32的GPIO推挽输出、定时器PWM波形生成、NEC红外编码与解码、协议适配及示波器调试等关键环节展开帮助读者理解从红外信号发射到空调响应的完整链路。压缩包共226个文件约8.35MB以32个c源文件、34个h头文件、42个crf中间文件、44个o目标文件及uvprojx、uvoptx等Keil工程文件为主另含hex烧录文件、map映射表与少量说明文档工程结构完整可直接编译。目前已有890人学习下载。读者可借此掌握STM32定时器与GPIO协同控制红外发射的编程思路理解格力空调遥控编码的解析方法并参考调试与测试流程排查信号不一致问题对物联网与智能家居项目开发具有实际参考价值。1. 从遥控器堆里抢回控制权STM32红外模块控制格力空调的完整方案家里空调遥控器又找不到了沙发上、床头柜、茶几底下翻个遍最后在冰箱顶上摸出来——这种场景做嵌入式的人都懂。与其继续忍受这种玄学找遥控器不如直接上STM32加红外模块把空调控制权收进自己手里。这套方案要解决的核心问题很明确用一颗STM32做主控搭配红外发射和接收模块实现格力空调的开关、温度调节、模式切换和风速控制同时预留扩展接口方便后续接入温湿度传感器做自动控温。适合正在做嵌入式毕设、课设的学生也适合想拿这个当智能家居入门项目的开发者。整套方案从硬件选型到红外协议解析再到代码落地全部可以照着复现。2. 需求拆解与技术选型为什么是STM32加红外而不是直接换智能空调2.1 功能需求与非功能需求先把需求拆清楚不然后面写代码全是坑。功能层面这套系统需要做到红外发射控制空调开关机、温度加减、模式切换制冷/制热/送风/除湿、风速调节自动/低/中/高、扫风开关红外接收用于学习原遥控器码值省去手动查协议表的麻烦串口输出调试信息方便排查问题预留I2C或单总线接口后续接温湿度传感器。非功能层面红外载波频率必须稳定在38kHz误差超过2kHz空调就可能不响应按键响应延迟控制在200ms以内系统连续运行不重启看门狗必须开。通常的做法是先把格力空调的红外协议码值抓出来再决定用哪种发射方案。格力空调红外编码遵循NEC格式的变体引导码是9000us低电平加4500us高电平逻辑0是560us低加560us高逻辑1是560us低加1690us高载波38kHz。这些参数在写发射代码时直接决定空调认不认你的信号。2.2 主控与红外模块选型对比主控选STM32F103C8T6原因很直接72MHz主频足够跑红外时序定时器资源丰富一个TIM输出PWM做38kHz载波另一个TIM做微秒级延时GPIO随便找个推挽输出接红外发射管驱动电路。比起用ArduinoSTM32的定时器精度更高红外时序不容易翻车。红外发射模块用常见的IR LED加三极管驱动电路接收用VS1838B一体化接收头。这里有个选型细节VS1838B输出是反相的接收到38kHz信号时输出低电平空闲时输出高电平写解码代码时电平判断别搞反。发射管驱动三极管选S8050基极电阻1k集电极接红外LED串限流电阻典型值100Ω到220Ω之间具体看LED正向压降和STM32的3.3V供电。模块型号关键参数作用主控STM32F103C8T672MHz64KB Flash红外编解码、逻辑控制红外接收VS1838B38kHz输出反相学习原遥控器码值红外发射IR LED S8050940nm100mA峰值发射控制信号调试接口CH340GUSB转TTL串口打印调试信息2.3 格力红外协议的关键参数格力空调红外码由引导码、35位数据码和结束码组成。数据码包含开关位、模式位、温度位、风速位、扫风位和校验位。温度编码不是直接二进制而是偏移编码比如16度对应0x0017度对应0x01一直到30度对应0x0E。模式编码制冷0x00除湿0x01送风0x02制热0x03。风速编码自动0x00低0x01中0x02高0x03。这些码值在写发射函数时直接填进去不用再猜。注意不同年份的格力空调红外协议可能有差异建议先用接收模块把原遥控器的码值完整抓一遍确认引导码和数据位定义后再写发射代码。3. 硬件设计与红外收发电路从原理图到PCB布局的落地细节3.1 最小系统与红外发射电路STM32最小系统包括晶振电路8MHz外部晶振加两个20pF电容、复位电路10k上拉加100nF电容、电源滤波每个VCC引脚配100nF去耦电容。红外发射电路的核心是PWM驱动。STM32的TIM3_CH1配置为PWM输出模式频率38kHz占空比1/3。为什么是1/3而不是50%因为红外接收头对载波占空比不敏感但1/3占空比能降低发射管功耗延长寿命。PWM输出接三极管基极三极管集电极串红外LED和限流电阻到3.3V。// TIM3 PWM初始化输出38kHz载波 void IR_PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); // PB4复用为TIM3_CH1 GPIO_InitStructure.GPIO_Pin GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); // 72MHz / 38kHz 1894.7取1895 TIM_TimeBaseStructure.TIM_Period 1895 - 1; TIM_TimeBaseStructure.TIM_Prescaler 0; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); // 占空比1/3比较值632 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 632; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); TIM_Cmd(TIM3, DISABLE); // 默认关闭发射时再开 }这段代码把TIM3配置成38kHz PWM输出关键参数是Period和Pulse。Period值1895是根据72MHz主频除以38kHz算出来的Pulse值632对应1/3占空比。发射时先使能TIM3延时对应时长后再关闭就能产生红外载波脉冲。3.2 红外接收电路与电平匹配VS1838B接收头有三个引脚VCC、GND、OUT。OUT接STM32的GPIO输入配置为上拉输入或浮空输入。接收头内部已经有滤波和放大输出信号直接进MCU。这里有个容易忽略的点VS1838B的输出电平是反相的空闲时OUT为高收到38kHz信号时OUT拉低。写解码代码时捕获下降沿作为引导码起始然后测量低电平和高电平持续时间来区分逻辑0和逻辑1。接收电路不需要额外放大但电源引脚必须加100nF和10uF电容滤波否则空调遥控器靠近时容易误触发。PCB布局时接收头远离发射管至少隔5cm以上不然发射时的红外光会直接串到接收头造成自收自发的死循环。3.3 电源与抗干扰设计整块板子用3.3V供电红外发射瞬间电流可能冲到100mA以上所以LDO选AMS1117-3.3时要注意散热或者直接用5V输入加1117-3.3输入输出都加10uF钽电容。红外LED的限流电阻根据供电电压算如果LED正向压降1.2V三极管饱和压降0.3V3.3V供电时电阻取(3.3-1.2-0.3)/0.118Ω但实际用100Ω到220Ω更安全峰值电流控制在20mA到50mA之间遥控距离够用就行。提示调试时如果空调没反应先用手机摄像头对着红外LED看发射时能看到紫色光点说明驱动电路在工作。如果看不到查三极管基极有没有PWM信号。4. 软件架构与核心代码实现红外编码、解码与空调控制逻辑4.1 软件分层与主循环设计软件分三层硬件驱动层PWM初始化、GPIO配置、定时器延时、红外协议层编码发射、解码接收、应用层空调状态机、按键处理、串口命令解析。主循环不做阻塞延时用定时器中断做微秒级延时主循环里轮询按键和串口数据。空调状态用一个结构体保存包括开关状态、温度值、模式、风速、扫风标志每次发射前根据当前状态生成35位数据码。typedef struct { uint8_t power; // 0关 1开 uint8_t mode; // 0制冷 1除湿 2送风 3制热 uint8_t temp; // 16-30 uint8_t fan; // 0自动 1低 2中 3高 uint8_t swing; // 0关 1开 } AC_State_t; AC_State_t ac_state {0, 0, 26, 0, 0}; // 默认26度制冷结构体定义清楚后所有控制逻辑围绕它展开。按键按下时修改对应字段然后调用红外发射函数把新状态发出去。这种设计的好处是状态可追溯串口打印出来一眼就能看出当前空调处于什么状态。4.2 红外发射函数与格力码值生成发射函数的核心是先把35位数据码拼出来再按NEC时序逐位发射。格力空调的数据码格式起始位加35位数据其中包含温度、模式、风速、扫风和校验。校验位通常是前几位异或的结果具体算法根据抓到的遥控器码值反推。// 发射一个逻辑位bit0发560us低560us高bit1发560us低1690us高 void IR_SendBit(uint8_t bit) { IR_Carrier_On(); delay_us(560); IR_Carrier_Off(); if (bit) { delay_us(1690); } else { delay_us(560); } } // 发射完整的格力空调码 void IR_Send_AC(AC_State_t *state) { uint8_t data[5] {0}; // 根据state填充data具体码值映射略 data[0] 0x08; // 开关和模式位 data[1] state-temp - 16; // 温度偏移编码 data[2] state-fan | (state-swing 2); // ... 校验位计算 IR_Carrier_On(); delay_us(9000); // 引导码低电平 IR_Carrier_Off(); delay_us(4500); // 引导码高电平 for (int i 0; i 35; i) { IR_SendBit((data[i / 8] (i % 8)) 0x01); } IR_Carrier_On(); delay_us(560); // 结束码 IR_Carrier_Off(); }这段代码里delay_us必须用定时器实现不能用空循环否则不同优化等级下延时不准。IR_Carrier_On和IR_Carrier_Off就是使能和关闭TIM3的PWM输出。发射完一帧后至少延时100ms再发下一帧给空调接收头留处理时间。4.3 红外解码与遥控器码值学习解码用外部中断加定时器捕获。VS1838B输出接PA0配置为下降沿触发中断。中断里记录定时器计数值算出低电平和高电平持续时间然后判断是引导码还是逻辑位。引导码的特征是低电平约9000us、高电平约4500us逻辑0是低560us高560us逻辑1是低560us高1690us。void EXTI0_IRQHandler(void) { static uint32_t last_time 0; uint32_t now TIM_GetCounter(TIM2); uint32_t duration now - last_time; last_time now; if (duration 8000 duration 10000) { // 引导码低电平 ir_bit_index 0; memset(ir_data, 0, sizeof(ir_data)); } else if (duration 400 duration 700) { // 逻辑0或逻辑1的低电平部分等下一个中断判断高电平 } else if (duration 1500 duration 1900) { // 逻辑1的高电平 ir_data[ir_bit_index / 8] | (1 (ir_bit_index % 8)); ir_bit_index; } else if (duration 400 duration 700) { // 逻辑0的高电平 ir_bit_index; } EXTI_ClearITPendingBit(EXTI_Line0); }解码代码的关键是状态机要清晰别在一个中断里塞太多逻辑。通常的做法是中断里只记录时间戳和电平主循环里做状态判断和码值解析。学习模式下把解析出的35位码值存到数组里串口打印出来对照格力协议表就能确认温度、模式、风速的编码位置。4.4 串口命令与状态机控制串口用来接收调试命令和输出状态。命令格式简单点比如“P1”开机“P0”关机“T26”设26度“M0”制冷“F2”中风。解析函数用switch-case处理收到命令后修改ac_state然后调用IR_Send_AC发射。void UART_Command_Handler(char *cmd) { switch (cmd[0]) { case P: ac_state.power cmd[1] - 0; break; case T: ac_state.temp atoi(cmd[1]); if (ac_state.temp 16) ac_state.temp 16; if (ac_state.temp 30) ac_state.temp 30; break; case M: ac_state.mode cmd[1] - 0; break; case F: ac_state.fan cmd[1] - 0; break; default: printf(Unknown command\r\n); return; } IR_Send_AC(ac_state); printf(State: P%d T%d M%d F%d\r\n, ac_state.power, ac_state.temp, ac_state.mode, ac_state.fan); }状态机控制的好处是逻辑集中后续加自动控温时只需要在定时器里读温湿度传感器比较设定值后自动修改ac_state并发射不用改红外协议层。5. 避坑与常见问题排查红外控制最容易翻车的五个点5.1 空调没反应但手机摄像头能看到红外光现象发射时红外LED亮但空调不响应。原因通常是载波频率偏了。STM32的TIM3配置成38kHz但实际输出频率受晶振精度和定时器分频影响偏差超过2kHz空调就认不出来。解决用示波器测PWM输出频率或者用逻辑分析仪抓红外接收头的输出波形确认引导码时长是否在9000us左右。如果偏了调整TIM_Period值重新算。5.2 接收头解码全是乱码现象串口打印的码值每次都不一样或者全是0xFF。原因有两个一是接收头电源没滤波空调遥控器靠近时干扰大二是解码中断里延时太长错过了后续边沿。解决接收头VCC并100nF加10uF电容中断里只记录时间戳解析放主循环。另外确认VS1838B输出是否反相如果空闲时是低电平说明接错了或者接收头坏了。5.3 发射距离短超过一米就没反应现象近距离能控稍微远一点就失灵。原因通常是红外LED驱动电流不够。STM32的GPIO最大输出20mA直接驱动LED亮度不够。解决加三极管驱动基极电阻1k集电极串LED和限流电阻峰值电流调到50mA到100mA。注意占空比别超1/3否则LED发热严重。5.4 连续发射时空调状态错乱现象快速按几次按键空调状态和预期不一致。原因是红外发射没有帧间隔空调接收头处理不过来。解决每次发射后延时至少100ms连续发射时在IR_Send_AC末尾加delay_ms(100)。另外状态更新和发射要原子操作别在发射过程中改ac_state。5.5 上电后系统跑飞或复位现象板子一上电就重启或者运行几分钟后死机。原因通常是电源电流不够。红外发射瞬间电流大LDO输出电容不够会导致电压跌落MCU复位。解决LDO输入输出都加10uF以上电容红外LED的限流电阻别取太小峰值电流控制在100mA以内。看门狗必须开IWDG超时设1秒主循环里定期喂狗。6. 验收标准与答辩演示怎么证明这套方案真的能控空调6.1 功能验收清单与测试方法验收不是跑通一个功能就算完得按清单逐项过。下面这张表是我带项目时常用的验收模板每一项都有明确的通过标准。验收项测试方法通过标准开关机串口发P1和P0空调响应开关延迟小于1秒温度调节串口发T16到T30空调温度逐度变化无跳变模式切换串口发M0到M3制冷、除湿、送风、制热均响应风速调节串口发F0到F3自动、低、中、高均响应红外学习按学习键后对准遥控器串口打印35位码值与原遥控器一致连续运行上电运行2小时不死机、不重启、状态不漂移测试时注意每次只改一个变量比如测温度时模式固定制冷风速固定自动避免多变量干扰判断。如果某项不通过先查串口打印的状态值对不对再查红外发射波形最后查空调接收。6.2 答辩演示的节奏与话术答辩演示时间通常5到10分钟节奏很关键。开场别讲原理直接演示功能串口发命令空调滴一声响应温度从26变到24模式从制冷切到送风。演示完功能再讲架构用框图说明STM32、红外发射、红外接收、空调之间的关系。最后讲扩展点比如预留了I2C接口可以接SHT30温湿度传感器后续做自动控温。话术上有个技巧主动说一个你踩过的坑。比如“最开始接收头没加滤波电容解码全是乱码后来在VCC并了100nF和10uF才稳定”。这种细节比背稿子更能让评委信服说明你真的动手调过。6.3 从演示到交付我踩过的坑和固定习惯第一次做这个项目时我以为红外发射就是把GPIO拉高拉低结果空调死活不响应。后来用逻辑分析仪抓波形发现引导码只有2000us远低于9000us原因是delay_us用空循环实现编译器优化后延时缩水了。从那以后我每次做红外项目都强制走一遍先用示波器确认38kHz载波再用逻辑分析仪抓引导码时长最后才写协议层代码。这个习惯帮我省了至少两天调试时间。还有一次答辩前夜连续发射测试时空调突然不响应了查了半天发现是发射管限流电阻取太小LED过热后光衰。换成220Ω电阻后连续发100帧都没问题。所以验收时别只测单次功能连续运行测试必须做至少跑2小时。希望帮到你这套方案从硬件到代码到验收都跑通过照着做能少走不少弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑