Dee*_*hia 4 c algorithm gps checksum nmea
我正在尝试查找已经由GPS计算的NMEA语句的校验和。
char GPRMCBuf[POS_BUFFER] = {0xA0, 0xA2, 0x00, 0x48, 0xDD,
0x24, 0x47, 0x50, 0x52, 0x4D, 0x43, 0x2C, 0x31, 0x35,
0x30, 0x35, 0x32, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2C,
0x41, 0x2C, 0x34, 0x31, 0x32, 0x31, 0x2E, 0x37, 0x39,
0x37, 0x37, 0x2C, 0x4E, 0x2C, 0x30, 0x30, 0x32, 0x31,
0x30, 0x2E, 0x39, 0x36, 0x36, 0x37, 0x2C, 0x45, 0x2C,
0x31, 0x2E, 0x35, 0x30, 0x2C, 0x35, 0x38, 0x2E, 0x32,
0x39, 0x2C, 0x32, 0x33, 0x30, 0x37, 0x31, 0x35, 0x2C,
0x2C, 0x2C, 0x41, 0x2A, 0x35, 0x38, 0x0D, 0x0A, 0x0F,
0x05, 0xB0, 0xB3};
Run Code Online (Sandbox Code Playgroud)
听到最后3位和4位字符是校验和,即0F05,但我们想更正算法。我们使用的算法如下
Index = first,
checkSum = 0,
while index < msgLen,
checkSum = checkSum + message[index],
checkSum = checkSum AND (2^15-1).
increment index.
Run Code Online (Sandbox Code Playgroud)
我们编写的代码如下:
#include<stdio.h>
main()
{
unsigned char i;
unsigned short chk;
char test[]={ 0x47, 0x50, 0x52, 0x4D, 0x43, 0x2C, 0x31,
0x35, 0x30, 0x35, 0x32, 0x30, 0x2E, 0x30, 0x30,
0x30, 0x2C, 0x41, 0x2C, 0x34, 0x31, 0x32, 0x31,
0x2E, 0x37, 0x39, 0x37, 0x37, 0x2C, 0x4E, 0x2C,
0x30, 0x30, 0x32, 0x31, 0x30, 0x2E, 0x39, 0x36,
0x36, 0x37, 0x2C, 0x45, 0x2C, 0x31, 0x2E, 0x35,
0x30, 0x2C, 0x35, 0x38, 0x2E, 0x32, 0x39, 0x2C,
0x32, 0x33, 0x30, 0x37, 0x31, 0x35, 0x2C, 0x2C,
0x2C, 0x41,0x2A, 0x35, 0x38, 0x0D, 0x0A};
chk = 0;
for(i = 0; i < 70; i++)
{
chk = chk + test[i];
chk = chk & 32767;
}
printf("A=%hu\n", chk);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
问题是我们得到3588,但应该是3845(0F05)。
请帮助我们解决此算法。
小智 5
您已经做了很好的尝试,但是有一些错误。我认为以下链接是NMEA的良好起点:http : //www.gpsinformation.org/dale/nmea.htm
您会在介绍中看到,每个命令都是独立的,以$符号开头,以回车/换行符结尾。校验和(如果存在)位于消息末尾,并带有星号*。您还将看到校验和是$和之间的所有字节的XOR,*校验和以十六进制形式遵循*ASCII格式。
输入数据的开头和结尾都有一些噪音,需要将其丢弃。让我注释您的输入:
char GPRMCBuf[POS_BUFFER] = {
0xA0, 0xA2, 0x00, 0x48, 0xDD, // these bytes are not part of the message
0x24, // this is the '$' character, so this is the message start byte
// checksum calculation starts with the next byte (0x47)
0x47, 0x50, 0x52, 0x4D, 0x43, 0x2C, 0x31, 0x35, // GPRMC,15
0x30, 0x35, 0x32, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2C, // 0520.000,
0x41, 0x2C, 0x34, 0x31, 0x32, 0x31, 0x2E, 0x37, 0x39, // A,4121.79
0x37, 0x37, 0x2C, 0x4E, 0x2C, 0x30, 0x30, 0x32, 0x31, // 77,N,0021
0x30, 0x2E, 0x39, 0x36, 0x36, 0x37, 0x2C, 0x45, 0x2C, // 0.9667,E,
0x31, 0x2E, 0x35, 0x30, 0x2C, 0x35, 0x38, 0x2E, 0x32, // 1.50,58.2
0x39, 0x2C, 0x32, 0x33, 0x30, 0x37, 0x31, 0x35, 0x2C, // 9,230715,
0x2C, 0x2C, 0x41, // ,,A
// checksum calculation ends here
0x2A, // The '*' character, i.e. message/checksum delimiter
0x35, 0x38, // The checksum, '5' and '8', so the checksum is 0x58
0x0D, 0x0A, // The CR/LF line terminator
0x0F, 0x05, 0xB0, 0xB3 // these bytes are not part of the message
};
Run Code Online (Sandbox Code Playgroud)
因此,校验和计算为:
chk = 0;
chk = chk ^ 0x47; // chk = 0x47
chk = chk ^ 0x50; // chk = 0x17
chk = chk ^ 0x52; // chk = 0x45
...
chk = chk ^ 0x41; // chk = 0x58
Run Code Online (Sandbox Code Playgroud)
请注意,您最终将获得0x58,该消息在中显示为0x35 0x38。因此,一旦您正确地构造了消息并调整了for循环以遍历校验和字节,循环主体就变成了:
chk ^= test[i];
Run Code Online (Sandbox Code Playgroud)
循环之后,您需要将的两个半字节转换chk为ASCII并与信号校验和进行比较,或者将信号校验和转换为二进制值并与进行比较chk。