红外信号需经硬件接收、内核驱动解码(如ir-lirc-codec)后,通过/dev/lirc0或/sys/class/rc/rc0/event传入c++程序;自行解析须处理载波、脉宽容差及协议校验,优先使用lircd服务确保可靠性。

红外信号怎么从硬件进到 C++ 程序里
C++ 本身不直接“听”红外,得靠硬件(比如 VS1838B 接 GPIO)+ 驱动层把原始电平变化转成时间戳序列。常见路径是:红外接收头 → GPIO 中断或定时器采样 → 内核驱动(如 ir-lirc-codec)→ 用户态通过 /dev/lirc0 读取解码后的键值,或读 /sys/class/rc/rc0/event 获取原始脉宽数据。
如果你跳过驱动、自己用 GPIO 轮询或中断抓波形,就得处理载波频率(通常 38kHz)、逻辑高/低电平持续时间(比如 NEC 协议中 560μs 脉冲 + 560μs 间隔是“0”,560μs + 1690μs 是“1”),这非常容易因定时精度不足或中断延迟导致误判。
- 别用
std::this_thread::sleep_for做延时采样——毫秒级精度根本不够,会漏掉关键边沿 - Linux 下优先走
lircd服务,它已适配多数红外接收芯片,ir-ctl -r可实时查看原始脉宽,比自己写驱动稳妥得多 - 树莓派等平台若启用了
gpio-ir内核模块,cat /sys/class/rc/rc0/protocols应显示rc-5 nec rc-6 jvc sony等,说明协议支持已就绪
用 lircd 读键值时为什么总是返回 UNKNOWN
不是 C++ 写错了,大概率是红外协议没对上,或者 lircd 没加载对应解码器。NEC、RC-5、Sony 这些协议的起始码、位数、校验方式全不同,lircd 默认只启用部分协议,且依赖硬件上报的原始脉宽是否落在识别窗口内。
- 先确认硬件是否真收到信号:
mode2 -d /dev/lirc0—— 如果没输出任何数字,说明物理链路或驱动没通 - 检查当前启用的协议:
ir-keytable -p,若输出里没有nec,就运行ir-keytable -p nec手动开启 -
ir-ctl -r输出的脉宽序列如果全是1234 567 1234 567...这种规律重复值,说明接收头被环境光干扰或供电不稳,不是协议问题 - C++ 里用
open("/dev/lirc0", O_RDONLY)后,read()到的是struct lirc_scancode,其中scancode是厂商码+命令码拼成的整数,别直接当 ASCII 字符打印
自己解析 NEC 脉宽时怎么判断逻辑 0 和 1
NEC 协议里一个比特由“引导脉冲 + 间隔”组成,关键不是绝对时间,而是相对比例。标准定义:脉冲固定约 560μs,之后间隔为 560μs(逻辑 0)或 1690μs(逻辑 1)。但实际硬件有±15% 偏差,所以必须用容差匹配,不能写死 == 560。
立即学习“C++免费学习笔记(深入)”;
- 先用
ir-ctl -r抓一段真实按键输出,观察典型值范围,比如你看到间隔列常在500–620和1500–1800两簇分布,那就设阈值为 1000μs - 起始引导码是 9ms 脉冲 + 4.5ms 间隔,这个必须先识别成功,否则后面全错;很多遥控器发完键值还会发重复码(9ms+2.25ms),要区分避免重复触发
- C++ 里存脉宽建议用
std::vector<uint32_t></uint32_t>,别用浮点——微秒级整数足够,且避免浮点比较陷阱 - 别忘了地址码和命令码是反码校验:
address + address_inv == 0xFF且command + command_inv == 0xFF,这是防误触发的关键一环
为什么同一个遥控器在不同设备上识别结果不一致
根本原因是红外接收电路的滤波特性、GPIO 中断响应延迟、内核驱动采样策略不同。VS1838B 和 IRM-3638 对噪声抑制能力不同,树莓派的 gpio-ir 模块默认用 100μs 分辨率采样,而某些嵌入式平台用 50μs,同样一段波形会被切出不同脉宽序列。
- 别迷信“标准 NEC”——格力、美的空调遥控器常用自定义 NEC 变种:地址码 16 位、命令码 16 位、无校验,
lircd默认配置不认,得改/etc/lirc/lirc_options.conf加driver = default和自定义lircd.conf - USB 红外接收器(如 RedRat)自带固件解码,输出已是键值,不经过脉宽阶段,和 GPIO 方案完全不在同一抽象层,混用会导致调试混乱
- 用
strace -e trace=read,write跟 C++ 程序读/dev/lirc0的行为,能快速确认是数据源问题还是程序解析问题
红外这事,硬件链路比代码难调十倍。脉宽数值漂移、电源纹波、LED 干扰、甚至遥控器电池电量,都可能让 560 变成 490 或 630。先用 mode2 和 ir-ctl -r 把真实波形钉死,再动 C++,不然永远在猜。










