尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

自制红外信号记录仪:从脉冲捕获到波形回放的完整指南

自制红外信号记录仪:从脉冲捕获到波形回放的完整指南 很多人家里都有过这种经历电视机遥控器按起来没反应以为坏了拆开后发现是按键氧化空调遥控器不小心摔碎外壳主板还好好的却配不到原装型号车库卷帘门遥控器丢了一只再配一个要大几百。这些场景其实有一个共通的解决办法做一个红外信号记录仪把原遥控器发出的红外波形录下来需要的时候原样放回去。这篇文章想分享的就是这样一个自制项目——Infrared Signal Recorder。它的核心价值不在于技术创新而在于你亲手把看得到却摸不着的红外信号变成可以存储、回放和改造的数据。无论你手里是Arduino、STM32还是ESP32只要理解了红外接收头、38kHz载波、脉冲时序这几件事整个项目就能从零搭起来。对搞智能家居、折腾无线控制的老玩家来说这个项目也是理解所有IR控制设备的天然入口。1. 红外记录仪到底在记录什么要做一个能用的记录仪必须先搞清楚红外遥控信号本身长什么样。很多人以为接收头收到的就是红外光其实不是。一体化接收头输出的是一串串高低电平脉冲这串脉冲才是遥控器信息的真正载体。1.1 遥控信号的三层结构任何红外遥控信号都可以拆成三层来看。最底层是物理载波红外LED以38kHz左右的频率闪烁发光这个频率是接收头最敏感的频点中间层是调制波形遥控芯片让载波间歇性地出现和消失出现就是高电平、消失就是低电平由此形成编码数据最上层是协议帧厂家把地址码、数据码、校验码按特定顺序排布成一条完整的指令。接收端的一体化红外接收头比如TSOP38238做的事情就是把第一层物理信号干掉它内置了光敏二极管、前置放大器、限幅器和带通滤波器输出端直接给出解调后的TTL电平脉冲序列。换句话说录波器要记录的其实就是中间层那串脉冲的宽度序列——每个高电平持续多久和低电平持续多久。这里有个很多人第一次做项目时容易犯的错误想用ADC去采样红外波形。实际上完全没有必要。遥控信号的频率带宽远低于载波用高电平/低电平边沿捕获的效率比盲目ADC采样高得多也精准得多。以NEC协议为例最短脉冲是560微秒而单片机的中断响应加时间戳读取通常只需几微秒精度完全足够。1.2 两种记录路线波形原样记录与协议解码记录搞清楚记录对象之后紧接着要做一个路线选择是记录原始脉冲宽度序列还是直接把信号解码成协议数据后存储两条路线各有适用场景。原始波形记录的优点是通吃一切协议——不管NEC、RC5、SONY还是某个杂牌遥控器的私有格式只要接收收头能解调就都能原样存下来。缺点是占存储空间而且回放时需要高精度控制引脚翻转时机程序复杂度略高。协议解码记录的优点是存储量小得惊人——一条NEC指令解出来就是32位数据4个字节就搞定回放时只需要按协议重新编码即可。缺点是协议覆盖率有限遇到不认识的格式就没辙。我的建议是第一版先做原始波形记录因为它的通用性强排错也直观等你想做多按键学习或者联网控制时再在原始波形的基础上加一层协议识别和解码形成两条腿走路。本文的核心电路和固件设计也是围绕原始波形录制展开的协议解码作为进阶扩展放在后面。2. 从NEC协议说起一个足够典型的学习样本虽然原始波形记录器不需要懂协议但理解协议仍然很重要——它决定了你怎么设计解码容差、压缩格式和回放逻辑。NEC协议是所有红外协议里最适合当学习样本的。2.1 NEC帧结构和脉冲宽度参考一条标准的NEC指令帧由引导码lead code、地址码address和数据码command构成具体脉冲时序参考如下组成低电平脉宽高电平脉宽说明引导码9000us4500us用来标识一帧开始逻辑0560us560us一位数据逻辑1560us1690us一位数据重复码9000us2250us按键持续时循环发送地址码和数据码各8位并各跟一个反码用于校验。也就是说解码成功后你能得到这样一组32位数据8位地址 8位地址反码 8位命令 8位命令反码。校验逻辑很简单地址 地址反码 0xFF命令 命令反码 0xFF满足这个条件才算收到一个合法帧。了解这个结构有什么用首先它让你知道录制时等待引导码出现再开始存储可以滤掉大量无意义的空闲噪声其次在画波形的时候你能一眼判断出时序异常是发生在引导区还是数据区最后如果后面的固件要加解码功能这些容差范围可以直接复用。2.2 容差设计真实遥控器不是示波器新手最容易忽略的一点是你录到的脉冲宽度永远不会像数据手册上那么整齐。同一台遥控器换了新电池、按偏了位置、距离接受头远近不一样录到的引导码可能是8800us到9400us之间波动数据位也可能出现540us、600us、610us这种看起来不太对的数值。所以无论是解码还是波形判定都要留容差空间。一般取标称值的±20%到±30%。比如判断一个560us的短脉冲只要落在大约440us到680us区间就算合法判断引导码9000us宽容度可以放到±30%约6300us到11700us。原始波形录制阶段你其实不太需要这些判据但设计录制启动逻辑时可以用一条规则提升体验检测到超长低电平大于6000us比如引导码或者重复码才认为录制开始避免把环境光的零星毛刺当信号。3. 硬件选型和电路设计要点硬件部分并不复杂核心只需要四个模块接收电路、发射电路、主控和存储。接下来逐个说重点讲每个元件的选型理由和必要的计算。3.1 接收电路一体化红外接收头的优势与坑接收端强烈建议直接用一体化接收头不要用光敏二极管加分立放大电路。一体化接收头把光电流检测、带通滤波、波形整形全部做完了输出直接就是单片机可以读取的高/低电平外围只需要一个10uF电解电容和一个100nF陶瓷电容做电源去耦。选型上有几个关键参数中心频率常见的36kHz、37.9kHz、38kHz、40kHz、供电电压、输出极性。市面上最常见的TSOP38238中心频率是38kHz供电2.7V到5.5V输出为静态高电平收到有效信号时拉低。这个逻辑要注意看因为有些老型号如TSOP1738的输出极性和TSOP38238是相反的拿错型号直接导致录到的波形高低反相。事实上反相波形里也可以事后软件翻转但能避免还是尽量避免。我踩过的坑是接收头离主控的I/O引脚走线太长而且旁边有一根5V电源线。结果是录制时偶尔收到一串莫名其妙的毛刺——实际上那是电源线上的纹波耦合进了信号引脚。解决方法并不复杂信号线上串一个1kΩ电阻靠近接收头侧再放一个100pF电容对地能明显改善。3.2 发射电路载波驱动与限流电阻计算发射端的电路同样不复杂但驱动计算必须认真做。红外LED的工作特性与普通LED需求差别比较大它允许在短脉冲下通过更大的峰值电流因为脉冲占空比低平均功耗接近静态值。举例来说一个额定连续电流50mA的红外LED在25%占空比下可以脉冲到100mA在更短的载波脉冲下甚至能到1A级别只是实际电路中没必要逼那么狠。典型驱动电路用NPN三极管如8050作为开关MCU的I/O引脚通过基极电阻控制三极管导通集电极串限流电阻和红外LED到电源。计算限流电阻时以峰值电流为目标R (VCC - V_LED - V_CEsat) / I假设VCC 5VLED正向压降约1.3V8050饱和压降约0.2V希望峰值电流80mAR (5 - 1.3 - 0.2) / 0.08 43.75Ω取标准阻值47Ω实际峰值电流约74mA够用且安全。如果希望更远发射距离可以把电流推到120mA以上但注意确认LED的脉冲电流规格同时把三极管的基极驱动电流也相应加大确保进入饱和区而不是工作在线性区。3.3 主控、存储与显示方案的取舍对于这个项目主流选择是Arduino Uno、STM32F103小板或者ESP32开发板。三者对比大概是这样方案时序精度开发便利度联网能力适合阶段Arduino Uno16MHz足够最简单弱入门原型STM32F10372MHz定时器精度高中等弱正式制作ESP32240MHz但Wi-Fi中断有干扰中等强联网扩展第一版建议直接Arduino Uno因为生态成熟、示例多你可以把精力集中在信号逻辑而非底层寄存器。做到第二个版本再迁到STM32或ESP32也不迟。存储方面有两条思路。如果你的记录仪只存几条常用遥控指令那么芯片内置EEPROMArduino Uno是1KBSTM32F103通常也有可用的Flash扇区就够了。如果打算做几十上百条的学习库则建议外挂I2C或SPI接口的EEPROM比如24LC25632KB或者直接用SPI FlashW25Q64。对原始波形记录来说NEC一帧的脉冲序列压缩后大约需要60个字节左右便宜的小容量EEPROM也能存几十上百条。显示方案不是必需品调试期间用串口打印就够。但做到成品形态时一块0.96寸OLEDSSD1306I2C接口很实用可以显示当前状态、录制指示和按键编号。预留三个按键很必要一个录制键、一个回放键、一个模式切换键。4. 固件实现从边沿捕获到波形重放固件是这个项目的灵魂。建议整体分成三层底层是微秒时间戳和边沿中断捕获中间层是脉冲缓冲存储与压缩编码上层是录制/回放状态机。下面按这个顺序展开。4.1 状态机设计三个按键触发五态切换整个设备的逻辑可以用五个状态来形容空闲态、等待录制态、录制中、等待回放态、回放中。空闲态下接收头持续工作但固件只扫描按键按下录制键进入等待录制态此时需要给用户一个明确的视觉反馈LED点亮并把接收中断打开——但要注意并不是一检测到低电平就开始录而是先判断是否出现一个超长低电平脉宽如大于6000us确认是真正的引导码后才进入录制中录制中固件不断记录跳变沿时间戳直到检测到超过20ms的空闲高电平帧结束标志才停止回到空闲态回到空闲态后用户可以按回放键固件进入等待回放态再按一次确认或直接立即回放根据你的交互设计回放完自动回到空闲等待下一次操作。4.2 边沿捕获的精度问题对Arduino这种环境很多人想到直接用digitalRead去轮询引脚但这样精度受限于循环时间极不稳定。正确做法是用引脚电平变化中断PCINT每次中断时读取micros()作为时间戳并记录当前电平状态。以16MHz主频来说micros()本身有个约4微秒的误差加上中断响应延迟实测总误差大约在±5到±10微秒。对照NEC最短560微秒的脉冲宽度这个误差只占1%~2%完全可接受。核心数据结构可以设计成这样一个数组volatile uint16_t pulseWidth[MAX_PULSES];每个元素存储一次边沿到下一次边沿的持续时间同时用一个全局标志记录当前边沿是上升还是下降。为了避免录制过程中长时间占用中断导致丢失边沿脉冲写入采用简单的环形缓冲区主循环定期把数据搬运到SRAM里的正式缓冲区。录制结束条件可以通过当前高电平持续时间超过20毫秒来触发因为正常信号帧与帧之间的间隔远大于这个值。4.3 存储压缩把原始波形塞进EEPROM如果直接存脉冲宽度数组NEC一帧大约60~70个脉冲每个脉冲用uint16_t2字节就要130字节左右多按键多协议根本存不下。所以要在写入EEPROM之前做一级压缩。我的做法是将脉冲宽度做分级编码。先从录到的数据里提取出**短脉宽对应数据0和长脉宽对应数据1以及超长脉宽对应引导码**这三个典型值然后在存储时用2 bit表示一个脉冲00短脉宽即逻辑0的脉宽区间01长脉宽即逻辑1的脉宽区间10超长脉宽即引导码区间的脉宽11特殊标记帧结束 / 扩展这样一条NEC帧从120字节左右压缩到大约15~20字节。注意编码时高低电平是交替出现的所以不需要为每个脉冲单独记录电平极性——从第一个脉冲的电平开始后续自动交替。回放时只要先读回脉冲编码的档位再映射为实际微秒数按顺序翻转引脚即可。如果后续要做协议解码模式NEC的压缩更极端——只存8位地址和8位命令共2字节或含反码校验4字节回放时固件按固定时序生成引导码、数据位和反码。但这需要额外的协议类型字段对通用记录仪来说不是必须的。4.4 重放逻辑38kHz载波如何生成回放时最核心的问题是如何生成38kHz的载波。Arduino环境下推荐用定时器比较匹配输出CTC模式直接产生38kHz方波接到发射LED的驱动三极管上。当固件需要发送高电平即载波出现时打开定时器输出需要发送低电平即载波暂停时关闭定时器输出。有一个细节容易被忽视从关闭到重新打开载波定时器相位最好保持连续否则可能出现半个载波周期的毛刺。实际测试中相位连续性对大多数接收头影响很小但如果你对信号质量要求高可以尝试把定时器一直运行用输出比较寄存器控制引脚输出而不是直接关闭定时器。在STM32平台上可以做得更精细直接PWM输出缓冲按脉冲数组控制CCR寄存器的使能/失效效果不亚于商用遥控器。5. 实测与调试录出来回放没反应怎么办纯理论堆完这些才是真正决定项目成败的地方。我第一次做这个记录仪的时候录完电视遥控器回放电视一点反应没有。回头看原因说穿了都简单但排查链路很值得分享。5.1 从录到放的完整自测链路拿到第一批录制数据后不要急着回放先在串口里打印脉冲宽度序列用肉眼检查它是否符合预期的NEC结构。正常来说你应该能看到类似这样的节奏第1个脉冲: 低电平 8900us 第2个脉冲: 高电平 4400us 第3个脉冲: 低电平 550us 第4个脉冲: 高电平 570us 第5个脉冲: 低电平 550us 第6个脉冲: 高电平 1680us ...如果前两个脉冲差距很大说明录制起点判定有问题如果数据位里混入大量不规则的超长脉宽大概率是环境光干扰或者接收头供电部分没有做好去耦。下面这张排查表能覆盖大多数问题现象常见原因解决方向录制波形里有一条超长电平环境光/遥控器电池不足增加接收头遮蔽降低录制触发阈值回放无反应但示波器看波形正常载波频率选错确认遥控器实际频率36/38/40kHz回放距离短、角度窄发射电流不足增大峰值电流检查红外LED封装角度录到的脉冲宽度整体偏大/偏小中断延迟和micros误差改用定时器时间戳减少中断工作量按键刚按的一下录不到触发条件设置过于严格允许重复码作为有效触发5.2 手机摄像头是意外好用的探测工具调试阶段最好用的工具不是示波器而是手机摄像头。几乎所有的Android手机前置摄像头都能看到红外LED的发光——发射时会在屏幕上出现一个紫白色光点或者光晕。回放时用手机摄像头对准红外发射管再按回放键如果能看到连续闪动说明载波和脉冲逻辑至少已经工作了。iPhone的前置摄像头通常有红外滤光片拍不到红外光但很多iPhone的后置摄像头在特定角度下能拍到微弱的紫光这个实验值得试一下。更严谨的做法是用一个旧遥控器对着手机摄像头按按键先把摄像头验证好再测试自制的发射电路。5.3 环境遮蔽和供电滤波环境光是接收头最大的敌人晴天从窗户射进来的阳光在某些时段会直接淹没38kHz解调窗口导致接收头输出持续的杂波。给接收头套一截黑色热缩管作为遮光罩只留正面开孔算是成本最低且非常有效的手段供电端则建议在接收头正极到地之间并联一个10uF电解电容和一个100nF陶瓷电容并且尽量靠近接收头引脚布置这能显著减少毛刺。6. 进阶扩展方向与我的体会核心功能稳定之后这个项目有很多可以继续挖的方向。这里列三个我认为最有价值的。6.1 给记录仪配上蓝牙或Wi-Fi接上ESP32之后你可以把录制好的指令通过MQTT或HTTP暴露出来在手机App上一键触发。配合智能音箱和中控平台就能用一个设备抄走家里的各种遥控器实现统一的语音控制。ESP32最大的坑是Wi-Fi栈的实时性——在回放红外信号的临界时刻尽量使用多核并行并设置中断优先级否则Wi-Fi任务可能抢占时序导致波形出现毛刺。6.2 从原始波形反推协议录制大量真实遥控器波形后自然会想做一个协议识别引擎根据引导码、脉冲宽度分布和重复码特征自动判断是NEC、RC5、SONY还是未知格式然后自动解码成结构化数据。这个功能适合数据结构和算法功底扎实的人去挑战做完之后你会发现所有以脉冲时序为载体的通信协议底层逻辑是相通的。6.3 一些细节与体会最后分享几条个人经验。第一红外信号记录仪本质上是一个波形回放器不是万能遥控器——遇到RF射频遥控、蓝牙遥控、Wi-Fi遥控它无能为力做之前要有这个预期。第二外壳用3D打印或者简陋的洞洞板加塑料盒都行但一定把接收头和发射管隔得远一点否则回放时发射管的光可能直接串进接收头里造成自激。第三代码层面养成给每个脉冲打日志的习惯就算项目做完了也别删后续解码调试时这些日志能救你一次又一次。我做这个项目的最大感受是很多平时觉得玄学的设备原理亲手录一份波形、画一条时间轴就全通了。整个过程不依赖昂贵设备可能你抽屉里已经躺着所有需要的零件。如果你也遇到过遥控器找不着的瞬间不妨动手搭一个比买成品遥控器有意思得多。
返回列表