【问题标题】:Appending CRC (Checksum) to data stream serial port communication C++将 CRC(校验和)附加到数据流串行端口通信 C++
【发布时间】:2016-01-28 13:20:42
【问题描述】:

我将 CRC 附加到数据流中。我正在为 Linux 和 Windows 使用来自 RS-232 的串行端口库。

我想得到和comport工具图片上显示的一样的值:

我正在使用const char[4086]="123456789"; 作为缓冲区。

返回的 CRC 是 bb3d,然后我将其从 unsigned short 转换为 char *

#define SERIALPORT_BUFSIZE       4088

char *im_buf = (char *)malloc(SERIALPORT_BUFSIZE  + 8);

char *tx_buf = (char *)malloc(SERIALPORT_RCV_BUFSIZE  + 8);

const char buf[SERIALPORT_BUFSIZE]="123456789";

strcpy(im_buf, buf);
WriteToSerialPort(); // call to function

void SerialPortCom::WriteToSerialPort(void)
{
    if(!port_open) return;

    int i,n, tmp, tmp2;

    if(newline == 1)
    {
        strcat(im_buf, "0a");
    }
    else if(newline == 2)
    {
        strcat(im_buf, "0d");
    }
    else if(newline == 3)
    {
        strcat(im_buf, "0d0a");
    }

    n = strlen(im_buf) / 2;

    if(n < 1) return;

    for(i=0; i< n; i++)
    {
        tmp = im_buf[i*2];

        if((tmp >= '0') && (tmp <= '9'))
        {
            tmp -= '0';
        }
        else if((tmp >= 'a') && (tmp <= 'f'))
        {
            tmp -= ('a' - 10);
        }
        else if((tmp >= 'A') && (tmp <= 'F'))
        {
            tmp -= ('A' - 10);
        }

        tmp *= 16;

        tmp2 = im_buf[(i*2)+1];

        if((tmp2 >= '0') && (tmp2 <= '9'))
        {
            tmp2 -= '0';
        }
        else if((tmp2 >= 'a') && (tmp2 <= 'f'))
        {
            tmp2 -= ('a' - 10);
        }
        else if((tmp2 >= 'A') && (tmp2 <= 'F'))
        {
            tmp2 -= ('A' - 10);
        }

        tmp += tmp2;

        tx_buf[i] = tmp;

    }
    //generate crc
    unsigned short crc  = GetCrc16(im_buf, strlen(im_buf));
    //append crc
    memcpy( tx_buf + n, &crc, 2 );
    //send to serial port
    RS232_SendBuf(comport_nr, (unsigned char *)tx_buf, n+2);

}

我得到了什么:(12 34 56 78 70 11 4A 3D)
我想要什么:(12 34 56 78 7B 34 FD FD FD FD)

如何达到预期效果?

unsigned short SerialPortCom::GetCrc16(const char* InStr,unsigned int len)
{
    //Crc16
    unsigned short Crc16Table[256];
    unsigned int i,j;
    unsigned short Crc;      
    unsigned char CRCHigh = 0xFF, CRCLow = 0xFF;

    for (i = 0; i < 256; i++)
    {
        Crc = i;
        for (j = 0; j < 8; j++)
        {
            if(Crc & 0x1)
                Crc = (Crc >> 1) ^ 0xA001;
            else
                Crc >>= 1;
        }
        Crc16Table[i] = Crc;
    }
    //CRC16
    Crc=0x0000;
    for(i=0; i<len; i++)
    {
        Crc = (Crc >> 8) ^ Crc16Table[(Crc & 0xFF) ^(uint8_t) InStr[i]];

    }
    //Crc ^= 0x0000;

    return Crc;
}

【问题讨论】:

    标签: c++ checksum crc


    【解决方案1】:

    首先,一些注意事项:

    • 您的输入是 ASCII 十六进制。每个字符是一个半字节,但您的输入字符串有奇数个字符:您丢弃最后一个字符。
    • 您期望的是12 34 56 78 7B 340x347B0x12 0x34 0x56 0x78 的CRC。额外的FDs 看起来像是一些无关紧要的缓冲区结束(或另一个错误?)。

    你的程序的问题:

    您需要使用RS232_SendBuf 发送数据缓冲区。您将 ASCII 转换为数据并将其放入 tx_buf,然后获取其 CRC。没关系,但是您使用 strcat 将 CRC 附加到缓冲区;你不能这样做,strcat 用于文本。 strcat 期望有两个以 null 结尾的字符串,但您有两个数据缓冲区。

    您的 CRC 函数也有问题:您有一个多余的掩码 &amp; 0x7F,它删除了每个 CRC 字节的最后一位。 0xFF 掩码就足够了(实际上甚至不需要)。

    您还使用new char[2] 分配了一个缓冲区,但从不使用delete 它。这会起作用,但它很丑。

    请注意,您的 CRC 只是两个字节;直接以unsigned short 的形式返回Crc

    之后,只需使用 memcpy 将 CRC 附加到缓冲区。
    在你的情况下,那将是memcpy( tx_buf + n, &amp;my_crc_short, 2 );

    【讨论】:

    • 感谢您的及时回复,我已经包含了我的 crc 功能,如果您能给我一个例子,我将不胜感激。我可以附上我已经使用了两个星期的 crc 的方法。谢谢
    • @MelFzllc 编辑了我的答案。
    • 谢谢@elderbug,你的例子很有见地。我已经编辑了我的问题,以反映我从你的指点中理解的内容。但是我仍然没有得到7B34 的价值,我得到了3D BBchar *im_buf 以及char *tx_buf 的各种价值。任何指针感谢您的帮助
    • @MelFzllc 那是因为当您想要数据的 CRC (0x12 0x34 0x56 0x78) 时,您实际上计算了 ASCII 文本“123456789”的 CRC。您需要为tx_buf 制作大小为n 的CRC。
    • tx_buf 的 CRC,大小为 n,您的意思是 `unsigned short crc = GetCrc16(tx_buf, strlen(tx_buf));`RS232_SendBuf(comport_nr, (unsigned char *)tx_buf, n+2); 对吗?感谢您的耐心和及时的回复,我仍然得到 varing crc,
    猜你喜欢
    • 2015-07-03
    • 1970-01-01
    • 2014-05-11
    • 2010-11-13
    • 2015-06-29
    • 2015-06-05
    • 1970-01-01
    • 1970-01-01
    • 2020-02-28
    相关资源
    最近更新 更多