3、LoRa数据包结构详解:前导码、同步字、报头、净荷、CRC校验

各位同学,咱们今天来聊聊LoRa数据包的结构。说实话,很多做LoRa开发的朋友,上来就调库、发数据,但数据包在空中的样子,可能从来没仔细看过。我个人觉得,搞通信的人,一定要把数据包的每一段都吃透,不然出了问题你都不知道从哪查起。

LoRa的数据包结构,说白了就是五段:前导码、同步字、报头、净荷、CRC校验。咱们一段一段拆开讲。

3.1 前导码(Preamble)—— 唤醒接收机的敲门砖

前导码是数据包的第一段。它的作用是什么?很简单,就是告诉接收机:“嘿,注意了,我要发数据了!”

接收机平时处于低功耗的监听模式,它需要检测到前导码才能知道有数据来了。前导码是一串固定的、已知的码片序列。接收机通过检测这个序列,来同步时钟和频率偏移。

前导码的长度可以配置,默认是12个符号长度。但我在项目中遇到过一个问题:如果前导码太短,接收机可能来不及同步,导致丢包;如果太长,又会增加功耗和占用信道时间。

我的经验:在低功耗场景下,我习惯把前导码设成8个符号。如果通信距离远、干扰大,我会增加到16个符号。你想想看,接收机需要花时间检测前导码,太短了它还没反应过来,数据就来了。

前导码的格式其实很简单,就是连续的“1”和“0”交替的码片。接收机通过检测这个模式,就能锁定信号的起始位置。

3.2 同步字(Sync Word)—— 区分不同网络的身份证

前导码之后,紧跟着的就是同步字。同步字的作用是区分不同的LoRa网络。说白了,就是告诉接收机:“这个数据包是发给你的网络的,不是隔壁老王那个网络的。”

LoRa的同步字默认是0x12和0x34。但你可以修改它。我记得有一次做项目,两个LoRa网络在同一个区域工作,结果数据互相串扰。后来我把其中一个网络的同步字改成了0xAB和0xCD,问题就解决了。

注意:同步字必须发送端和接收端一致,否则接收机会直接丢弃数据包。我曾经见过有人改了发送端的同步字,忘了改接收端,结果折腾了一整天找问题。

同步字在数据包中的位置,紧接在前导码之后。它的长度是固定的,2个字节。接收机检测到同步字后,就知道这个数据包是发给自己的,然后继续解析后面的内容。

3.3 报头(Header)—— 数据包的说明书

报头是数据包的第三段。它包含了数据包的元信息,比如净荷长度、编码率、是否使用CRC等。说白了,报头就是数据包的说明书,告诉接收机怎么解析后面的数据。

LoRa有两种报头模式:显式报头和隐式报头。

  • 显式报头:默认模式。报头会包含净荷长度、编码率、CRC标志等信息。接收机通过解析报头,就知道后面该收多少数据。
  • 隐式报头:报头被省略了。发送端和接收端需要事先约定好净荷长度、编码率等参数。这种模式适合固定数据包长度的场景。

我个人习惯在大多数场景下使用显式报头,因为灵活。但如果你做的是传感器数据上报,每次数据长度都一样,用隐式报头可以省掉报头的开销,提高传输效率。

关键点:显式报头会占用额外的传输时间,但提供了灵活性。隐式报头省掉了报头,但需要双方事先约定参数。你想想看,哪个更适合你的项目?

报头的结构是这样的:

显式报头格式:
- 净荷长度(1字节):表示后面净荷的字节数
- 编码率(1字节):表示前向纠错的编码率
- CRC标志(1位):表示是否使用CRC校验
- 保留位(7位):预留的位,通常为0

3.4 净荷(Payload)—— 真正要传的数据

净荷就是数据包的核心内容,也就是你真正想传的数据。比如传感器的温度值、开关的状态、控制指令等。

净荷的长度是有限制的。LoRa的净荷最大长度取决于扩频因子和编码率。一般来说,扩频因子越大,净荷长度越小。举个例子,SF7时净荷最大可以到255字节,但SF12时可能只有几十个字节。

我在项目中遇到过一个问题:有一次我想传一个比较大的数据包,结果发现发送失败了。后来一查,原来是净荷长度超过了当前扩频因子下的最大值。嗯,这里要注意,设计协议时一定要考虑净荷长度的限制。

净荷的格式完全由你自己定义。你可以用JSON、二进制、或者自定义的协议。我个人建议用二进制格式,因为效率高、占用空间小。比如温度值用2字节的整数表示,湿度用1字节的整数表示,这样解析起来也快。

我的建议:净荷设计时,尽量用固定长度。如果必须用变长,一定要在净荷开头加一个长度字段,方便接收端解析。我曾经见过有人用变长净荷但没加长度字段,结果接收端解析得一塌糊涂。

3.5 CRC校验—— 数据完整性的守护神

CRC是数据包的最后一段。它的作用是检测数据在传输过程中是否发生了错误。说白了,就是检查数据有没有被干扰、有没有丢位。

LoRa支持两种CRC模式:净荷CRC和报头CRC。

  • 净荷CRC:对净荷部分进行CRC校验。如果CRC校验失败,接收机会丢弃这个数据包。
  • 报头CRC:对报头部分进行CRC校验。如果报头CRC校验失败,接收机也会丢弃数据包。

CRC的算法是标准的CRC-16,多项式是0x8005。你不需要自己实现,LoRa芯片内部已经集成了CRC计算模块。

警告:千万不要为了省那一点点传输时间而关闭CRC!我曾经在一个项目中关闭了CRC,结果数据偶尔出错,排查了三天才发现是CRC的问题。从那以后,我再也不敢关CRC了。

CRC校验失败后,接收机会怎么做?它会丢弃这个数据包,然后继续监听下一个数据包。发送端如果开启了确认机制,会重传数据包。如果没有确认机制,数据就丢了。

3.6 数据包结构总结

好了,咱们把LoRa数据包的五个部分都讲完了。来,我画个表格总结一下:

字段 作用 长度 可配置
前导码 唤醒接收机,同步时钟 可配置(默认12符号)
同步字 区分不同网络 2字节
报头 描述净荷的元信息 显式/隐式
净荷 真正要传输的数据 可变(受SF限制)
CRC 检测数据完整性 2字节

你想想看,这五个部分缺一不可。前导码负责唤醒,同步字负责区分网络,报头负责描述数据,净荷负责承载内容,CRC负责保证正确性。任何一个环节出问题,数据包都可能传不过去。

我记得刚开始做LoRa开发时,总觉得这些细节不重要,能用就行。后来遇到各种奇怪的问题,才明白每一个字段都有它的设计道理。嗯,这里要提醒大家,做通信开发,一定要把数据包结构吃透,不然出了问题你都不知道从哪查起。

下一章咱们会讲如何自定义LoRa协议,包括如何设计净荷格式、如何实现确认重传机制等。到时候咱们再深入聊。