源码下载:https://download.csdn.net/download/foxclever/12838885

自从开源了我们自己开发的Modbus协议栈之后,有很多朋友建议我针对性的做几个示例。所以我们就基于平时我们的应用整理了几个简单但可以说明基本的应用方法的示例,这一篇中我们来简述如何使用协议栈实现一个Modbus TCP服务器应用。

1、何为TCP服务器

Modbus协议是一个主从协议,那肯定就有主站和从站之分,在Modbus TCP中亦称之为客户端与服务器。所谓TCP客户端其功能基本与RTU主站一样,RTU主站会向从站发起数据请求,同样的TCP客户端也会向服务器发起请求。也就是说在Modbus TCP模式下客户端亦是发起通讯的一方。

对于TCP客户端来说,自己并不会产生数据,它的数据均是从服务器获取,为了得到数据就必须向服务器发起数据请求。在Modbus TCP协议中,服务器一般也不会主动向外发送数据,服务器需要根据客户端的数据请求来决定是否发送数据、发送哪些数据。这一过程如下图所示:

从上图我们不难看出,首先客户端要主动发起数据请求,客户端发起的数据请求需要告诉服务器它请求的数据有哪些。服务器收到这个数据请求后,服务器解析客户端的请求并按照客户端的请求返回数据。客户端收到数据响应后解析数据,这样就完成了客户端与服务器之间的一次数据通讯。

需要注意的是,Modbus TCP与Modbus RTU不同的是有一个专用的MBAP报文头来识别Modbus应用数据单元。这一报文头由7个字节组成:

这种MBAP报文头虽然也是用来识别Modbus数据域,但还是与串行链路上使用的MODBUS RTU应用数据单元有一些差别,具体如下:

(1)、用MBAP报文头中的单个字节单元标识符取代MODBUS串行链路上通常使用的MODBUS从地址域。这个单元标识符用于设备的通信,这些设备使用单个 IP 地址支持多个独立MODBUS 终端单元,例如:网桥、路由器和网关。

(2)、使用接收者可以验证的方式来构造所有MODBUS请求和响应。对于MODBUS PDU有固定长度的功能码来说,仅功能码就足够了。对于在请求或响应中携带一个可变数据的功能码来说,数据域包括字节数。

(3)、使用TCP上传送MODBUS数据域时,即使将报文分成多个信息包来传输,可在MBAP报文头上携带附加长度信息,这样接收者就能够识别报文的完整性。

2、如何实现TCP服务器

我们已经简单的描述了基于TCP/IP的Modbus数据通讯,在此基础上我们将进一步描述基于协议栈的Modbus TCP服务器的实现。

在协议栈中,我们已经实现了Modbus TCP服务器的基本功能,如数据的管理及响应客户端的请求等。Modbus TCP服务器作为数据的生产者,管理者四类数据:线圈量、状态量、输入寄存器和保持寄存器。所以在Modbus TCP服务器中我们要为这四种数据定义相应的地址,以便客户端能够对应的访问。所以设计一个Modbus TCP服务器我们先来设计它的数据地址。在我们的例子中,出于操作方便,我们规定了每类数据类型的数量为10,我们以用的最多的保持寄存器为例,定义寄存器地址为40001到40010。

在我们的协议栈中实现了0x01、0x02、0x03、0x04、0x05、0x06、0x0F以及0x10等功能码。也就是说客户端对象会生成面向这些功能码的Modbus TCP服务器数据请求。Modbus TCP服务器收到请求后,解析请求并根据请求生成响应的数据响应。可以表示为下图所示:

从上图我们明白协议栈中已经实现了对收到的主站数据请求进行解析以及根据解析生成对应的响应的函数。我们使用协议栈时,主要需要做两个方面的事情:解析数据请求和生成数据响应。

在协议栈中定义了一个解析函数,该函数将收到的数据请求消息解析,并根据解析的结果生成返回的数据响应。该函数的原型如下:

/*解析接收到的信息,返回响应命令的长度*/

uint16_t ParsingClientAccessCommand(uint8_t *receivedMessage,uint8_t*respondBytes)

这个函数有2个参数:uint8_t *receivedMessage是收到的数据请求消息; uint8_t*respondBytes是返回的数据响应消息,也是函数需要生成的;而函数的返回值则是生成的数据响应详细的长度。

在解析的过程中,该函数判断消息的完整性,并根据不同的功能码调用不同的回调函数来实现,包括设置本地数据和获取本地数据的相关回调函数,在后续将讨论它们的实现。

3TCP服务器编码

到这里其实我们已经很清楚,使用协议栈实现Modbus TCP服务器只需要在TCP/IP收到客户端请求后调用sendLen = ParsingClientAccessCommand(buffer,sendBuf);函数解析收到的请求命令。并根据请求执行相应的操作就可以了。那需要实现哪些操作呢?在协议栈中定义了8个回调函数,分别是获取线圈量、获取状态量、获取输入寄存器和获取保持寄存器,以及预置单个线圈量、预置多个线圈量、预置单个保持寄存器和预置多个保持寄存器。函数原型定义如下:

/*获取想要读取的Coil量的值*/__weak void GetCoilStatus(uint16_t startAddress,uint16_t quantity,bool*statusList){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容} /*获取想要读取的InputStatus量的值*/__weak void GetInputStatus(uint16_t startAddress,uint16_t quantity,bool*statusValue){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容} /*获取想要读取的保持寄存器的值*/__weak void GetHoldingRegister(uint16_t startAddress,uint16_t quantity,uint16_t*registerValue){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容} /*获取想要读取的输入寄存器的值*/__weak void GetInputRegister(uint16_t startAddress,uint16_tquantity,uint16_t *registerValue){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容} /*设置单个线圈的值*/__weak void SetSingleCoil(uint16_t coilAddress,bool coilValue){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容} /*设置单个寄存器的值*/__weak void SetSingleRegister(uint16_t registerAddress,uint16_tregisterValue){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容} /*设置多个线圈的值*/__weak void SetMultipleCoil(uint16_t startAddress,uint16_t quantity,bool*statusValue){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容} /*设置多个寄存器的值*/__weak void SetMultipleRegister(uint16_t startAddress,uint16_tquantity,uint16_t *registerValue){  //如果需要Modbus TCP Server/RTU Slave应用中实现具体内容}

这些函数就是我们要根据我们的Modbus TCP服务器功能设计实现的。对于我们这个测试例子我们只需要实现读取保持寄存器就可以了。具体实现如下:

/*获取想要读取的保持寄存器的值*/void GetHoldingRegister(uint16_t startAddress,uint16_t quantity, uint16_t* registerValue){   uint16_t start;   uint16_t count;       /*先判断地址是否处于合法范围*/    start =(startAddress > 0) ? ((startAddress <= 9) ? startAddress : 9) : 0;    count =((start + quantity - 1) <= 9) ? quantity : (9 - start);     for(int i = 0; i     {       registerValue[i] = holdingRegister[start + i];    }}

这个例子中我们实现了读取40001到40010保持寄存器的值。

4TCP服务器小结

我们在TCP服务器的基础上使用我们的协议栈实现一个Modbus TCP服务器应用。其实使用协议栈实现Modbus TCP服务器应用是很简单的,我们需要使用如ModPoll这样的软件来测试一下它。

我们读取10个保持寄存器,值分别为对应位固定的1到10,如上图读出的结果与预期一致。我们还可以采用TCP&UDP测试工具来看一下报文,具体如下:

同样的,在同一台设备上只需实现一个Modbus TCP服务器,哪怕是通过不同的网络端口来访问。这一点与客户端是不一样的,原因是Modbus TCP服务器的数据是自己产生,而且只需被动响应客户端的数据请求。

接下来我们来总结一下使用协议栈实现Modbus TCP服务器的工作流程,或者说实现的步骤。首先Modbus TCP服务器要解析从客户端送来的数据请求。在协议栈中已经封装了数据请求的解析函数、所以我们实现Modbus TCP服务器时首先就是调用这一函数来解析接收到的数据请求消息。

然后将解析函数返回的数据响应消息发送到客户端就可以了。也就是说使用协议栈,只需要调用一下这个函数Modbus TCP服务器功能就实现了。这是因为这个函数实现了整个Modbus TCP服务器的响应过程,大致分三个步骤:第一步,解析收到的客户端数据请求消息;第二步,根据解析的结果预置数据或者获取数据,预置和获取数据由8个回调函数实现;第三步,生成Modbus TCP服务器数据响应消息。说到这里我们已经清楚,Modbus TCP服务器必须实现这些回调函数,其它工作则全由协议栈完成。

源码下载:https://download.csdn.net/download/foxclever/12838885

欢迎关注:

modbus tcp主站和从站_【技术】Modbus协议栈应用实例之四:ModbusTCP服务器应用相关推荐

  1. modbus tcp主站和从站_组态王与西门子 PLC无线Modbus通讯

    组态王与西门子PLC无线Modbus通信方案 本方案是组态软件与西门子S7-200 Smart 进行无线MODBUS 通信的实现方法.此方案可以作为西门子S7-200 Smart与组态软件的无线MOD ...

  2. modbus tcp主站和从站_【智】S7200PLC与台达变频器MODBUS轮询实时读取详解

    大家好,我是微控小智,今天又跟大家见面了.学习不是一蹴而就,需要坚持,做技术亦是如此,厚积才能博发. 上次分享的S7-200PLC与台达VFD_M变频器Modbus通讯案例程序,是采用SM0.5时钟脉 ...

  3. modbus tcp主站和从站_ModBus的加深理解与实际应用举例

    今天主要讲一下怎么更加用简单的方式去理解ModBus协议. (一)什么是协议ModBus是一种协议,可以理解成一种语言.比如小王说的是汉语,小张说的是英语,如果小王和小张路上碰见了,那小王说了一堆,小 ...

  4. modbus tcp主站和从站_Modbus-RTU 一主多从PLC无线通讯经典案例

    一.无线方案简介 该方案可适用于 3 台以上西门子 PLC,S7-200 或 S7-200Smart 之间实现一主多从Modbus 通讯协议的无线通讯. 适用 PLC 型号:S7-200 和 S7-2 ...

  5. c#modbus tcp通讯助手开源_RS485和Modbus知识点汇总

    RS485 RS485 特点: 1.逻辑"1"以两线间的电压差为+(2-6)V表示:逻辑"0"以两线间的电压差为-(2-6)V表示.接口信号电平比RS232降低 ...

  6. Modbus协议栈应用实例之四:ModbusTCP服务器应用

    自从开源了我们自己开发的Modbus协议栈之后,有很多朋友建议我针对性的做几个示例.所以我们就基于平时我们的应用整理了几个简单但可以说明基本的应用方法的示例,这一篇中我们来简述如何使用协议栈实现一个M ...

  7. 三菱fx5u modbus tcp fb块用法_一文教会你,如何掌握三菱FX5U PLC基础知识

    现在市面上三菱FX5U PLC因自身的性能特点,使用的人群越来越广! 01 首先FX5U PLC支持结构化程序,并可写入ST语言和FB语言,以及支持多个程序的执行. 02 其次,在FX系列中,FX5U ...

  8. 三菱fx5u modbus tcp fb块用法_三菱PLC型号怎么选?四大方面告诉你三菱FX3U和5U的最大区别!...

    三菱FX3U系列PLC是第三代微型可编程控制器,采用一类可编程的存储器,用于其内部存储程序,执行逻辑运算.顺序控制.定时.计数与算术操作等面向用户的指令,并通过数字或模拟式输入/输出控制各种类型的机械 ...

  9. tcp转串口_PROFIBUS DP与Modbus/TCP网络转换操作指南

    >>PROFIBUS DP转Modbus/TCP网关操作指南 摘要: 本文以NT100-RE-DP网关为例,实现Modbus/TCP Client与PROFIBUS DP设备间的通讯,从而 ...

最新文章

  1. CentOS 6.3 安装 samba 共享
  2. python下载word文件-python-docx操作word文件(*.docx)
  3. 如何看待第三代神经网络SNN?详解脉冲神经网络的架构原理、数据集和训练方法 原创
  4. django中的项目使用mysql中的配置新建用户授予权限
  5. web前端实战系列[1]——三列布局
  6. 企业实战(Jenkins+GitLab+SonarQube)_05_Jenkins创建管理员用户
  7. 1562区别 洛达1552_洛达1562A与洛达1536u与杰里有哪些区别呢?
  8. 判断作弊 牛客 编程_牛客企业服务产品-新功能速递-第5期
  9. Android新浪微博分享
  10. html编辑器pp,在线轻设计工具之H5
  11. 台式电脑主板插线步骤图_图解电脑主机电源线接法图解
  12. ERNIE: Enhanced Language Representation with Informative Entities
  13. yolov3的weights文件获取方法(yolov3-spp.weights等等)
  14. C语言求ax2+bx+c=0的解,解一元二次方程
  15. 【调研】Soft Prompt Tuning 模型发展调研:P-tuning,Prefix-tuning,Prompt-tuning,P-tuning v2,PPT
  16. F28335 PWM触发ADC采样 代码+注释
  17. 聊聊那些年的骚操作!!!
  18. 计算机英语图片素材,计算机编程英语素材.docx
  19. scrapy爬取起点小说网
  20. [高通SDM450][Android9.0]同一套代码兼容不同的emmc

热门文章

  1. Android 使用Zxing
  2. android 7.0 系统关闭彩信过CTA测试的方法
  3. php四舍五入+1位小数,PHP 四舍五入精确小数位及取整
  4. 2022-2028全球与中国在线股票交易平台市场现状及未来发展趋势
  5. c语言八字节,C语言相关
  6. 设计新一代的网游——第三章(游戏概况)
  7. [转]注册表基本知识
  8. 数据恢复在计算机应用重要性,恢复数据的重要性.doc
  9. Linux配置安装 Elasticsearch 7.10.2 详细教程
  10. 远程访问JMX遇到连接不上的问题(JConsole和VisualVM工具类似)