有人可以解释如何使用8位二进制加法计算校验和吗?这是文档的摘录:
这是消息的一般形式:
STX | TYPE | FS | DATA | FS | CHK | ETX
STX是HEX 02
ETX是HEX 03
FS是HEX 15
“类型”是唯一的1字节消息标识符(例如,用于轮询消息的“P”)。 “数据”包含可打印的ASCII字符。
校验
校验和是根据<FS>
和<STX>
之间的所有字符计算的,包括所有<CHK>
个字符。 校验和通过所有包含字符的8位二进制加法计算,其中第8个或奇偶校验位假定为零。超出第8位的数据将丢失。 8位结果将转换为两个可打印的ASCII十六进制字符,范围从00到FF,然后作为<CHK>
插入到数据流中。十六进制字符A-F是大写的。接收设备重新计算缓冲消息的校验和,并将其与收到的校验和进行比较。比较是后续确认(<ACK>
)或否定确认(<NAK>
)的基础。
答案 0 :(得分:5)
将每个字符视为整数值。由于每个字符的高位假设为零(如规范中没有说你需要检查它),用这样的东西掩盖它的值(伪C / C ++ / Java /等等) ):
get_next_character() & 0x7f;
现在你只需要添加(伪C / C ++ / Java /等等):
int s = 0;
while(!end_of_string())
{
s += get_next_character() & 0x7f;
s &= 0xff;
}
这将连续添加每个ASCII字符,并从结果总和中删除第8位之后的所有内容。当你全部完成时(C或写得不好的C ++):
printf("Checksum: %02x\n", s); /* You may need %02X for uppercase.
I don't remember my printf codes anymore. */
作为优化(如果你真的需要它 - 在这种情况下不太可能!)你可以推迟s &= 0xff
位,而是在校验和的使用点使用截断。但是这不会对性能有很大帮助 - 你的I / O将会更加昂贵 - 并且当你重构代码时,可能会在以后忘记这样做。
答案 1 :(得分:4)
如需添加,请使用以下功能。
function Summatory(const Data: AnsiString): Byte;
var
C: AnsiChar;
begin
Result := 0;
for C in Data do
begin
Result := Result + Ord(C);
end;
end;
对于旧版本的Delphi,没有“for in”:
function Summatory(const Data: AnsiString): Byte;
var
I: Integer;
begin
Result := 0;
for I := 1 to Length(Data) do
begin
Result := Result + Ord(Data[I]);
end;
end;
函数Summatory被声明为Byte,因此它将“忽略”超出第8位。您可以传递要添加的所有字节。
使用IntToHex
中的SysUtils
函数将8位结果转换为两个可打印的ASCII十六进制字符。
例如:ChkSum := IntToHex(Summatory(Data), 2);
答案 2 :(得分:0)
这个(未经测试的)类JavaScript函数能解决您的问题吗?
function calc_checksum( DATA ) {
var i;
var checksum = 0;
for ( i = 0; i < DATA.length; ++i ) {
checksum += DATA[i]; // any carry just falls off the high-order end
}
return 0x7F & checksum;
}
答案 3 :(得分:0)
在Java中,您可以执行以下操作。
byte[] bytes =
byte total = 0;
for(byte b: bytes) total += b;
OutputStream os =
os.write(total);
答案 4 :(得分:0)
当字节的总和超过256时,以上答案均无效。
OP可能正在尝试将 Siemens Dimension EXL200 化学分析仪与他的 _Lab信息系统连接。
他发布的段落(关于校验和的规范)是从其手册中复制/粘贴的。 在过去的12个小时里,我一直在努力应对这个特殊的问题,却找不到解决的办法。 我包括了西门子手册中提到的一些字符串,因为它们提供了校验和。
您会注意到,以上所有答案均有效,但仅适用于某些字符串。 在其他情况下,手册中的校验和与我们使用上面发布的方法获得的校验和完全不同。
我要发布两个示例,1个失败,1个成功=>相同的算法。
为方便起见(由于该协议使用十六进制字符,因此我包括了实际的字节数组,以便任何阅读此内容的人都可以使用他/她选择的语言进行尝试)。 我希望有人可以在这里找到解决方案:
/***
RAW STRING:
P<FS>9300<FS>1<FS>1<FS>0<FS>
BYTE ARRAY:
{80, 28, 57, 51, 48, 48, 28, 49, 28, 49, 28, 48, 28}
EXPECTED CHECKSUM :
6C
ACTUAL CHECKSUM :
3A
CODE TO REPRODUCE BELOW:
***/
byte[] byteArry = {80, 28, 57, 51, 48, 48, 28, 49, 28, 49, 28, 48, 28};
String ss = new String(byteArry);
int s = 0;
for(int i = 0; i < ss.length(); i++)
{
s += ss.charAt(i) & 0x7f;
s &= 0xff;
}
System.out.println(s);
System.out.format("Checksum: %02X\n", s);
}
/***
RAW STRING:
M<FS>A<FS><FS>
BYTE ARRAY:
{77, 28, 65, 28, 28}
EXPECTED CHECKSUM :
E2
ACTUAL CHECKSUM :
E2
CODE TO REPRODUCE BELOW:
***/
byte[] byteArry = {77, 28, 65, 28, 28};
String ss = new String(byteArry);
int s = 0;
for(int i = 0; i < ss.length(); i++)
{
s += ss.charAt(i) & 0x7f;
s &= 0xff;
}
System.out.println(s);
System.out.format("Checksum: %02X\n", s);
}
考虑到以上示例,我注意到,一旦字节的总和超过某个值(我无法确定),它似乎就会失败,但是我认为它大约为256。高于256的任何值都会产生结果有别于西门子员工想要的东西。 第一个示例已大大超过256,但第二个示例已超过226。手册中还有另一个示例,其字节和甚至更小,上面的代码似乎可以正常工作,产生了预期的校验和。 我不是一个很好的程序员,但是我敢肯定这与溢出有关。
Bhargav R。