mangolu 发表于 2021-1-18 01:12:35

请教坛里很多MODBUS计算CRC16的方法两个uint8_t return能得到uint16_t吗?

本帖最后由 mangolu 于 2021-1-18 01:13 编辑

请教坛里很多MODBUS计算CRC16的方法两个uint8_t return (CRCcode_L << 8 | CRCcode_H)能得到uint16_t?

代码如下:
/**************************************************************************************************
    NAME : comp_crc16
   INPUT : unsigned char *pack 数据缓冲首地址, unsigned char num 数据字节数
OUTPUT : unsigned int 计算结果,低位在前 高位在后(MODBUS 规定)。
FUNCTION :
           CRC16 计算 MODBUS使用公式:X16+X15+X2+1 。此不同于CITT公式
**************************************************************************************************/
unsigned int comp_crc16(unsigned char *pack, unsigned char num)
{
        unsigned char CRCcode_H = 0XFF;                // 高CRC字节初始化
        unsigned char CRCcode_L = 0XFF;                // 低CRC 字节初始化
        unsigned char index;                        // 数据索引

        while (num--)
        {
                index = CRCcode_L ^ (*pack++);       

                CRCcode_L = CRCcode_H ^ CRC_H;

                CRCcode_H = CRC_L;
        }
        return (CRCcode_L << 8 | CRCcode_H);        // MODBUS 规定低位在前
}

按照我的理解,CRCcode_L为uint8_t,左移8位后应应该为0x00吧?两个uint8_t相或后,能返回uint16_t值?我看了坛里很多代码都是这样的。

而freemodbus里的代码为:
USHORT
usMBCRC16( UCHAR * pucFrame, USHORT usLen )
{
    UCHAR         ucCRCHi = 0xFF;
    UCHAR         ucCRCLo = 0xFF;
    int             iIndex;

    while( usLen-- )
    {
      iIndex = ucCRCLo ^ *( pucFrame++ );
      ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi );
      ucCRCHi = aucCRCLo;
    }
    return ( USHORT )( ucCRCHi << 8 | ucCRCLo );
}

明显这里的代码采用了强制类型转换,这样的结果才是正确的。

我就很疑惑,坛里很多人的代码真能正常计算吗?

takashiki 发表于 2021-1-18 08:42:30

符合C语言标准的当然是必须可以,不符合标准的编译器要特立独行就不一定了。

zhugean 发表于 2021-1-18 08:48:23

return (( USHORT )ucCRCHi << 8 | ucCRCLo ); 才是正确的写法。前面都需要依赖C语言的自动整型提升

Error.Dan 发表于 2021-1-18 08:48:25

看你的函数声明的返回类型,这里有个隐含的类型转换,最后一步运算两个byte都升到unsigned int类型计算了.

JasonGao 发表于 2021-1-18 09:34:31

楼主C语言基础不牢啊。建议时常复习一下K&R的那本C语言圣经,基础不牢,地动山摇嘛

tangmin 发表于 2021-1-18 10:38:21

直接用freemodbus里面的一个专门计算crc的c文件就可以了,直接调用函数

kation122 发表于 2021-1-18 10:50:05

本帖最后由 kation122 于 2021-1-18 10:56 编辑

班门弄斧,抛砖引玉,分享使用联合体来做 2byte to uint16,4byte to uint32 的方法,
不浪费MCU 移位运算,不逻辑运算,简洁明了,稳定使用多年,抛砖引玉,请各位大侠点评。

# define LSB 1
# define MSB 0

typedef unsigned char U8;
typedef unsigned int U16;

typedef union UU16
{
   U16 U16;
   U8 U8;
} UU16;
//-----------------------------//
UU16 CRC;
CRC.U8=0XAB;
CRC.U8=0X34;
return CRC.U16;
这里CRC.U16 的值就是0XAB34,数据类型是unsigned int ,

//-----------------------------//
CRC.U16=0XBD56;
CRC.U8值就是0XBD
CRC.U8值就是0X56

编译器大小端不同,只需要调整# define LSB ,# define MSB两个参数。

mangolu 发表于 2021-1-18 14:58:16

Error.Dan 发表于 2021-1-18 08:48
看你的函数声明的返回类型,这里有个隐含的类型转换,最后一步运算两个byte都升到unsigned int类型计算了. ...

哦,原来这里还有个隐形转换,这个一直没有注意过。

mangolu 发表于 2021-1-18 14:58:50

kation122 发表于 2021-1-18 10:50
班门弄斧,抛砖引玉,分享使用联合体来做 2byte to uint16,4byte to uint32 的方法,
不浪费MCU 移位运算 ...

这个方法不错,谢谢
页: [1]
查看完整版本: 请教坛里很多MODBUS计算CRC16的方法两个uint8_t return能得到uint16_t吗?