在实现一个无线门铃产品时,不得不接触一下433。空研究了好几天,终于有一些眉目,这里记录一些研究感想。门铃协议中的专业术语比较多,比如OOKManchester code、433的模组又有很多型号,随便钻入某个专业词不得几天爬不出来,这期间还借助claude、ChatGPT、Gemini的帮助下来了解,这个AI工具就像汽车,如果不会使用提示词,也是和搜索引擎差不多,所以还得自身的驾驶技术过硬才可以。

了解一个新技术,我喜欢先找靠山,对于433我因为手上有PulseView逻辑分析仪,就以它为靠山。它抓取的信号可以使用内置的协议解析,比较找到两个相关的一个是OOKRC encode,我在OOK中陷入了很久出不来,不过最终在后者RC encode的帮助下理解这种协议了。

实现官网例子

开源逻辑分析仪协议解析官网有RC encode介绍,其中还给出一个例子,以应试教育的心态,如果自己造出和该参考答案一致的图形,那么说明算对433有了初步的了解。

有帮助的截图
sigrok官网RC encode 例子

使用Arduino生产波形

参考《使用 Arduino 和 RC Switch 逆向遥控器》写出如下Arduino代码:

/*
  Example for different sending methods
  
  https://github.com/sui77/rc-switch/
  
*/

#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {

  Serial.begin(9600);
  
  // Transmitter is connected to Arduino Pin #10  
  mySwitch.enableTransmit(10);

  // Optional set pulse length.
  // mySwitch.setPulseLength(320);
  
  // Optional set protocol (default is 1, will work for most outlets)
  // mySwitch.setProtocol(2);
  
  // Optional set number of transmission repetitions.
  // mySwitch.setRepeatTransmit(15);
  
}

void loop() {

  /* Same switch as above, but using decimal code */
  mySwitch.send(5393, 24);  // 5393 表示发送的信号代码, 24 表示数据长度。
  delay(1000);              // 暂停 1000 毫秒后再执行下一行代码。
  mySwitch.send(5396, 24);
  delay(1000);  

  delay(20000);
}

逻辑分析仪接上之后读取的波形如下所示:

有帮助的截图
生成Button D信号

经过参考答案是A,我们自己能生产相近的D,至于为了PulseView为何认为是这两字母,是ASCII还是HID或者UNICODE暂时不清楚,继续生产了数字1、2的波形如下,开始了解到规律,RC encode中出现U不必惊慌,自动读波形才更加准确,窄波形是0、宽波形是1,正好24位。

有帮助的截图 有帮助的截图
数字1 数字2

生成参考答案

通过查询参考答案对应的数值,使用计算器转换为16进制后是0x111154,将其写入代码支持并抓取波形,如右图所示,生成了 Button A的波形。

有帮助的截图 有帮助的截图
查询参考答案对应的数值 生成 Button A

代码如下:

#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();

void setup() {
  Serial.begin(115200);
  // Transmitter is connected to Arduino Pin #10  
  mySwitch.enableTransmit(10);
  
}

void loop() {
  /* Same switch as above, but using decimal code */
  mySwitch.send(0x111154, 24);  // 0x111154 表示发送的信号代码, 24 表示数据长度。
  delay(1000);              // 暂停 1000 毫秒
}

RCSwitch参数与PulseView图示对照

以上算是快速理解,本小节对比一下参数。RCSwitch可以很容易生产波形,并被PulseView抓取显示。如果先有了PulseView抓取的波形,想来匹配使用RCSwitch来接收解析和发送,则需要能根据波形总结出参数的能力。库代码中有这么一段注释来说明:

/* Format for protocol definitions:
 * {pulselength, Sync bit, "0" bit, "1" bit, invertedSignal}
 * 
 * pulselength: pulse length in microseconds, e.g. 350
 * Sync bit: {1, 31} means 1 high pulse and 31 low pulses
 *     (perceived as a 31*pulselength long pulse, total length of sync bit is
 *     32*pulselength microseconds), i.e:
 *      _
 *     | |_______________________________ (don't count the vertical bars)
 * "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
 *     and 3 low pulses, total length (1+3)*pulselength, i.e:
 *      _
 *     | |___
 * "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
 *      ___
 *     |   |_
 *
 * These are combined to form Tri-State bits when sending or receiving codes.
 */
static const RCSwitch::Protocol PROGMEM proto[] = {
   { 350, {  1, 31 }, {  1,  3 }, {  3,  1 }, false },    // protocol 1

我来将这些参数直接标注在波形图上

有帮助的截图
如何读信号

pulselength(350)

注意这个参数不是周期,而是高电平的宽度

有帮助的截图
pulselength(350)

Sync bit{ 1, 31 }

两段波形中间低电平的宽度

有帮助的截图
Sync bit{ 1, 31 }

“0” bit and “1” bit

0和1分别的占空比

有帮助的截图
“0” bit and “1” bit

nSeparationLimit

这个参数在库中被固定的设置为了4300,根据其注释应该是和Sync bit,比如pulselength * 30 = 10500,只要小于该10500即可。比如我测试的波形是pulselength是34us,合适的值是34 * 30 = 1020,如果还使用默认的4300则就抓取不到正确信号。这个是重点。

总结

了解的时候应该避免上来就去选择433发射接收模组,也尽可能不要在自定义的数据中徘徊,找到公认的靠山,死磕就能磕明白。按照现在的总结, PulseView的解析也不是十分的精准,如果不准确的东西太多,那就没有办法有策略的来熟悉这种协议。我其实到现在也不清楚会何PulseView在解析bits(第一行)的时候会把两位当成1位,这样的话就没有办法正确读取。