树莓派控制433MHz射频插座需重复运行程序才生效问题求解
问题描述
我尝试使用Raspberry Pi 3 B控制433MHz射频插座,采用433MHz发射模块与433Utils工具集,通过433MHz接收模块配合RFSniffer已验证插座开启码为-1900218880(对应十六进制0x8ebcf600),使用如下C++代码发送控制码:
#include "../../lib/433Utils/rc-switch/RCSwitch.h" #include <stdlib.h> #include <stdio.h> int main(int argc, char* argv[]) { int PIN = 0; // see wiringpi-belegung int codeSocketDon = 0x8ebcf600; int codeSocketDoff = 0x81bcf600; if (wiringPiSetup() == -1) { printf("wiringPiSetup failed."); return 1; } RCSwitch sw = RCSwitch(); sw.enableTransmit(PIN); if (atoi(argv[1]) == 1) sw.send(codeSocketDon, 32); else sw.send(codeSocketDoff, 32); return 0; }
该代码可正常编译,且RFSniffer可接收到程序发送的控制码,插座与发射模块距离仅约1米,但插座无法触发开启动作。
关于该配置失效原因的初始疑问可参考下方更新内容。
使用的软硬件组件清单
- Raspberry Pi 3 Model B v1.2
- 433 MHz收发模块 FS1000A XY-FST XY-MK-5V
- McPower Comfort射频插座套装
- Wiring Pi
- 433Utils
问题更新
我找到了一种可触发插座动作的方式,但该现象十分反常,暂不明确其生效逻辑:
上述代码通过编译指令g++ -DRPI ../../lib/433Utils/rc-switch/RCSwitch.cpp switch-socket.cpp -o switch-socket -lwiringPi编译生成可执行文件switch-socket,连续两次执行该程序(执行指令switch-socket 1 && switch-socket 1)即可成功开启插座。最初判断是单次发射时长过短,但调用RCSwitch.setRepeatTransmit(30)增大重发次数无效,在程序内单次执行两次发送逻辑无效,将完整控制逻辑放入for循环连续执行两次也无效。
咨询内容:为何连续两次独立运行程序可成功控制插座,以及如何修改C++代码实现单次运行程序即可正常控制插座动作。
原因说明
这个现象是廉价433MHz发射模块硬件特性叠加RCSwitch库初始化逻辑导致的:
- FS1000A这类低成本发射模块上电后无法立刻进入稳定工作状态,需要100~300ms的起振时间,这段时间输出的信号频率偏移大、波形畸变,插座内置的接收芯片无法正常解码。
- 连续两次独立运行程序时,第一次程序运行已经给发射模块供电完成起振,虽然第一次发出的信号无效,但第二次程序启动时模块已经处于稳定工作状态,输出的信号波形符合解码要求,因此可以触发插座动作。
- 同进程内循环发送、增大重发次数无效,是因为程序从启动到第一次发送的间隔太短,模块还没完成起振,后续同进程内的连续发送间隔仅几毫秒,模块始终没有进入稳定状态,输出的全是无效畸变信号。
修复方案
修改代码,增加模块上电稳定等待时间,调整发送间隔和参数即可,修改后的可运行代码如下:
#include "../../lib/433Utils/rc-switch/RCSwitch.h" #include <stdlib.h> #include <stdio.h> #include <wiringPi.h> int main(int argc, char* argv[]) { int PIN = 0; int codeSocketDon = 0x8ebcf600; int codeSocketDoff = 0x81bcf600; if (wiringPiSetup() == -1) { printf("wiringPiSetup failed."); return 1; } RCSwitch sw = RCSwitch(); sw.enableTransmit(PIN); // 等待FS1000A模块起振稳定,廉价模块建议至少留200ms以上延时 delay(300); // 按RFSniffer抓包得到的实际脉冲长度设置,McPower插座通常为300~350us sw.setPulseLength(320); // 重发次数设置为5~10次即可,过大会导致接收芯片缓存溢出无法解码 sw.setRepeatTransmit(8); int targetCode = atoi(argv[1]) == 1 ? codeSocketDon : codeSocketDoff; // 第一次发送(模块刚进入稳定阶段可能仍有小幅偏差) sw.send(targetCode, 32); // 两次发送间隔留100ms,模拟两次独立运行程序的时间间隔 delay(100); // 第二次发送,此时模块完全稳定,信号可被正常解码 sw.send(targetCode, 32); return 0; }
如果测试后仍有偶发失效,可以适当增大delay(300)的延时数值,或者用RFSniffer重新抓包确认准确的脉冲长度,替换setPulseLength的参数即可。
内容的提问来源于stack exchange,提问作者Spock

