搜索
bottom↓
回复: 8

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

[复制链接]

出0入0汤圆

发表于 2021-1-18 01:12:35 | 显示全部楼层 |阅读模式
本帖最后由 mangolu 于 2021-1-18 01:13 编辑

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

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

  13.         while (num--)
  14.         {
  15.                 index = CRCcode_L ^ (*pack++);       

  16.                 CRCcode_L = CRCcode_H ^ CRC_H[index];

  17.                 CRCcode_H = CRC_L[index];
  18.         }
  19.         return (CRCcode_L << 8 | CRCcode_H);        // MODBUS 规定低位在前
  20. }
复制代码


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

而freemodbus里的代码为:
  1. USHORT
  2. usMBCRC16( UCHAR * pucFrame, USHORT usLen )
  3. {
  4.     UCHAR           ucCRCHi = 0xFF;
  5.     UCHAR           ucCRCLo = 0xFF;
  6.     int             iIndex;

  7.     while( usLen-- )
  8.     {
  9.         iIndex = ucCRCLo ^ *( pucFrame++ );
  10.         ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] );
  11.         ucCRCHi = aucCRCLo[iIndex];
  12.     }
  13.     return ( USHORT )( ucCRCHi << 8 | ucCRCLo );
  14. }
复制代码


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

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

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入93汤圆

发表于 2021-1-18 08:42:30 来自手机 | 显示全部楼层
符合C语言标准的当然是必须可以,不符合标准的编译器要特立独行就不一定了。

出0入0汤圆

发表于 2021-1-18 08:48:23 | 显示全部楼层
return (  ( USHORT )ucCRCHi << 8 | ucCRCLo ); 才是正确的写法。前面都需要依赖C语言的自动整型提升

出0入20汤圆

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

出0入0汤圆

发表于 2021-1-18 09:34:31 | 显示全部楼层
楼主C语言基础不牢啊。建议时常复习一下K&R的那本C语言圣经,基础不牢,地动山摇嘛

出0入0汤圆

发表于 2021-1-18 10:38:21 来自手机 | 显示全部楼层
直接用freemodbus里面的一个专门计算crc的c文件就可以了,直接调用函数

出0入0汤圆

发表于 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[2];
} UU16;
//-----------------------------//
UU16 CRC;
CRC.U8[MSB]=0XAB;
CRC.U8[LSB]=0X34;
return CRC.U16;
这里CRC.U16 的值就是0XAB34,数据类型是unsigned int ,

//-----------------------------//
CRC.U16=0XBD56;
CRC.U8[MSB]值就是0XBD
CRC.U8[LSB]值就是0X56

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

出0入0汤圆

 楼主| 发表于 2021-1-18 14:58:16 来自手机 | 显示全部楼层
Error.Dan 发表于 2021-1-18 08:48
看你的函数声明的返回类型,这里有个隐含的类型转换,最后一步运算两个byte都升到unsigned int类型计算了. ...

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

出0入0汤圆

 楼主| 发表于 2021-1-18 14:58:50 来自手机 | 显示全部楼层
kation122 发表于 2021-1-18 10:50
班门弄斧,抛砖引玉,分享使用联合体来做 2byte to uint16,  4byte to uint32 的方法,
不浪费MCU 移位运算 ...

这个方法不错,谢谢
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 05:09

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表