资讯详情

资讯详情

STM32智能投影仪外挂控制板:红外、状态机与安全时序设计

1. 先把“智能投影仪控制”这件事拆开看1.1 控制板到底要控什么边界在哪里很多人一说“用STM32控制投影仪”脑子里想的是一块板子从零驱动DLP光机、点亮LED光源、跑梯形校正算法。这条路走不通也不该走。投影仪整机内部的光机、驱动板、色轮时序、DMD微镜刷新都是整机厂做了十几年调校的东西外人拿一块MCU根本接不进去就算接进去也没有光学参数可以配合。真正可落地、而且市场上大量产品在用的做法是STM32做一个外挂的智能控制板站在投影仪的外面用投影仪原本就对外开放的接口去“替人按键”。这些接口无非三类——红外遥控接收窗口、串口控制口工程机、商用机常见、以及电平触发口很多机型背部的12V Trigger。想清楚这个边界以后项目范围就非常清晰了STM32要干的事是“感知环境 下发指令 守住安全”而不是“驱动光机”。感知环境靠温湿度、光照、人体存在、电流检测下发指令靠红外发射和串口协议解析守住安全靠一套围绕“灯泡/LED光源有余热”的状态机。这三件事拼起来才是一个完整的、能真正放在会议室或者家庭吊装场景里跑起来的东西。我见过太多初学者一上手就去啃光机驱动时序啃了两周发现连个能亮的东西都没有最后放弃。反过来先做外挂控制板一周之内就能看到“板子上电、投影仪自己开机、风扇延时关闭”的完整闭环成就感完全不一样而且这套东西是真的能装到实际项目里的。1.2 为什么是STM32而不是现成的智能模块选型的第一个问题永远是“要不要用MCU”。市面上有一堆Wi-Fi模组、智能插座方案、红外宝塔直接买来配个APP就能用为什么还要自己写固件答案在确定性和安全时序上。投影仪这类设备有一个很讨厌的特性光源关闭后散热风扇必须继续转足够长的时间把余热排掉否则光机寿命直线下降严重的会烤坏透镜镀膜。智能插座断电是“啪”一下全断风扇跟着停这是最典型的毁机操作。任何云平台掉线、路由器重启、APP卡死都不应该影响这件事。本地MCU跑裸机状态机掉网了照样能守住延时关机这才叫可靠。第二个理由是接口丰富度。STM32F103这一档的芯片两路UART、两路I2C、两路SPI、多个定时器PWM、12位ADC做红外发射需要精确的38kHz载波和微秒级时序、串口协议、NTC采样、风扇调速一颗芯片全包BOM成本压得很低。换成纯Wi-Fi模组PWM精度和定时器数量往往不够做红外载波抖动大遥控距离直接腰斩。第三个理由是生态。HAL库虽然有争议但对于这种外设多、逻辑不复杂的控制类项目它把GPIO、定时器、UART、ADC的初始化全部模板化你只需要关心业务逻辑。我个人的习惯是初始化全部用CubeMX生成业务代码手写绝不依赖库里的延时和阻塞函数。注意选型时不要盲目追高性能。这个项目里CPU负载很低主频跑到72MHz都算浪费重点是定时器资源和中断响应确定性不是算力。选一颗定时器够用、供货稳定的型号比选一颗跑得快的更重要。2. 硬件设计那些看起来不起眼但要命的细节2.1 供电域划分与上电时序整个控制板最容易被忽略、又最容易烧东西的地方就是供电。投影仪吊装在天花板上控制板通常从投影仪自身的待机电源取电或者单独引一路12V。这里必须分清三个域12V原始输入域、5V中间域、3.3V逻辑域。12V先过一级 buck 降到5V再由LDO降到3.3V给MCU。为什么中间要加一级5V因为红外发射管的脉冲电流能到150~300mA这个瞬间电流如果直接从3.3V LDO抽会把MCU的电源拉塌表现为“一发射红外MCU就复位”。这是我踩过的第一个坑后来在5V和3.3V之间加了π型滤波10μF 磁珠 0.1μF才彻底解决。上电时序也要想清楚。MCU上电复位需要时间而继电器或者MOS管控制的对外输出口在上电瞬间是未知态如果这个口直接接到投影仪的触发输入可能导致投影仪误开机。稳妥做法是在输出口加下拉电阻硬件保证默认关闭软件初始化完成后再主动拉高。另外如果控制板和外接设备共用一路电源要考虑谁先上电——MCU先起来、外设后上电是最安全的顺序反过来容易出现IO口倒灌长期跑会腐蚀IO。电源部分的经验值buck 输出加一颗 470μF 电解应付脉冲负载LDO 输入端加 TVS 管防浪涌所有对外接口串口、触发口一律串 100Ω 电阻并加 TVS天花板上的设备最怕的就是雷雨天的感应电压。2.2 红外发射电路38kHz载波与驱动能力红外是消费级投影仪唯一通用的控制入口做好这一块项目就成了一半。硬件上分两部分载波调制和功率驱动。载波由定时器PWM产生38kHz是绝大多数接收头的中心频率。以72MHz主频计算分频系数取0、自动重装值取1894实际频率是 72,000,000 / 1895 ≈ 37994Hz偏离中心频率约0.016%接收头的带通滤波完全能接受遥控距离基本无损。占空比我一般取1/3因为红外LED允许的脉冲峰值电流远大于平均电流占空比低可以把峰值电流做大同时不让管子发热。功率驱动这一级千万别直接用IO口推LEDIO的灌/拉电流只有20mA级别做不了远距离。标准做法是NPN三极管或小MOS做开关红外LED串限流电阻。算一下5V供电红外LED正向压降约1.2V想要150mA峰值电阻就是 (5 - 1.2) / 0.15 ≈ 25Ω。实际取22Ω或27Ω都可以我偏22Ω留一点余量。要注意的是这个150mA是脉冲电流不是持续电流因为载波占空比1/3、编码里还有大半时间是空闲平均电流不到10mA一颗普通SOT-23三极管完全扛得住。提示红外LED尽量不要和MCU放在同一块小板上朝同一个方向接收头对发射管的直射光非常敏感容易自己干扰自己。物理上错开90度或者在发射管周围加一圈黑色热缩管做遮光。2.3 串口控制口电平匹配与隔离工程投影仪背后那个9针口是宝藏通过它可以直接下发开关机、切换信号源、查询状态的指令比红外可靠得多——红外是单向的发出去不知道有没有收到串口是双向的能查询、能确认。但直接拿MCU的TTL电平接上去是错的必须加电平转换。常见做法是用专用收发芯片把3.3V的TTL转成±电平同时注意方向控制。如果板子和投影仪不是同一个电源系统还要考虑地环路我一般会加光耦隔离虽然多花几毛钱但能避免“插上串口线就死机”这种玄学问题。协议层面这类控制口发的都是短帧比如“开机”“关机”“查询电源状态”帧格式通常是固定的几个字节加结束符没有复杂的握手指令。但也有部分机型用的是网络控制协议那套东西基于TCP帧结构相对规整做起来要解析长度字段和校验。我的建议是先抓包。拿一台样机用串口助手或者网络调试工具把原厂控制软件下发的每一帧原样记录下来做成一张指令表比翻任何手册都准。2.4 温度采样NTC分压的计算与精度核算测温是这个项目里唯一不能省的模拟量。投影仪出风口温度是最直接的“它是不是热过头了”的指标。我用的是10K NTCB值3950上拉10K到3.3V中间点接ADC。这个分压网络有几个数值得算明白。25℃时NTC阻值就是10K分压后电压是 3.3 × 10K/(10K10K) 1.65V。12位ADC在3.3V参考下一个LSB约0.806mV对应读数2048左右。再看灵敏度NTC的阻值随温度变化率 dR/dT -B·R/T²代入B3950、R10000、T298K得到约 -445Ω/℃。分压网络对阻值的灵敏度 dV/dR 3.3 × R_pullup / (RR_pullup)²在25℃时约 8.25×10⁻⁵ V/Ω。两者相乘得到约-36.7mV/℃。也就是说每升高1℃ADC读数变化约45个LSB——这个分辨率对散热控制来说绰绰有余不需要外部运放放大。真正麻烦的是非线性。NTC的阻值-温度曲线是指数型的直接线性换算在高温段误差会到好几度。工程上的处理方式是查表加分段线性插值在5℃、15℃、25℃、35℃……每10℃打一个点用二分查找定位区间区间内做线性插值。这样整段误差能控制在0.3℃以内代码不到五十行比现场跑浮点指数运算省事得多也更适合没有FPU的芯片。注意NTC要紧贴散热鳍片或者出风口别悬空在机箱里否则测的是机箱空气温度反应慢半拍等它报警的时候光机可能已经超温了。固定方式用导热硅胶或者压片不要用热熔胶那个东西七十度就软了。2.5 风扇调速PWM频率与转速闭环散热风扇基本都是四线制电源、地、PWM输入、转速反馈。PWM频率有讲究规范要求是25kHz这个频率高于人耳可闻范围不会产生啸叫。我见过有人用几百赫兹去驱动结果整机嗡嗡响用户投诉噪音大——这不是风扇坏了是驱动频率选错了。定时器配置上72MHz下取预分频72、重装值40得到 72MHz/(72×40) 25kHz占空比分辨率2.5%够用。转速反馈是一路开漏输出的方波风扇转一圈给两个脉冲。测速用输入捕获或者定时器计数都行。为什么要闭环因为风扇老化以后转速会掉同样的PWM占空比吹不出同样的风量光靠开环控制机器用一年就散热不良了。闭环的思路很简单设定目标转速测实际转速误差超过阈值就调整占空比。哪怕是简单的比例控制也比纯开环强得多。我一般设三个档位静音档40%占空比、标准档65%、强冷档100%只在温度超过阈值时切到强冷。2.6 电流检测判断“它到底开没开机”这是一个非常实用但很少有人做的设计。红外发出去了投影仪到底开了没有串口查询也可能因为协议实现差异返回假状态。最可靠的判据是电流。投影仪待机功耗只有零点几瓦开机后光源点亮整机功耗会跳到几十瓦甚至上百瓦电流变化极其明显。检测方式有两种串在主供电回路里的分流电阻需要隔离运放成本高或者非接触式的霍尔电流传感器串在火线上输出模拟电压直接接ADC。后者更安全不破坏原有布线精度对判断“开/关”这种二值状态完全够用。有了这个信号整套逻辑就闭环了发开机指令后轮询电流值3秒内电流跃升超过阈值判定开机成功超过20秒还没动静判定失败重发一次两次失败就上报异常。这比“发完就当它开了”可靠一百倍也是整个项目里最像“工业级”的一个设计点。3. 软件架构状态机是这套东西的骨架3.1 分层方式与任务划分裸机还是RTOS这个项目我强烈建议裸机。理由很实在任务数量少实时性要求集中在红外发射的微秒级时序上RTOS反而会引入调度抖动。裸机加一个主循环 中断 软件定时器逻辑清晰、调试方便、没有栈溢出的风险。分层上我习惯分三层。驱动层GPIO、定时器、UART、ADC的初始化与读写全部由CubeMX生成自己只在上面包一层“发一个红外码”“读一次温度”这样的接口。逻辑层状态机、指令解析、安全保护。应用层业务动作序列比如“开机”这个动作实际上是一串有序操作——先开风扇、再发红外、再等电流反馈。这样分的好处是逻辑层完全不知道自己控制的是红外还是串口将来换机型只改应用层。主循环的节奏感很重要。我一般用一个1ms的系统滴答做时基主循环里跑一个10ms的任务调度表每10ms采样一次温度、每50ms更新一次风扇、每100ms轮询一次通信、每500ms刷新一次状态机。红外发射放在中断里因为它需要微秒级精度不能受主循环影响。3.2 状态机设计从待机到冷却的六个态这是整个项目最核心的部分也是最容易写错的地方。我把状态机分成待机IDLE、自检SELFTEST、预热WARMUP、运行RUN、冷却COOLING、故障FAULT。待机态只做两件事等指令、维持风扇最低转速如果机型需要。收到开机指令后进自检读一次温度如果超温直接拒绝开机避免在异常状态下强行点亮光源检查风扇是否转起来读转速反馈转不起来也不许开机。自检通过进预热发开机红外然后进入一个持续几十秒的等待期——这个等待期不是随便定的光源从点亮到稳定输出需要时间这段时间内不能接受“关机”以外的指令否则容易出现光源还没起辉就被断电对灯芯损伤很大。运行态是主战场持续监控温度、电流、通信连接。温度超过第一阈值比如75℃切强冷风扇超过第二阈值比如85℃主动下调亮度或者发节能指令超过第三阈值95℃直接进故障态强制关机。故障态不是终点它还会继续维持风扇全速运转等温度降下来再回待机。冷却态是被最多人写错的地方。收到关机指令后先把光源关掉然后风扇必须继续转120秒以上。这个时间不能拍脑袋要看机型小功率LED光源60秒够大功率灯泡机要180秒甚至更久。我的做法是把延时做成可配置的常量部署时按机型调整。冷却期间如果收到开机指令要拒绝或者先等冷却完成绝对不能直接重启——冷机重启会导致光源热冲击。提示状态机里的每一次迁移都应该有日志输出哪怕只是一串串口打印否则现场出问题的时候你根本不知道它卡在哪一态。我现在的习惯是每个状态占一个字节的状态码随时可以通过串口查询排查效率提升非常明显。3.3 通信帧格式为什么要加校验上位机手机APP、中控面板、上位网关和下位机之间的通信最容易出问题的不是协议本身而是“不知道自己收到了什么”。我做自定义帧的时候固定这么几段帧头两个字节故意选一个不会在数据里出现的组合、长度字段、命令字、负载、校验字节。校验用CRC8多项式选常见的那个代码十几行查表法更快。为什么一定要校验因为现场环境里串口线可能几米长走的是弱电桥架旁边就是强电线干扰不是理论问题。没有校验偶发的位翻转会导致命令错位本来是“查询状态”被解析成“关机”用户在演示途中投影仪突然黑屏这种事出一次就够丢脸的。加了CRC以后误帧直接丢弃等下一个帧头重新同步健壮性完全不是一个级别。接收用中断加环形缓冲区不要在中断里解析。中断只负责把字节塞进缓冲区主循环里再去取、找帧头、验长度、算校验、执行命令。这样即使解析逻辑写得再重也不会阻塞中断不会丢数据。缓冲区大小我一般给256字节普通控制指令几十字节绰绰有余。3.4 几个必须算准的外设参数UART波特率误差115200波特率72MHz时钟BRR值为 72,000,000/(16×115200) 39.06取整39实际波特率是 72,000,000/(16×39) 115384误差0.16%远小于3%的容忍上限通信稳定。但如果主频选了奇怪的晶振比如用内部RC振荡器那误差可能到2%以上长帧就会开始丢字节。所以这类项目必须用外部晶振别省那两毛钱。ADC采样时间NTC分压源阻抗是10K并联等效约5KADC采样保持电容需要足够的充电时间。采样周期设到239.5个周期转换时间约 239.512.5 252 个ADC时钟在12MHz ADC时钟下约21μs非常宽裕。别为了省时间设最小的1.5周期那样读数会明显偏低。红外载波占空比PWM的比较值取重装值的三分之一也就是631左右1894/3。这个数值决定了红外LED的峰值电流和平均功耗的平衡点取二分之一也能工作但管子发热会多一点。4. 从零到跑通实操过程记录4.1 第一步让红外“发得出去”先自检再联调新手最常见的误区是拿真机当调试对象改一次代码对着投影仪按一次看它开不开机。这种方式效率极低因为变量太多——可能是码不对可能是载波不对可能是距离不够可能是发射管接反了。正确的顺序是先闭环自检。做法是在板子上同时装一个红外发射管和一个红外接收头接收头输出的就是解调后的基带信号用MCU自己的输入捕获去读它。发一个码读回来比对时序。如果能原样读回说明载波频率、占空比、脉宽都对读不回来或者读回来是乱的问题一定出在发射侧跟投影仪无关。这一步能让调试效率提升好几倍我第一次做的时候用示波器探头点接收头输出看着那一串9ms低电平、4.5ms高电平的引导码心里瞬间就有底了。验证通过以后再用“学习模式”把原装遥控器的码抓下来。学习模式下接收头捕获到的每个脉宽都记进数组原样存进Flash。这样不管什么机型学习一次就能用通用性直接拉满。存储时用两个字节表示一个脉宽单位是微秒除以10最大可表示655ms一个码30多个脉宽占几十字节留一页Flash专门存这些码掉电不丢。4.2 第二步把状态机跑起来用串口打印观察硬件通路打通后先别急着接投影仪把状态机单独跑起来用串口把每一次状态迁移打印出来。我给自己定了一个规矩任何一个新写的状态机必须能在不接任何外设的情况下靠人为注入事件走完全部状态。开机事件、超温事件、关机事件、故障事件全部可以从串口模拟注入。这样相当于给状态机写了一套“单元测试”等真机接上去以后剩下的就只是硬件时序问题了。这一步还能顺手验证一个很关键的东西冷却延时到底有没有被正确执行。很多人的代码在收到关机命令后直接进待机风扇跟着停测试的时候不接投影仪看不出来接上真机跑几次光源就开始出问题。把延时做成状态机里的独立一态用软件定时器计时中途不允许被其他事件打断这是唯一靠谱的写法。4.3 第三步联调现场把电流反馈接进来真机联调的时候最有价值的信息来自电流。我第一次联调时遇到一个诡异现象红外码完全正确用接收头验证过但投影仪有时开有时不开。后来接上电流传感器才发现问题出在指令发送的时机——投影仪刚上电时红外接收电路还在初始化这段时间发的码会被吞掉。解决办法很简单上电后先延时两秒再发开机码如果两秒后电流没起来隔一秒重发最多三次。加了重试以后成功率从七成提升到接近百分之百。这个经验说明一件事单向通信必须配合状态确认。发出去不等于送达只有通过电流、温度这些物理量确认对方真的响应了这套系统才算闭环。这也是我后来在所有类似项目里都坚持加一个“执行结果确认”环节的原因。4.4 关键代码红外发送与温度换算红外发送的核心是把一串脉宽数组变成载波的通断。用一个定时器做载波输出另一个定时器做脉宽计时在计时中断里切换载波输出的使能/* 红外发送按脉宽数组依次切换载波输出使能 */ static void ir_send_frame(const uint16_t *pulses, uint8_t len) { ir_pulses pulses; ir_len len; ir_idx 0; ir_level 1; /* 第一个脉宽为载波输出 */ IR_CARRIER_ON(); htim_pulse.Init.Period pulses[0]; /* 单位10us1us计数 */ HAL_TIM_Base_Start_IT(htim_pulse); } /* 脉宽计时中断翻转载波输出加载下一个脉宽 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim ! htim_pulse) return; ir_idx; if (ir_idx ir_len) { IR_CARRIER_OFF(); HAL_TIM_Base_Stop_IT(htim_pulse); ir_busy 0; return; } ir_level !ir_level; if (ir_level) IR_CARRIER_ON(); else IR_CARRIER_OFF(); __HAL_TIM_SET_AUTORELOAD(htim_pulse, ir_pulses[ir_idx]); __HAL_TIM_SET_COUNTER(htim_pulse, 0); }温度换算用查表加插值代码里只处理整数避免浮点开销/* NTC 10K B3950 查表表项为 {ADC读数, 温度×10}按ADC升序排列 */ typedef struct { uint16_t adc; int16_t temp_x10; } ntc_point_t; static const ntc_point_t ntc_tab[] { { 3800, -100 }, { 3600, 0 }, { 3300, 100 }, { 2900, 200 }, { 2048, 250 }, { 1400, 300 }, { 900, 400 }, { 560, 500 }, { 330, 600 }, { 200, 700 }, { 120, 800 }, { 70, 900 }, }; int16_t ntc_read_temp_x10(uint16_t adc) { uint8_t n sizeof(ntc_tab) / sizeof(ntc_tab[0]); if (adc ntc_tab[0].adc) return ntc_tab[0].temp_x10; if (adc ntc_tab[n-1].adc) return ntc_tab[n-1].temp_x10; for (uint8_t i 0; i n - 1; i) { if (adc ntc_tab[i].adc adc ntc_tab[i1].adc) { int32_t d_adc ntc_tab[i].adc - ntc_tab[i1].adc; int32_t d_temp ntc_tab[i].temp_x10 - ntc_tab[i1].temp_x10; int32_t off adc - ntc_tab[i1].adc; return ntc_tab[i1].temp_x10 (off * d_temp) / d_adc; } } return 250; }这两段代码都不是什么高深东西但胜在结构清楚、没有动态内存、没有浮点、中断里只做最轻的活儿。这类项目里我宁可代码看起来“土”一点也不愿意为了优雅引入一堆库和抽象层——现场调试的时候你不会有心情去翻三层封装去找一个空指针。4.5 上电时序与安全保护的落地写法安全保护这块我总结成三条硬规则写死在代码里不给任何上层指令覆盖的机会第一温度超过硬阈值时任何开机指令无效第二光源关闭后风扇强制运转不少于设定时长计时器不受外部事件打断第三通信丢失超过设定时间我一般设30秒自动进入安全关机流程。第三条尤其重要。中控面板死机、网线被拔、上位机崩溃都是现实中会发生的事。如果投影仪一直保持开着会议室没人管散热、能耗、寿命都是问题。加一个心跳超时保护成本为零收益巨大。实现上就是在主循环里记录最后一次收到有效帧的时间戳超时就触发热关机流程并且打印一条明确日志说明是超时导致的。5. 常见问题与排查实录5.1 红外“有时候灵有时候不灵”这是出现频率最高的问题原因通常分四类。载波频率偏了拿示波器或者逻辑分析仪带频率计功能点一下发射管驱动脚确认是38kHz附近偏差超过2kHz就开始影响距离。驱动电流不足表现为近距离能控、三米外失灵用万用表测脉冲电流不方便改测平均电流如果是预期的一半以下说明三极管没饱和或者限流电阻取大了。接收窗口被遮挡或者角度太偏投影仪的红外接收窗一般在前脸吊装后朝下控制板如果贴在机身侧面发射角度可能超过30度。环境光干扰阳光直射、某些LED灯具的调制光会淹没红外信号这个只能靠提高发射功率或者改用串口来控制。排查顺序建议从易到难先换角度再看波形最后改电路。别一上来就怀疑代码红外发射的代码往往是最不容易出错的。5.2 风扇啸叫、转速不稳、报错停转风扇问题的排查表我整理过一份实际用起来挺顺手现象可能原因排查手段处理方式明显啸叫PWM频率落在可闻段示波器测PWM脚频率改为25kHz避开20kHz以下转速忽高忽低闭环比例系数过大或采样周期太短打印转速与占空比曲线降低比例系数转速采样周期放到1秒低速档停转启动占空比低于风扇启动阈值从0缓慢增加占空比观察低速档不低于35%或先给100%启动再降速转速反馈读数为0反馈脚无上拉或开漏未配置万用表测反馈脚电平加10K上拉输入模式配成上拉输入高温下风扇异响轴承润滑失效或积灰断电手动拨动扇叶更换风扇同时检查进风口滤网提示风扇的低速启动阈值一定要实测。同一个型号不同批次启动占空比可能差5%到10%。如果你的静音档设置在临界点附近冬天能转、夏天就转不动这种问题最难受。5.3 继电器或电源开关抖动导致误开机用继电器控制投影仪电源的那种方案最容易出现的问题是上电瞬间的抖动被投影仪误判为按键。原因是继电器触点吸合有弹跳加上线缆电感造成的电压振荡。解决办法有三个层次硬件上在触点两端并RC吸收100Ω串0.1μF软件上吸合后延时50ms再确认状态系统上干脆不用继电器控电源、改用红外控制。我现在基本不推荐继电器方案一来有安全隐患二来投影仪自己就能待机没必要外部断它的电。如果是用MOS管做电平触发抖动的表现是触发输入被拉低又拉高设备反复进出触发态。检查一下MOS的栅极有没有下拉电阻、驱动信号有没有上拉通常加一个100K下拉就能解决。5.4 串口通信偶发丢包、收到乱码排查这类问题的顺序基本固定。先确认电平方向TTL直连RS232电平是绝对不行的会把接收端打坏。再确认波特率误差尤其是双方都用内部RC振荡器的时候误差叠加起来超过4%就开始出问题。然后看地线长距离通信如果只接了TX/RX没接好地共模干扰会把信号淹掉。还有一个隐蔽的坑某些机型的串口是半双工的或者需要RTS/DTR做方向控制你按全双工去发对方收到的就是残缺帧。这种情况必须看时序用逻辑分析仪抓双向信号一看就明白。最后是缓冲区溢出。如果主循环里有阻塞操作比如某个命令里调了个长延时接收中断一直在填缓冲区主循环没空取满了就丢。解决办法是把所有阻塞延时都改成状态机里的非阻塞等待这是裸机编程里最基本的纪律。6. 几个不那么显而易见的经验和后续玩法有一个坑我印象特别深冷却延时不能只靠软件定时器。有一次现场反馈说设备偶尔在关机后风扇立刻停转。查了很久最后发现是看门狗复位——程序跑飞了看门狗把它拉回来重启后状态机从待机开始风扇自然是停的。后来的改法是把“冷却中”这个状态写进备份寄存器重启后读出来如果还处在冷却期就继续跑完剩余时间再停风扇。多花二十行代码解决了一类很难复现的偶发问题。另一个经验是关于调试接口的保留。这类板子装到天花板上以后你再想插调试器基本不可能所以一定要留一路串口出来做成可以查询状态、注入事件、读取日志的“运维口”。我现在的固件里固定有这么几条命令查询当前状态、查询温度与风扇转速、查询最近十次错误码、强制进入某个状态。就靠这几条很多现场问题不用拆机就能定位。后续扩展的话我比较看好的方向是把红外学习和云端指令结合起来板子本地存十几组常用机型的红外码云端下发一个机型编号板子自己去选对应码组这样一套固件能适配一批设备部署成本压得很低。再进一步是做场景联动——投影仪开机时自动把灯光调暗、把窗帘关上、把空调切到静音模式这些都可以挂在同一个状态机的事件上无非是多接几路输出。真正难的部分永远是那套安全时序和状态确认把它做扎实了往上面加什么功能都只是顺手的事。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →