天道酬勤,学无止境

CRC-CCITT 到 CRC16 Modbus 实现(CRC-CCITT to CRC16 Modbus implementation)

问题

我在使用 PHP 生成 modbus CRC16 代码时遇到了很多麻烦。 我在互联网上找到了很多不同的代码,但我已经尝试过,但由于某种原因我没有得到正确的结果。 我找到了一个用于生成 CRC16-CCITT 的 PHP 代码。 我已将查找表更改为 modbus CRC 对应表,但结果仍然不正确。 代码如下。 我还需要做什么才能将 CRC16-CCITT 代码转换为 CRC16-MODBUS 代码。

<?php 

/*************************************************************************
 * phpCrc16 v1.1 -- CRC16/CCITT implementation 
 *
 * By Matteo Beccati <matteo@beccati.com>
 * 
 * Original code by:
 * Ashley Roll
 * Digital Nemesis Pty Ltd
 * www.digitalnemesis.com
 * ash@digitalnemesis.com 
 *
 * Test Vector: "123456789" (character string, no quotes)
 * Generated CRC: 0x29B1
 * 
 *************************************************************************/



/*
 * Returns CRC16 of a string as int value
 */
function CRC16($str)
{
    static $CRC16_Lookup = array(
              0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
        0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
        0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
        0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
        0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
        0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
        0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
        0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
        0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
        0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
        0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
        0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
        0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
        0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
        0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
        0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
        0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
        0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
        0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
        0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
        0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
        0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
        0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
        0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
        0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
        0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
        0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
        0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
        0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
        0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
        0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
        0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040
    );

    $crc16 = 0xFFFF; // the CRC
    $len = strlen($str);

    for($i = 0; $i < $len; $i++ )
    {
        $t = ($crc16 >> 8) ^ ord($str[$i]); // High byte Xor Message Byte to get index
        $crc16 = (($crc16 << 8) & 0xffff) ^ $CRC16_Lookup[$t]; // Update the CRC from table
    }

    // crc16 now contains the CRC value
    return $crc16;
}

/*
 * Returns CRC16 of a string as hexadecimal string
 */
function CRC16HexDigest($str)
{
    return sprintf('%04X', crc16($str));
}
echo CRC16HexDigest('123456789');
?>

回答1

这个Pascal片段是MODBUS RTU(ASCII不同)协议在线计算,没有任何表格:

function mb_CalcCRC16(ptr: pointer to byte; ByteCount: byte): word;
var
  crc: word;
  b, i, n: byte;
begin
  crc := $FFFF;
  for i := 0 to ByteCount do
    if i = 0 then           // device id is 1st byte in message, and it is not in the buffer
      b := mb_GetMessageID; // so we have to calculate it and put it as 1st crc byte
    else
      b := ptr^;
      Inc(ptr);
    endif;
    crc := crc xor word(b);
    for n := 1 to 8 do
      if (crc and 1) = 1 then
        crc := (crc shr 1) xor $A001;
      else
        crc := crc shr 1;
      endif;
    endfor;
  endfor;
  Return(crc);
end;

function mb_CalcCRC: word; // Calculate CRC for message in mb_pdu
begin // this message can be one that is just received, or in a reply we have just composed
  Return(mb_CalcCRC16(@mb_pdu[1], mb_GetEndOfData));
end;

这是来自一个工作的嵌入式 AVR 设备的引用,该设备具有实施的 MODBUS RTU 从协议。

回答2

这比查找表快

 function crc16($data)
 {
   $crc = 0xFFFF;
   for ($i = 0; $i < strlen($data); $i++)
   {
     $crc ^=ord($data[$i]);

        for ($j = 8; $j !=0; $j--)
        {
            if (($crc & 0x0001) !=0)
            {
                $crc >>= 1;
                $crc ^= 0xA001;
            }
            else
                $crc >>= 1;
        }
    }   
   return $crc;
 }
回答3

多年后,您的回答对我非常有用。 我将您的答案结合在一个非查找表解决方案中:

function crc16_modbus($msg)
{
    $data = pack('H*',$msg);
    $crc = 0xFFFF;
    for ($i = 0; $i < strlen($data); $i++)
    {
        $crc ^=ord($data[$i]);

        for ($j = 8; $j !=0; $j--)
        {
            if (($crc & 0x0001) !=0)
            {
                $crc >>= 1;
                $crc ^= 0xA001;
            }
            else $crc >>= 1;
        }
    }   
    return sprintf('%04X', $crc);
}

我正在等待的结果与在线工具一致,例如:

  • 朗伯比斯
  • 斯塔克苏
回答4

谢谢你的回应。 我能够使用以下代码在 PHP 中执行 Modbus crc 检查:

<?php   
    //Calcula o CRC para uma mensagem modbus
    function modbus_crc($modbus_msg){

        $crctab16 = [0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
            0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
            0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
            0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
            0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
            0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
            0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
            0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
            0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
            0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
            0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
            0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
            0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
            0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
            0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
            0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
            0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
            0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
            0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
            0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
            0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
            0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
            0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
            0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
            0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
            0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
            0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
            0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
            0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
            0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
            0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
            0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040];

        $hexdata = pack('H*',$modbus_msg);
        $nLength = strlen($hexdata);
        $fcs = 0xFFFF;
        $pos = 0;
        while($nLength > 0)
        {
            $fcs = ($fcs >> 8) ^ $crctab16[($fcs ^ ord($hexdata[$pos])) & 0xFF];
            $nLength--;
            $pos++;
        }
        $crc_semi_inverted = sprintf('%04X', $fcs);//modbus crc invert the hight and low bit so we need to put the last two letter in the begining
        $crc_modbus = substr($crc_semi_inverted,2,2).substr($crc_semi_inverted,0,2);
        return $crc_modbus;
    }
?>

您应该输入一个带有十六进制消息的字符串:

$modbus_msg='01040000002'; $modbus_msg_crc=modbus_crc($modbus_msg);

回答5

这是用于 ModBus RTU 的 CRC16-ANSI (IBM) 算法的精简版。

function crc16_ansi($data) {
  $crc = 0xFFFF;
  for ($i = 0; $i < strlen($data); $i++){
    $crc ^= ord($data[$i]);
    for($j = 8; $j--;)
      $crc = $crc & 0x0001 ? $crc = ($crc >> 1) ^ 0xA001 : $crc >> 1;
  }
  return $crc;
}
标签

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • CRC-CCITT to CRC16 Modbus implementation
    I am having a lot of trouble on generating a modbus CRC16 code using PHP. I have found a lot of different codes over the internet but i have tried them and for some reason i didnt get right results. I have found a PHP code for generating CRC16-CCITT. I have chenge the look up table to the modbus CRC corresponding table but the result is still not the right one. The code is bellow. What do i need to do more in order to transform a CRC16-CCITT code into CRC16-MODBUS code. <?php /************************************************************************* * phpCrc16 v1.1 -- CRC16/CCITT
  • CRC-CCITT (0xFFFF) function?
    Can someone help me with Delphi implementation of CRC-CCITT (0xFFFF)? Already get the Java version, but confusing on how to port it to Delphi public static int CRC16CCITT(byte[] bytes) { int crc = 0xFFFF; // initial value int polynomial = 0x1021; // 0001 0000 0010 0001 (0, 5, 12) for (byte b : bytes) { for (int i = 0; i < 8; i++) { boolean bit = ((b >> (7-i) & 1) == 1); boolean c15 = ((crc >> 15 & 1) == 1); crc <<= 1; if (c15 ^ bit) crc ^= polynomial; } } crc &= 0xffff; //System.out.println("CRC16-CCITT = " + Integer.toHexString(crc)); return crc; } and for PHP implementation <?php function
  • CRC16算法之三:CRC16-CCITT-MODBUS算法的java实现
    CRC16算法系列文章:CRC16算法之一:CRC16-CCITT-FALSE算法的java实现 CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现 CRC16算法之三:CRC16-CCITT-MODBUS算法的java实现 功能 实现CRC16-CCITT-MODBUS算法支持int、short类型支持选择数组区域计算实现 /** * crc16_ccitt_modbus算法(四字节)友情提示:做好自己!--eguid博客地址:http://blog.csdn.net/eguid_1 * @param buf * @param offset * @param length * @return */ public static int crc16_ccitt_modbus(byte[] buf,int offset, int length) { int i, j; int c, crc = 0xFFFF; for (i = offset; i < length; i++) { c = buf[i] & 0x00FF; crc ^= c; for (j = 0; j < 8; j++) { if ((crc & 0x0001) != 0) { crc >>= 1; crc ^= 0xA001; } else crc >>= 1; } } return crc
  • Android CRC-CCITT
    I need a CRC check for an application Im writing, but cant figure out for the online code and calculators what im doing wrong. I may just not understand it correctly. This is what I need : It uses CRC-CCITT with a starting value of 0xFFFF with reverse input bit order. For example, the Get Device Type message is: 0x01, 0x06, 0x01, 0x00, 0x0B, 0xD9. The CRC is 0xD90B. And this is the code Im using : public static int CRC16CCITT(byte[] bytes) { int crc = 0xFFFF; // initial value int polynomial = 0x1021; // 0001 0000 0010 0001 (0, 5, 12) for (byte b : bytes) { for (int i = 0; i < 8; i++) { boolean
  • CRC16算法之三:CRC16-CCITT-MODBUS算法的java实现
    CRC16算法系列文章: CRC16算法之一:CRC16-CCITT-FALSE算法的java实现 CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现 CRC16算法之三:CRC16-CCITT-MODBUS算法的java实现 功能实现CRC16-CCITT-MODBUS算法支持int、short类型支持选择数组区域计算实现/** * crc16_ccitt_modbus算法(四字节)友情提示:做好自己!--eguid博客地址:http://blog.csdn.net/eguid_1 * @param buf * @param offset * @param length * @return */public static int crc16_ccitt_modbus(byte[] buf,int offset, int length) {int i, j;int c, crc = 0xFFFF;for (i = offset; i < length; i++) {c = buf[i] & 0x00FF;crc ^= c;for (j = 0; j < 8; j++) {if ((crc & 0x0001) != 0) {crc >>= 1;crc ^= 0xA001;} elsecrc >>= 1;}}return crc;} /** * crc16
  • 一文详解循环冗余校验校验算法(CRC校验)及C语言代码的实现 ---- 以CRC-16/MODBUS为例讲解
    一、概述 现在的产品开发过程中,无论是数据的储存还是传输,都需要确保数据的准确性,所以就需要在数据帧后面附加一串校验码,方便接收方使用校验码校验接收到的数据是否是正确的。 常用的校验方式有奇偶校验、异或校验、累加和校验(可以看我之前的一篇文章累加和校验算法(CheckSum算法))、循环冗余校验(CRC校验)等等。 奇偶校验、异或校验、累加和校验都比较简单,且易于实现,但是检错能力也一般,而本文的主角CRC校验,则大大提高了数据的检错能力。(对比文章看这篇《奇偶校验 累加和校验 CRC校验》) 讲CRC校验的文章很多,也有非常多的好文章,本文只是将这些文章总结,用自己的理解再阐述一遍,再次感谢各位大佬优质的文章。 CRC校验有很多的参数模型,尤其是有很多标准模型的存在,这些标准模型经过理论计算,大大提高校验检错的能力,所以推荐使用标准模型,由于有大量的教程和网上资源,参考后实现起来也比较简单,同时也利于不同部门间的沟通和定下标准。 本文就是采用CRC-16/MODBUS参数模型,该模型就被各行各业大量使用 二、CRC的基本原理 网上有看到一篇讲解CRC原理的文章非常不错的文章:循环冗余检验 (CRC) 算法原理。 文章讲解了CRC校验的基本原理,讲的很清楚,尤其是查表法的原理,需要静下来心来看几遍才能理解透彻。 如果还不懂,还可以看看这篇:最通俗的CRC校验原理剖析。
  • Modbus协议详解
    一、Modbus协议 1、Modbus协议简介 Modubs协议是应用应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(如以太网)和其他设备之间可以通讯。它已经成为一种通用的工业标准。有了它,不同的厂商生产的控制设备可以连成工业网络,进行集中监控。 此协议定义了一个控制器能认识使用的消息结构,而不管他们是经过何种网络进行通信的。他描述了一控制器请求访问其他设备的过程,如果回应来自其他设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。 当在一Modbus网络上通信时,此协议决定了每个控制器必须要知道他们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其他网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。 2、在Modbus网络上传输 标准的Modbus口是使用一RS-232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。控制器能直接或经由Modem组网。 控制器通信使用主——从技术,即仅一设备(主设备)能初始化传输(查询)。其他设备(从设备)根据主设备查询提供的数据做出相应反应。典型的主设备:主机和可编程仪表。典型的从设备:可编程控制器。
  • 纠错码CRC详细计算(精华)
    1. CRC CRC(Cyclic Redundancy Check)循环冗余校验码,是常用的校验码.对通信的可靠性检查就需要‘校验’,校验是从数据本身进行检查,它依靠某种数学上约定的形式进行检查,校验的结果是可靠或不可靠,如果可靠就对数据进行处理,如果不可靠,就丢弃重发或者进行修复。 CRC码是由两部分组成,前部分是信息码,就是需要校验的信息,后部分是校验码,如果CRC码共长n个bit,信息码长k个bit,就称为(n,k)码。 它的编码规则是: 1、首先将原信息码(kbit)左移r位(k+r=n) 2、运用一个生成多项式g(x)(也可看成二进制数,是事先定义好了的)用模2除上面的式子,得到的余数就是校验码。3.多项式的二进制数位数是r(原信息的左移位)+1位. 非常简单,要说明的:模2除就是在除的过程中用模2加,模2加实际上就是我们熟悉的异或运算,就是加法不考虑进位,公式是: 0+0=1+1=0,1+0=0+1=1即‘异’则真,‘非异’则假。 有了加法就可以用来定义模2除法,于是就可以用生成多项式g(x)生成CRC校验码。例如: g(x)=X4+X3+X2+1,(7,3)码,信息码110产生的CRC码就是: 101 商11101 | 1100000 11101 10100 11101 1001 余数余数是1001,所以CRC码是110,1001标准的CRC码是,CRC
  • LabView:MODBUS协议CRC-16校验VI
    功能描述:实现MODBUS协议指令的CRC校验功能。输入位字符串指令,输出为:指令+校验码(字符串)、校验码(字符串)、校验码(整型)。 MODBUS-RTU:   当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。 代码系统 8位二进制,十六进制数0...9,A...F消息中的每个8位域都是一个两个十六进制字符组成每个字节的位1个起始位8个数据位,最小的有效位先发送1个奇偶校验位,无校验则无1个停止位(有校验时),2个Bit(无校验时) 错误检测域 CRC(循环冗长检测) 前面板: 后面板: 实验验证: 实际工程中通过串口调试 http://www.ip33.com/crc.html 来源:https://blog.csdn.net/L0ve777/article/details/105936170
  • STM32F7 硬件CRC校验驱动,支持CRC7,CRC8,CRC16,CRC32
    本来想实现32bit写入,一次进行4字节校验,结果测试过程中发现兼容性不好,最后放弃了,统一使用字节模式写入。 已经实现了硬件的CRC7,CRC8,CRC16,CRC32运算,并且均进行了测试对比,计算结果完全正确,通过配置可以实现不同的CRC校验,我已经实现了如下的配置: // //常见的CRC校验配置 extern const STM32F7_CRC_Config cg_CRC_CONFIG_CRC32; //默认的CRC-32校验 extern const STM32F7_CRC_Config cg_CRC_CONFIG_CRC32_MPEG2; //CRC-32/MPEG-2校验 extern const STM32F7_CRC_Config cg_CRC_CONFIG_CRC16_XMODEM; //CRC-16/XMODEM校验 extern const STM32F7_CRC_Config cg_CRC_CONFIG_CRC16_MODBUS; //CRC-16/MODBUS校验 extern const STM32F7_CRC_Config cg_CRC_CONFIG_CRC16_USB; //CRC-16/USB校验 extern const STM32F7_CRC_Config cg_CRC_CONFIG_CRC16_IBM; //CRC-16/IBM校验
  • CRC-16/MODBUS 算法
    CRC-16/MODBUS 算法:在CRC计算时只用8个数据位,起始位及停止位,如有奇偶校验位也包括奇偶校验位,都不参与CRC计算。CRC计算方法是:1、 加载一值为0XFFFF的16位寄存器,此寄存器为CRC寄存器。2、 把第一个8位二进制数据(即通讯信息帧的第一个字节)与16位的CRC寄存器的相异或,异或的结果仍存放于该CRC寄存器中。3、 把CRC寄存器的内容右移一位,用0填补最高位,并检测移出位是0还是1。4、 如果移出位为零,则重复第三步(再次右移一位);如果移出位为1,CRC寄存器与0XA001进行异或。5、 重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理。6、 重复步骤2和5,进行通讯信息帧下一个字节的处理。7、 将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换8、 最后得到的CRC寄存器内容即为:CRC校验码。 C#代码: void ModBusCRC16(ref byte[] cmd, int len) { ushort i, j, tmp, CRC16; CRC16 = 0xFFFF; //CRC寄存器初始值 for (i = 0; i < len; i++) { CRC16 ^= cmd[i]; for (j = 0; j < 8; j++) { tmp = (ushort)(CRC16 & 0x0001)
  • stc单片机做modbus server rtu通信,已封装好库函数
    modbus server 库文件 基于stc8单片机测试 硬件平台是基于stc8系列单片机进行的测试,这个函数目前只能实现整数类型的数据读取与写入,没法做浮点数通信,且进行数据写入的时候最好是一个地址一个地址的写入,测试是上位机使用modscon进行的测试,数据读取以及一个地址的数据写入都没有问题 头文件 #ifndef __MODBUS_H__ #define __MODBUS_H__ #include <stc8.h> //头文件定义,串口发送函数中,SBUF寄存器的头文件 /* 需要在主文件中定义这些变量 然后参照参数写入说明,对modbus函数填入参数即可 uchar xdata getdata[10]={0}; //串口收取的存储区间,接收报文一般是八个字节,所以这里定义了10个区间 uchar xdata putdata[100]={0x01}; //串口发送的存储区间 uchar xdata datacache[100]={0}; //数据存储区间,[0]和[1]累加16位的值就是address的地址。 uint address=0; //数据的开始地址,0就代表40001地址 uchar num,flag=0; //一些标志位的定义 */ #define uchar unsigned char //宏定义 #define uint unsigned int
  • CRC校验查表法原理及实现(CRC-16)
    绪论 在网上浏览了很多关于CRC校验的文章,基本上都是针对CRC校验原理的阐述以及关于CRC校验查表法的实际应用以及具体软件实现方法。 至于查的表是怎么来的,软件为什么要这样实现很多文章并没有说明。本篇文章就针对这两点问题进行总结和归纳,有错误的地方欢迎大家评论区指出,不胜感激。 注意:本篇文章不涉及CRC校验的基本原理,如果不了解CRC的基本原理,请移步至如下链接: CRC查找表法推导及代码实现比较 以下的CRC查表法的软件实现及推导过程均建立在modbusRTU协议使用的CRC-16标准。 查表法的表是怎么来的? CRC16算法的生成多项式 x 16 + x 15 + x 2 + 1 x^{16}+x^{15}+x^2+1 x16+x15+x2+1,十六进制表示为0x8005。 CRC16常见的表格中的数据是按照先传输LSB,消息右移进寄存器来计算的。因此需要判断寄存器的最低位LSB,同时要将0x8005按位颠倒后(0xA001)根据LSB的情况决定是否与寄存器异或即可。 CRC16的表格中对应的数依次为0~255计算出来的CRC值,因此,此处只选取其中一两个数作为实例计算CRC值。 具体步骤如下所示: 1)从0~255中选取需要计算的数,将其对应的十六进制数放入一个长度为16的寄存器的低八位,高八位填充0; 2)如果寄存器的末位LSB为1,将寄存器的数值右移1位
  • 获取字节数组的CRC校验和并将其添加到该字节数组(Getting the CRC checksum of a byte array and adding it to that byte array)
    问题 我有这个字节数组: static byte[] buf = new byte[] { (byte) 0x01, (byte) 0x04, (byte)0x00, (byte)0x01,(byte)0x00, (byte) 0x01}; 现在,假定此字节数组的CRC校验和为0x60、0x0A。 我希望Java代码重新创建此校验和,但是我似乎无法重新创建它。 我尝试了crc16: static int crc16(final byte[] buffer) { int crc = 0xFFFF; for (int j = 0; j < buffer.length ; j++) { crc = ((crc >>> 8) | (crc << 8) )& 0xffff; crc ^= (buffer[j] & 0xff);//byte to int, trunc sign crc ^= ((crc & 0xff) >> 4); crc ^= (crc << 12) & 0xffff; crc ^= ((crc & 0xFF) << 5) & 0xffff; } crc &= 0xffff; return crc; } 并使用Integer.toHexString()进行转换,但结果均不匹配正确的CRC。 有人可以根据CRC公式指出我正确的方向。 回答1 请使用以下代码: //
  • freemodbus modbus TCP 学习笔记
    freemodbus modbus TCP 学习笔记 1.前言 使用modbus有些时间了,期间使用过modbus RTU也使用过modbus TCP,通过博文和大家分享一些MODBUS TCP的东西。在嵌入式中实现TCP就需要借助一个以太网协议栈,在这里我选择最简单的uIP协议栈。uIP协议栈简单易用方便上手,相比于LwIP无论是移植还是使用难度都低些,这样就可以把更多的精力花在modbus tcp协议本身而不必花大量的时间研究以太网协议栈。modbus协议栈为freemodbus 【其他有用的博文】 【1】uIP学习笔记 【2】MODBUS协议整理——汇总 【工程代码】 示例代码托管于GitHub——【Github Clone】 如果有问题我会及时更新。【使用说明】 【1】工具链为IAR 6.5 【2】从机IP为固定IP 192.168.1.15,请保证从机和路由器位于同一个网段中。 【3】modbus tcp的侦听端口号为502 2.MODBUS TCP注意点2.1 主机和从机、服务端和客户端图1 MODBUS请求响应模型【在modbus协议中】主机发送modbus请求,从机根据请求内容向主机返回响应。在modbus协议中,主机总是主动方,从机总是被动方。【在网络应用中】在网络应用中存在客户端和服务器端,客户端(例如浏览器)发送请求到服务器,服务器向客户端返回内容
  • 如何在 PHP HEX 中计算 CRC16 CCITT?(How to calculate CRC16 CCITT in PHP HEX?)
    问题 我正在尝试使用 PHP CRC16 CCITT 函数来计算校验和。 设备向我发送了一个包含校验和的 PACKET: 10 00 00 00 00 00 00 00 12 51 09 08 00 18 00 04 02 14 00 0c 00 0c 02 1c 00 02 00 00 00 00 00 7 00 a 0 校验和在最后: a0 77 我试过使用 如何在php中计算crc16 为 CRC16 函数将 C 转换为 PHP 没有成功,CRC 16 计算返回: E6 F4而不是a0 77 查找时,我返回了正确的十六进制信息: 100000000000000012510908001800040214000c000c021c0002000000000000 在网站 http://www.lammertbies.nl/comm/info/crc-calculation.html 上,但我无法重现它。 (确保选择输入类型为HEX) 你能帮我弄清楚如何获得十六进制值字符串的 crc16 CCITT 100000000000000012510908001800040214000c000c021c0002000000000000 我正在寻找校验和a0 77 回答1 我能够使用如下实现生成相同的校验和: define('CRC16POLYN', 0x1021); function
  • C# CRC implementation
    I am trying to integrate a Serial-port device into my application, which needs CRC-CCTT validation for the bytes that I send to it. I'm kinda new into managing byte packets, and need help for this. It uses this formula for making the CRC calculus: [CRC-CCITT P(X)= X16 + C12 + C8 + 1] So for example for the packet: 0xFC 0x05 0x11, the CRC is 0x5627. Then I send this packet to the device: 0xFC 0x05 0x11 0x27 0x56 Also, packet lenghts will vary from 5 to 255 (including CRC checks bytes) I don't know how to implement this, so any idea/suggestions will be welcome. Hope I made myself clear, Thanks
  • CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现
    CRC16算法系列文章: CRC16算法之一:CRC16-CCITT-FALSE算法的java实现 CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现 CRC16算法之三:CRC16-CCITT-MODBUS算法的java实现 前言CRC16算法有很多种,本篇文章会介绍其中的CRC16-CCITT-XMODEM算法 功能实现CRC16-CCITT-XMODEM算法支持int、short类型支持选择数组区域计算实现package cc.eguid.crc16; /** * crc16多项式算法 * @author eguid * */public class CRC16 { /** * CRC16-XMODEM算法(四字节) * @param bytes * @return */public static int crc16_ccitt_xmodem(byte[] bytes) {return crc16_ccitt_xmodem(bytes,0,bytes.length);} /** * CRC16-XMODEM算法(四字节) * @param bytes * @param offset * @param count * @return */public static int crc16_ccitt_xmodem(byte[] bytes,int
  • CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现
    CRC16算法系列文章:CRC16算法之一:CRC16-CCITT-FALSE算法的java实现 CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现 CRC16算法之三:CRC16-CCITT-MODBUS算法的java实现 前言CRC16算法有很多种,本篇文章会介绍其中的CRC16-CCITT-XMODEM算法 功能实现CRC16-CCITT-XMODEM算法支持int、short类型支持选择数组区域计算实现package cc.eguid.crc16; /** * crc16多项式算法 * @author eguid * */ public class CRC16 { /** * CRC16-XMODEM算法(四字节) * @param bytes * @return */ public static int crc16_ccitt_xmodem(byte[] bytes) { return crc16_ccitt_xmodem(bytes,0,bytes.length); } /** * CRC16-XMODEM算法(四字节) * @param bytes * @param offset * @param count * @return */ public static int crc16_ccitt_xmodem(byte[] bytes,int
  • CRC16算法之一:CRC16-CCITT-FALSE算法的java实现
    CRC16算法系列文章: CRC16算法之一:CRC16-CCITT-FALSE算法的java实现 CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现 CRC16算法之三:CRC16-CCITT-MODBUS算法的java实现 前言JDK里包含了CRC32的算法,但是没有CRC16的,网上搜了一堆没有找到想要的,索性自己实现注意:CRC16算法分为很多种,本篇文章中,只讲其中的一种:CRC16-CCITT-FALSE算法CRC16算法系列之一:CRC16-CCITT-FALSE算法的java实现功能1、支持short类型2、支持int类型3、支持数组任意区域计算实现/** * crc16-ccitt-false加密工具 * * @author eguid * */public class CRC16 { /** * crc16-ccitt-false加/解密(四字节) * * @param bytes * @return */public static int crc16(byte[] bytes) {return crc16(bytes, bytes.length); } /** * crc16-ccitt-false加/解密(四字节) * * @param bytes -字节数组 * @return */public static int crc16