8位二进制加法

发布于 2024-10-18 23:13:56 字数 686 浏览 4 评论 0原文

有人能解释一下如何用8位二进制加法计算校验和吗?这是文档的摘录:

这是消息的一般形式:

STX | TYPE | FS | DATA | FS | CHK | ETX

STX 是十六进制 02

ETX 是十六进制 03

FS 是十六进制 15

“类型”是唯一的 1 字节消息标识符(例如,“P”表示轮询)信息)。 “数据”包含可打印的 ASCII 字符。

校验和 校验

和是根据 之间的所有字符计算的,包括所有 字符。 CHK>校验和是通过将所有包含的字符进行 8 位二进制加法计算得出的,其中第 8 位或奇偶校验位假定为零。超过第 8 位的进位将丢失。8 位结果被转换为两个可打印的 ASCII 十六进制字符,范围从 00 到 FF,然后作为 .十六进制字符 AF 为大写。接收设备重新计算缓冲消息的校验和,并将其与收到的校验和进行比较。该比较是后续传输确认 () 或否定确认 () 的基础。

Can someone explain how to calculate checksum with 8-bit binary addition? This is an excerpt from the documentation:

This is the general form of the messages:

STX | TYPE | FS | DATA | FS | CHK | ETX

STX is HEX 02

ETX is HEX 03

FS is HEX 15

The "type" is a unique, 1-byte message identifier (e.g., 'P' for Poll message).
"Data" contains printable ASCII characters.

Checksum

The Checksum is computed on all characters, including all the <FS> characters, between <STX> and <CHK>. The Checksum is calculated by the 8-bit binary addition of all included characters with the 8th or parity bit assumed to be zero. Carries beyond the 8th bit are lost. The 8-bit result is converted into two printable ASCII Hex characters, ranging from 00 to FF, which are then inserted into the data stream as <CHK>. The Hex characters A-F are uppercase. The receiving device recalculates the checksum on the buffered message and compares it with the checksum it received. The comparison is the basis for subsequent acknowledgement (<ACK>) or negative acknowledgement (<NAK>) of the transmission.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

半透明的墙 2024-10-25 23:13:56

将每个字符视为整数值。由于每个字符的高位假设为零(正如规范中没有说你需要检查它),用这样的东西掩盖它的值(伪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 将会更加昂贵——并且可能会导致您在稍后重构代码时忘记这样做。

Treat each character as an integer value. Since each character's high bit is assumed to be zero (as in the spec doesn't say you need to check it), mask its value with something like this (pseudo-C/C++/Java/whatever):

get_next_character() & 0x7f;

Now you just do the add (pseudo-C/C++/Java/whatever):

int s = 0;
while(!end_of_string())
{
    s += get_next_character() & 0x7f;
    s &= 0xff;
}

This will consecutively add each ASCII character and remove everything past the 8th bit from the resulting sum. When you're all finished (C or badly-written C++):

printf("Checksum: %02x\n", s);  /* You may need %02X for uppercase.
                                   I don't remember my printf codes anymore. */

As an optimization (if you really need it -- unlikely in this case!) you can defer the s &= 0xff bit and instead use the truncation at the point of use for the checksum. This won't save you much on performance, however -- your I/O will be far more expensive -- and leads to the possibility of you forgetting to do it at some later date when you refactor your code.

征﹌骨岁月お 2024-10-25 23:13:56

如需添加,请使用以下函数。

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 位的进位。您可以传递要添加的所有字节。

使用 SysUtils 中的函数 IntToHex 将 8 位结果转换为两个可打印的 ASCII 十六进制字符。

例如:ChkSum := IntToHex(Summatory(Data), 2);

For addition, use the following function.

function Summatory(const Data: AnsiString): Byte;
var
    C: AnsiChar;
begin
    Result := 0;

    for C in Data do
    begin
        Result := Result + Ord(C);
    end;
end;

For older versions of Delphi, with no "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;

The function Summatory is declared as Byte, so it will "ignore" carries beyond the 8th bit. You can pass all of the bytes that you want to add.

Use the function IntToHex from SysUtils to converted the 8-bit result into two printable ASCII Hex characters.

Ex: ChkSum := IntToHex(Summatory(Data), 2);

暮倦 2024-10-25 23:13:56

在 Java 中,您可以执行以下操作。

byte[] bytes =
byte total = 0;
for(byte b: bytes) total += b;

OutputStream os = 
os.write(total);

In Java you can do the following.

byte[] bytes =
byte total = 0;
for(byte b: bytes) total += b;

OutputStream os = 
os.write(total);
瘫痪情歌 2024-10-25 23:13:56

当字节总和超过 256 时,上述答案都不起作用。OP

可能试图将 Siemens Dimension EXL200 化学分析仪与其 _Lab 信息连接起来系统。

他发布的段落(关于校验和的规范)是从他们的手册中复制/粘贴的。
在过去的 12 个小时里,我一直在努力解决这个特殊问题,但找不到任何解决方法。
我包括了西门子手册中提到的一些字符串,因为它们提供了校验和。

您会注意到上面的所有答案都有效,但仅适用于某些字符串。
在其他情况下,手册中的校验和与我们使用上面发布的方法得到的完全不同。

我发布了两个例子,1个失败,1个成功=>相同的算法。

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

  1. 示例一:@Just My Correct Opinion's Solution 失败:
/***

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. 示例二:@Just My Correct Opinion's Solution SUCCEEDS:
/***


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。手册中还有一个字节和更小的示例,我们上面的代码似乎可以工作,生成预期的校验和。
我不是一个很好的程序员,但我确信这与溢出有关。

巴尔加夫·R.

None of the answers above work, when the sum of the bytes crosses 256.

The OP was probably trying to interface a Siemens Dimension EXL200 chemistry analyzer with his _Lab information system.

The paragraph he's posted (about the spec for the checksum) is copy/paste from their manual.
I've been banging my head against this particular problem for the last 12 hours and cannot find any way around it.
I am including some of the strings mentioned in the Siemens Manual, as they have provided the checksums.

You will notice that all the answers above work, but only for some of the strings.
In others, the checksum in the manual is completely different from what we get by using the methods posted above.

I am posting two examples, 1 failure, and 1 success => same algorithm.

For convenience(as the protocol uses HEX characters, I'm including the actual byte arrays, so that anyone reading this can try it in his/her language of choice).
I hope someone can find a solution here:

  1. Example One: @Just My Correct Opinion's Solution Fails:
/***

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. Example Two: @Just My Correct Opinion's Solution SUCCEEDS:
/***


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

Given the above examples, I've noticed that it seems to fail as soon as the sum of the bytes crosses a certain value(what I cannot be sure), but I think its around 256. Anything above 256 gives a result different from whatever the people at Siemens seem to want.
The first example has crossed 256 by a big margin, but the second one is at 226. There is another example in the manual of an even smaller byte sum, where our code above seems to work, producing the expected checksum.
I'm not a very good programmer, but I'm sure this has something to do with overflows.

Bhargav R.

简单气质女生网名 2024-10-25 23:13:56

这个(未经测试的)类似 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;
}

Does this (untested) JavaScript-like function solve your problem?

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文