4. 校验和计算与验证实战
在NMEA 0183报文中,校验和(Checksum)是判断一条语句在传输过程中是否发生位错误的最直接手段。它位于语句末尾的“*”之后,由两位十六进制大写字符组成。理解它的算法并能够手工复算,是识读报文的基本功——当设备显示的数据异常时,第一步往往就是确认这条报文本身是否完整可信。
异或校验算法:逐字符异或
NMEA校验和的计算范围有严格约定:从起始符“$”之后第一个字符开始,到“*”之前最后一个字符结束,不包含“$”和“*”本身。算法是把范围内所有字符的ASCII码逐字节进行按位异或(XOR),得到一个8位结果,再格式化为两位大写十六进制数。
异或运算有三个便于手工计算的性质:相同两数异或为0;任何数与0异或等于其本身;异或满足交换律,因此字符顺序不影响结果,但漏算或多算一个字符一定会改变结果。计算时通常维护一个累加变量,初值取0,每读入一个字符就执行一次“累加值 = 累加值 XOR 字符ASCII码”。
示例语句(GGA定位数据):
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
计算范围($ 与 * 之间):
GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,
逐字符异或过程(ASCII码,十六进制):
G(47) → 47
P(50) → 47^50 = 17
G(47) → 17^47 = 50
G(47) → 50^47 = 17
A(41) → 17^41 = 56
,(2C) → 56^2C = 7A
1(31) → 7A^31 = 4B
2(32) → 4B^32 = 79
3(33) → 79^33 = 4A
...(中间字符略)
最终累加结果 = 0x47
校验和字段写作:*47
上例中的“47”是用于讲解算法流程的示例值,实际复算时应以完整字符序列为准。手工计算时建议把字符按每5~8个一组分段,每段算完记录中间值,最后再合并,这样比一口气算完整串更不容易出错。对于较长的语句,可以借助计算器或脚本,但必须清楚输入范围是“$”之后到“*”之前。
验证流程:先定位范围,再比对结果
验证一条报文时,操作顺序应当是:找到“$”和“*”,截取中间子串;对子串逐字符异或;把结果格式化为两位大写十六进制;与“*”后两位逐字符比对。若一致,说明该语句在字符层面完整;若不一致,则该语句应被丢弃,不能把其中的字段当作有效数据使用。
常见校验错误原因
实际排查中,校验和不匹配通常集中在以下几类原因:
- 计算范围错误:把“$”或“*”计入范围,或把“*”后的校验和字符也算了进去,这是最常见的人为错误。
- 字符被改动:串口参数不匹配、线路干扰、电平转换异常导致个别字符丢失或被替换,尤其是逗号、数字被误读。
- 大小写与格式问题:校验和应为两位大写十六进制,若程序输出小写或只输出一位(如“*7”而非“*07”),严格解析器会判为不合法。
- 报文被截断或拼接:接收缓冲区处理不当,导致一条语句尾部缺失,或两条语句首尾粘连,校验范围自然错位。
- 换行符混入:部分实现误把CR/LF计入计算范围,或发送端在“*”前多加了空格。
排查时可采取“由外向内”的策略:先确认报文边界是否完整(是否有“$”开头、“*”加两位十六进制结尾),再确认计算范围,最后才怀疑算法实现。若同一设备的多条语句全部校验失败,优先怀疑串口参数或线路;若仅个别语句失败,则更可能是该条语句在生成或传输中被改动。
工具辅助验证方法
工程上常用三类手段辅助验证。第一类是串口调试工具,如常见的串口助手,可设置波特率4800或38400、8位数据位、无校验、1位停止位,观察原始字节流,确认报文边界与字符是否完整。第二类是脚本复算,用几行代码即可批量校验,适合分析录制的日志文件:
def nmea_checksum(sentence):
body = sentence.strip().lstrip('$').split('*')[0]
cs = 0
for ch in body:
cs ^= ord(ch)
return f"{cs:02X}"
# 示例:返回 "47"
print(nmea_checksum("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47"))
第三类是协议分析仪或带NMEA解析功能的导航测试软件,它们会在解析前自动校验并标记异常语句,便于快速定位问题报文。无论使用哪种工具,都应保留原始报文记录,避免工具“自动纠正”掩盖真实问题。
实战中的判断要点
把上述流程落到实际识读中,可以形成一条清晰的判断链:先看报文是否以“$”开头、以“*”加两位十六进制结尾,确认边界完整;再按“$”之后到“*”之前的范围复算;比对一致后,才进入字段解析与合理性判断。若不一致,按“串口参数与线路—报文边界—计算范围—算法实现”的顺序逐层排查,而不是直接怀疑设备故障。掌握这套方法后,面对任何一条陌生的NMEA语句,都能先独立判断其可信度,再决定是否采信其中的定位、航向或时间数据。