简单的串行通信。 & 使用 C 计算 CRC16

Simple serial comm. & Calculating CRC16 using C

我有一个传感器,我希望从中获取一些数据。我想问它日期或要数据。

传感器采用RS-232; 9600 8N1 进行通信。

通信包由headerpayloadCRC[=54=组成].该手册提供了 header 和 payload 以供您执行任何操作。每个通信包的组成如下:

<SOH> header <STX> payload <ETB> CRC16 <ETX>

  • <SOH>: 0x01
  • <STX>: 0x02
  • <ETB>: 0x17
  • <ETX>: 0X03

如果你想查询日期,手册给出了一个例子,它告诉你 header 是 0x31,有效载荷是 0x41。

因此发送传感器的命令为:\x01\x31\x02\x41\x17\CRC16\x03

现在举个例子,手册给你计算了CRC16,在ASCII中是A0D5。 CRC16需要传输little endian。

现在完整的命令是: \x01\x31\x02\x41\x17\x44\x35\x41\x30\x03

该手册没有提供任何其他 CRC16 计算,它希望用户这样做很好:)


来自手册:每个数据包都由以十六进制 ASCII 编码(四个字符)传输的 16 位 CRC 验证。 CRC 是根据header+有效负载连接计算得到的

WORD CRC16_Compute( BYTE *pBuffer, WORD length )
{
  BYTE i;
  BOOL bs;
  WORD crc=0;

  while( length-- )
  {
    crc ^= *pBuffer++;
    for( i = 0; i < 8; i++ )
    {
       bs = crc & 1;
       crc >>= 1;
       if( bs )
       {
         crc ^= 0xA001;
       }
    }
  }
return crc;
}

那是 C 中的 CRC 计算器,我不太懂,但是他们只提供了这段代码片段,没有上下文。


在 ASCII 中,他们使用 1+A (0x31+0x41) 得到 2 个字节,A0D5。有人可以向我解释一下 CRC 代码的作用吗,谢谢!

#include <stdio.h>
typedef unsigned char BYTE;
typedef unsigned int BOOL;
typedef unsigned int WORD;
WORD CRC16_Compute( BYTE *pBuffer, WORD length )
{
  BYTE i;
  BOOL bs;
  WORD crc=0;

  while( length-- )
  {
    crc ^= *pBuffer++;
    for( i = 0; i < 8; i++ )
    {
       bs = crc & 1;
       crc >>= 1;
       if( bs )
       {
         crc ^= 0xA001;
       }
    }
  }
    return crc;
}
int main ( void )
{
    unsigned char data[2];
    unsigned char sdata[9];
    unsigned int x;
    unsigned int z;
    unsigned int i;

    data[0]=0x31;
    data[1]=0x41;
    x = CRC16_Compute(data,2);
    x&=0xFFFF;
    printf("0x%X\n",x);
    z=0;
    sdata[z++]=0x01;
    sdata[z++]=data[0];
    sdata[z++]=0x02;
    sdata[z++]=data[1];
    sdata[z++]=0x17;
    sdata[z  ]=((x>> 4)&0xF)+0x30; if(sdata[4]>0x39) sdata[4]+=7; z++;
    sdata[z  ]=((x>> 0)&0xF)+0x30; if(sdata[5]>0x39) sdata[5]+=7; z++;
    sdata[z  ]=((x>>12)&0xF)+0x30; if(sdata[6]>0x39) sdata[6]+=7; z++;
    sdata[z  ]=((x>> 8)&0xF)+0x30; if(sdata[7]>0x39) sdata[7]+=7; z++;
    sdata[z++]=0x03;
    for(i=0;i<z;i++) printf("%02X ",sdata[i]); printf("\n");
    return(0);
}

运行它

gcc so.c -o so
./so 
0xA0D5
01 31 02 41 17 44 35 41 30 03 

那个正确答案怎么样....

你需要知道的一切都在你的问题中,只要按照它说的去做。几分钟粗略地把它放在一起。

CRC is calculated from the header+payload concatenated

    data[0]=0x31;
    data[1]=0x41;

这是header和payload,它根据提供的CRC码给出正确的答案。

然后你用其他物品构建数据包。如果你 google ASCII table 你可以看到 'D' 'A' '0' '5' 的值并且可以弄清楚如何从 0xD 到 0x44 和 0xA 到 0x41但首先看0x0到0x30和0x5到0x35,0-9很容易但是0x0A给出0x3A但需要是0x41,所以你调整。

所以代码根据描述的评论按照描述的方式工作,我不知道这个传感器,他们这样做的方式看起来很愚蠢,但对他们提供示例和 crc16 的详细信息有好处多个标准变化,包括初始值,因此再次对他们有好处,因为他们可以节省大量时间来弄清楚...