modbus协议讲解,上位机与PLC交互_汇川plc和上位机通讯-程序员宅基地

技术标签: C#  modbus协议  modbus  协议  上位机与PLC交互  工控  通讯协议  

开发过程中modbus-RTU需要电脑USB口对外交互,参考我的文章:C# 通过Com端口和单片机通讯(232/485/USB)_花开莫与流年错_的博客-程序员宅基地_c#与单片机通信

上位机和PLC交互的消息在Excel中配置,配置后通过Modbus协议加载到界面显示,Excel操作参考我的:C#使用EPPlus操作Excel(读写)_花开莫与流年错_的博客-程序员宅基地_epplus读取excel

PLC使用ST语言开发,参考我的文章:汇川中型PLC使用ST语言基础_花开莫与流年错_的博客-程序员宅基地_axis_ref_sm3

网络通讯概况

        上学的时候讲过网络7层架构依次为:物理层》数据链路层》网络层》传输层》会话层》表示层》应用层。而实际网络为5层结构物理层》数据链路层》网络层》传输层》应用层

        物理层,通过网线、光纤、双绞线等传输,如485/232。

        数据链路层,负责传输数据,如:以太网协议、PPP协议,CAN协议、i2c、spi等嵌入式协议一般定义了物理层和数据链路层。

        网络层的引入主要是为了屏蔽不同网络的差异,实现不同网络内主机的通信。如:ARP协议(地址解析)、IP协议、ICMP(控制报文协议,路由通不通、消息是否可达、路由是否可用)。

        传输层,每一个应用程序都有一个端口号,用于对外界发送或者接收数据。如重用的TCP、UDP协议。

        应用层,网络结构中最上层,经常被接触到,如web、ftp文件传输、smtp邮件发送等。

Modbus协议

        Modbus采用主从(Master-Salve)通信模式,仅有主设备(Master)能对传输进行初始化,从设备(Slave)根据主设备的请求进行应答。典型的主设备包括现场仪表和显示面板,典型的从设备为可编程逻辑控制器(PLC)。

        主要包含三种协议,Modbus-RTU、Modbus-ASCII和Modbus-TCP。三种协议数据格式基本一致。其中RTU英文“ Remote Terminal Unit”属于传输层、传输数据是协议定义的正整数,电脑直接通过串口与设备交互,因为TCP层有校验参数是否正常,而传输层没有,所以RTU需要计算校验码用于验证是否是正确的modbus报文。Modbus-ASCII主要区别是以ASCII格式传输数据。Modbus-TCP则数据应用层,基于TCP传输。

协议报文(走TCP不需要附加地址和校验,因为TCP有校验位了)

 PLC做主上位机为从时,上位机提供502服务端口,PLC发上位机回。PLC做从则与之相反。

 

 发收报文如下(事物处理标识符为0应该也可以)

 modbus协议完整的文档,我有,不过我还是描述我们经常用到的吧,我之前开发只用到0x03查询、0x06设单个、0x10设多个、0x41自定义(升级单板、读取电子标签)。

0x03查询命令

 0x06设置单个参数

 0x10设置多个参数:00 01 00 00 00 13 FF 10 03 E8 00 06 0C 00 24 0B 95 00 00 00 00 00 00 00 00

 校验备份C++代码

/**
  * @brief modbus rtu校验
  * @param p_data:要校验的数据的地址
  *        data_len:要校验数据的长度(字节)
  *        data_crc:数据的校验码
  * @retval 无
  */
void CRC_Checkout_16(uint8_t *p_data,uint32_t data_ len,uint8_t *data_crc)
{
  uint16_t wcrc = 0xFFFF; 
  uint8_t temp; 
  uint32_t i=0,j=0; 
  for(i=0;i<data_len;i++) 
  {
    temp = *p_data & 0X00FF; 
    p_data++; 
    wcrc = wcrc^temp; 
    for(j=0;j<8;j++) 
    {
      if(wcrc & 0X0001) 
      {
        wcrc>>=1; 
        wcrc^=0XA001; 
      }
      else 
      {
        wcrc>>=1; 
      }
    }
  }
  temp=wcrc;

  data_crc[0]=wcrc; 
  data_crc[1]=wcrc>>8; 

  return ;
}

/* 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,
  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,
  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,
  0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
  0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
  0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
  0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
  0x43, 0x83, 0x41, 0x81, 0x80, 0x40
} ;

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_17242837/article/details/128120944

智能推荐

在虚拟机中安装Linux操作系统详细步骤_虚拟机安装linux系统-程序员宅基地

文章浏览阅读3.5k次,点赞7次,收藏30次。《Linux从小白到大神》| 系统学习Linux开发、VIM/GCC/GDB/Make工具、Linux文件IO、进程管理、进程通信、多线程等,请关注专栏免费学习。本文主要介绍在VMWare虚拟机中安装Linux操作系统的原理和详细步骤。_虚拟机安装linux系统

使用puppeteer获取网页信息_puppeteer爬取网页数据-程序员宅基地

文章浏览阅读2.8k次。Puppeteer 是一个运行在Node端的浏览器,为我们提供了强大的功能,例如抓取页面数据,对页面进行截图等功能..._puppeteer爬取网页数据

[php5.2.4] explode函数不能按照"\r\n"切割字符串_explode 无法截取字符串中空格-程序员宅基地

文章浏览阅读7k次。php 版本 5.2.4现有一txt文件,格式如下:file.txt12345要将其内容按行分割存入数据$array中执行代码:$fileContent = trim(file_get_contents('file.txt');$array = explode("\r\n", $fileContent);并未达到预想的效果$array =>_explode 无法截取字符串中空格

C# List集合 GroupBy分组_c# list groupby-程序员宅基地

文章浏览阅读5.4k次。var grpBalance = listBalance.GroupBy(m => new { m.MerChantId, m.Name}).Distinct().Select(t => new balInfo { MerChantId = t.Key.MerChantId, ..._c# list groupby

【c语言基础】学习笔记+记录_c定义4字节数组-程序员宅基地

文章浏览阅读896次,点赞2次,收藏3次。c语言基础知识记录_c定义4字节数组

Kafka常见面试题-程序员宅基地

文章浏览阅读589次,点赞9次,收藏6次。接收端:对接收到的数据进行备份,定期进行检查对执行失败的数据重新执行;选择手动提交offset,对执行失败的数据不提交offset。零拷贝技术:在cache中未查到数据,从磁盘获取加载到cache中后,不copy到Kafka进程中,而是由操作系统直接发送到网卡。每隔一段时间消费数据,将当前时间与数据产生时间进行对比,小于延迟时间的不提交,并重新进入等待。在消费者端对数据进行幂等校验,禁止一定时间内出现相同含义的数据;页面缓存技术:将数据缓存到系统的cache中,在刷新到磁盘当中。

随便推点

【新型敏捷硬件开发语言——Chisel】_chisel 语言-程序员宅基地

文章浏览阅读864次。初步学习Scala与Chisel,了解HDL发展历史,同时也熟悉了项目的部署过程。_chisel 语言

遍历Stream并设置属性值_stream遍历赋值-程序员宅基地

文章浏览阅读1.2w次。// 初始化数据,设置评价等级 List<TblApplyForCleaning> list = (List<TblApplyForCleaning>) tblApplyForCleaningRepository.findAll(); list.stream().forEach(p -> { if (p.getXing() != null)..._stream遍历赋值

Matlab之图片拼接_matlab如何把四张图片合成-程序员宅基地

文章浏览阅读4.6k次,点赞8次,收藏42次。功能:可以自定义行列数拼接图片,拼接同时可以自定义对每张图片进行增(减)白边处理。1.使用Matlab建立.m文件,具体如何建立见文章:Matlab基础之.m文件创建及使用2.我写了两份代码可供参考代码一%图片合并,可以实现将一组图片变为统一规格尺寸(默认第一张图的尺寸)%可以自定义行列数拼合成一整张图片,若图片数不足行列乘积数则用等尺寸白色图片代替%可以设置为每一张图片增加或减少白..._matlab如何把四张图片合成

6-4 Reverse Linked List_write a nonrecursive procedure to reverse a singly-程序员宅基地

文章浏览阅读1k次。6-4 Reverse Linked List (20 分)Write a nonrecursive procedure to reverse a singly linked list in O(N) time using constant extra space.Format of functions:List Reverse( List L );where List is ..._write a nonrecursive procedure to reverse a singly linked list in o(n) time

深度学习 Pytorch Mnist手写数字识别_mnist_train-程序员宅基地

文章浏览阅读606次。mnist手写数字识别_mnist_train

05-黑盒测试用例_反测试用例用写吗-程序员宅基地

文章浏览阅读117次。等价划分法用例问题用例按照测试分类:功能function、界面ui、性能performance、安全security、接口interface测试项:必须是确定的,可写可不写,最好不写身份证号没有字母,数字和罗马数字Ⅹ测试项:一般只写一个测试目的(测试目的必须是明确的,一个反向的(无效的等价类)只要违反一个需求)注意单选复选按钮依赖用例:下游的用例依赖上游的用例(已经存在的用例),用例依赖可以跨越模块(A设计员可能会依赖B设计员的测试用例)测试步骤:表明操作对象和方式,数据测试数据:没有数_反测试用例用写吗

推荐文章

热门文章

相关标签