MODBUS 通讯协议及编程

[关键词]

  ModBus 通讯协议分为 RTU 协议和 ASCII 协议,我公司的多种仪表都采用 ModBus RTU 通讯协议,如: CH2000 智能电力监测仪、 CH2000M 电力参数采集模块、巡检表、数显表、光柱数显表等。下面就 ModBus RTU 协议简要介绍如下:

  一、通讯协议

  (一)、通讯传送方式 :
通讯传送分为独立的信息头,和发送的编码数据。以下的通讯传送方式定义也与 MODBUS RTU 通讯规约相兼容:

编 码

8 位二进制

起始位

1 位

数据位

8 位

奇偶校验位

1 位(偶校验位)

停止位

1 位

错误校检

CRC (冗余循环码)

初始结构 = ≥ 4 字节的时间
地址码 = 1 字节
功能码 = 1 字节
数据区 = N 字节
错误校检 = 16 位 CRC 码
结束结构 = ≥ 4 字节的时间


  地址码 :地址码为通讯传送的第一个字节。这个字节表明由用户设定地址码的从机将接收由主机发送来的信息。并且每个从机都有具有唯一的地址码,并且响应回送均以各自的地址码开始。主机发送的地址码表明将发送到的从机地址,而从机发送的地址码表明回送的从机地址。

  功能码 :通讯传送的第二个字节。 ModBus 通讯规约定义功能号为 1 到 127 。本仪表只利用其中的一部分功能码。作为主机请求发送,通过功能码告诉从机执行什么动作。作为从机响应,从机发送的功能码与从主机发送来的功能码一样,并表明从机已响应主机进行操作。如果从机发送的功能码的最高位为1 ( 比如功能码大与此同时 127) ,则表明从机没有响应操作或发送出错。

  数据区 :数据区是根据不同的功能码而不同。数据区可以是实际数值、设置点、主机发送给从机或从机发送给主机的地址。

  CRC 码 :二字节的错误检测码。

  (二)、通讯规约:

  当通讯命令发送至仪器时,符合相应地址码的设备接通讯命令,并除去地址码,读取信息,如果没有出错,则执行相应的任务;然后把执行结果返送给发送者。返送的信息中包括地址码、执行动作的功能码、执行动作后结果的数据以及错误校验码。如果出错就不发送任何信息。

  1 .信息帧结构

地址码

功能码

数据区

错误校验码

8 位

8 位

N × 8 位

16 位

  地址码 :地址码是信息帧的第一字节 (8 位 ) ,从 0 到 255 。这个字节表明由用户设置地址的从机将接收由主机发送来的信息。每个从机都必须有唯一的地址码,并且只有符合地址码的从机才能响应回送。当从机回送信息时,相当的地址码表明该信息来自于何处。

  功能码 :主机发送的功能码告诉从机执行什么任务。表 1-1 列出的功能码都有具体的含义及操作。

代码

含义

操作

03

读取数据

读取当前寄存器内一个或多个二进制值

06

重置单一寄存器

把设置的二进制值写入单一寄存器

  数据区 :数据区包含需要从机执行什么动作或由从机采集的返送信息。这些信息可以是数值、参考地址等等。例如,功能码告诉从机读取寄存器的值,则数据区必需包含要读取寄存器的起始地址及读取长度。对于不同的从机,地址和数据信息都不相同。

  错误校验码 :主机或从机可用校验码进行判别接收信息是否出错。有时,由于电子噪声或其它一些干扰,信息在传输过程中会发生细微的变化,错误校验码保证了主机或从机对在传送过程中出错的信息不起作用。这样增加了系统的安全和效率。错误校验采用 CRC-16 校验方法。

注:信息帧的格式都基本相同:地址码、功能码、数据区和错误校验码。

  2 .错误校验

  冗余循环码( CRC )包含 2 个字节,即 16 位二进制。 CRC 码由发送设备计算,放置于发送信息的尾部。接收信息的设备再重新计算接收到信息的 CRC 码,比较计算得到的 CRC 码是否与接收到的相符,如果两者不相符,则表明出错。

  CRC 码的计算方法是,先预置 16 位寄存器全为 1 。再逐步把每 8 位数据信息进行处理。在进行 CRC 码计算时只用 8 位数据位,起始位及停止位,如有奇偶校验位的话也包括奇偶校验位,都不参与 CRC 码计算。

  在计算 CRC 码时, 8 位数据与寄存器的数据相异或,得到的结果向低位移一字节,用 0 填补最高位。再检查最低位,如果最低位为 1 ,把寄存器的内容与预置数相异或,如果最低位为 0 ,不进行异或运算。

  这个过程一直重复 8 次。第 8 次移位后,下一个 8 位再与现在寄存器的内容相相异或,这个过程与以上一样重复 8 次。当所有的数据信息处理完后,最后寄存器的内容即为 CRC 码值。 CRC 码中的数据发送、接收时低字节在前。

计算 CRC 码的步骤为:

  • 预置 16 位寄存器为十六进制 FFFF (即全为 1 )。称此寄存器为 CRC 寄存器;
  • 把第一个 8 位数据与 16 位 CRC 寄存器的低位相异或,把结果放于 CRC 寄存器;
  • 把寄存器的内容右移一位 ( 朝低位 ) ,用 0 填补最高位,检查最低位;
  • 如果最低位为 0 :重复第 3 步 ( 再次移位 ); 如果最低位为 1 : CRC 寄存器与多项式 A001 ( 1010 0000 0000 0001 )进行异或;
  • 重复步骤 3 和 4 ,直到右移 8 次,这样整个 8 位数据全部进行了处理;
  • 重复步骤 2 到步骤 5 ,进行下一个 8 位数据的处理;
  • 最后得到的 CRC 寄存器即为 CRC 码。

  3 .功能码 03 ,读取点和返回值:

  仪表采用 Modbus RTU 通讯规约,利用通讯命令,可以进行读取点 ( “保持寄存器” ) 或返回值 ( “输入寄存器” ) 的操作。保持和输入寄存器都是 16 位( 2 字节)值,并且高位在前。这样用于仪表的读取点和返回值都是 2 字节。一次最多可读取寄存器数是 60 。由于一些可编程控制器不用功能码 03 ,所以功能码 03 被用作读取点和返回值。从机响应的命令格式是从机地址、功能码、数据区及 CRC 码。数据区中的寄存器数据都是每两个字节高字节在前。

  4 .功能码 06 ,单点保存

  主机利用这条命令把单点数据保存到仪表的存储器。从机也用这个功能码向主机返送信息。

  二、编程举例

  下面是一个用 VC 编写的 ModBus RTU 通讯的例子

  (一)、通讯口设置

        DCB dcb;
        hCom=CreateFile("COM1",
        GENERIC_READ|GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
        if(hCom==INVALID_HANDLE_VALUE)
        {
        MessageBox("createfile error,error");
        }
        BOOL error=SetupComm(hCom,1024,1024);
        if(!error)
        MessageBox("setupcomm error");
        error=GetCommState(hCom,&dcb);
          if(!error)
          MessageBox("getcommstate,error");
          dcb.BaudRate=2400;
          dcb.ByteSize=8;

          dcb.Parity=EVENPARITY;//NOPARITY;
          dcb.StopBits=ONESTOPBIT;

          error=SetCommState(hCom,&dcb);

          (二)、 CRC 校验码计算

          UINT crc
          void calccrc(BYTE crcbuf)
          {
          BYTE i;

          crc=crc ^ crcbuf;
          for(i=0;i<8;i++)
          {
          BYTE TT;
          TT=crc&1;
          crc=crc>>1;
          crc=crc&0x7fff;
          if (TT==1)
          crc=crc^0xa001;
          crc=crc&0xffff;
          }
          }

  (三)、数据发送

          zxaddr=11;// 读取地址为 11 的巡检表数据
          zxnum=10;// 读取十个通道的数据

          writebuf2[0]=zxaddr;
          writebuf2[1]=3;
          writebuf2[2]=0;
          writebuf2[3]=0;
          writebuf2[4]=0;
          writebuf2[5]=zxnum;
          crc=0xffff;
          calccrc(writebuf2[0]);
          calccrc(writebuf2[1]);
          calccrc(writebuf2[2]);
          calccrc(writebuf2[3]);
          calccrc(writebuf2[4]);
          calccrc(writebuf2[5]);

          writebuf2[6]=crc & 0xff;
          writebuf2[7]=crc/0x100;
          WriteFile(hCom,writebuf2,8,&comnum,NULL);

  (四)、数据读取

  ReadFile(hCom,writebuf,5+zxnum*2,&comnum,NULL);// 读取 zxnum 个通道数据
可增加错误处理程序,如地址码错误、 CRC 码错误判断、通讯故障处理等。

 

 

信息来源(作者):中国工控信息网

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
3 CRC 检测 使用RTU 模式消息包括了一基于CRC 方法的错误检测域CRC 域检测了整个消息的内容 CRC 域是两个字节包含一16 位的二进制值它由传输设备计算后加入到消息中接收设备重 新计算收到消息的CRC 并与接收到的CRC 域中的值比较如果两值不同则有误 CRC 是先调入一值是全1”的16 位寄存器然后调用一过程将消息中连续的8 位字节各当前寄 存器中的值进行处理仅每个字符中的8Bit 数据对CRC 有效起始位和停止位以及奇偶校验位 均无效 CRC 产生过程中每个8 位字符都单独和寄存器内容相或OR 结果向最低有效位方向移动 最高有效位以0 填充LSB 被提取出来检测如果LSB 为1 寄存器单独和预置的值或一下如 果LSB 为0 则不进行整个过程要重复8 次在最后一位第8 位完成后下一个8 位字节 又单独和寄存器的当前值相或最终寄存器中的值是消息中所有的字节都执行之后的CRC 值 珠海市裕泉水务公司 Http://plc.21ds.com Email:zhuhai007@tom.com 8 CRC 添加到消息中时低字节先加入然后高字节 CRC 简单函数如下 unsigned short CRC16(puchMsg, usDataLen) unsigned char *puchMsg ; /* 要进行CRC 校验的消息 */ unsigned short usDataLen ; /* 消息中字节数 */ { unsigned char uchCRCHi = 0xFF ; /* 高CRC 字节初始化 */ unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */ unsigned uIndex ; /* CRC 循环中的索引 */ while (usDataLen--) /* 传输消息缓冲区 */ { uIndex = uchCRCHi ^ *puchMsgg++ ; /* 计算CRC */ uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex} ; uchCRCLo = auchCRCLo[uIndex] ; } return (uchCRCHi << 8 | uchCRCLo) ; } /* CRC 高位字节值表 */ static unsigned char auchCRCHi[] = 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 珠海市裕泉水务公司 Http://plc.21ds.com Email:zhuhai007@tom.com 9 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 } ; /* CRC 低位字节值表*/ static char auchCRCLo[] = 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 珠海市裕泉水务公司 Http://plc.21ds.com Email:zhuhai007@tom.com 10 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值