8位二进制加法

时间:2011-02-25 10:22:24

标签: java algorithm delphi binary checksum

有人可以解释如何使用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>)的基础。

5 个答案:

答案 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个成功=>相同的算法。

为方便起见(由于该协议使用十六进制字符,因此我包括了实际的字节数组,以便任何阅读此内容的人都可以使用他/她选择的语言进行尝试)。 我希望有人可以在这里找到解决方案:

  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);
}

  1. 示例二:@仅是我的正确观点的解决方案成功:
/***


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。