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