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

自从开源了我们自己开发的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_t quantity,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_t registerValue)
{//如果需要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_t quantity,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 < count; 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

协议栈源码下载:https://github.com/foxclever/Modbus

欢迎关注:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外设驱动库开发笔记14:DS18B20温度变送器驱动

在一时候我们需要相对简单的检测温度信号&#xff0c;而DS18B20就是一款功能和应用都相对简单的温度传感器&#xff0c;通过单线就可以实现检测温度信号的需求。这一篇我们就来实现操作DS18B20获取温度数据的驱动。 1、功能概述 DS18B20是常用的数字温度传感器&#xff0c;其…

Modbus协议栈应用实例之五:Modbus ASCII主站应用

自从开源了我们自己开发的Modbus协议栈之后&#xff0c;有很多朋友建议我针对性的做几个示例。所以我们就基于平时我们的应用整理了几个简单但可以说明基本的应用方法的示例&#xff0c;这一篇中我们来使用协议栈实现Modbus ASCII主站应用。 1、何为ASCII主站 我们知道Modbus…

Modbus协议栈应用实例之六:Modbus ASCII从站应用

自从开源了我们自己开发的Modbus协议栈之后&#xff0c;有很多朋友建议我针对性的做几个示例。所以我们就基于平时我们的应用整理了几个简单但可以说明基本的应用方法的示例&#xff0c;这一篇中我们来使用协议栈实现Modbus ASCII从站应用。 1、何为ASCII从站 我们知道Modbus…

外设驱动库开发笔记15:DHT11温湿度传感器驱动

与DS18B20一样DHT11也是采用单总线&#xff0c;但所不同的是DHT11可同时实现温度和湿度的检测。在我们的产品中经常使用它来检测环境的温湿度信息。这一篇我们将设计并封装DHT11的驱动程序&#xff0c;以方便重复使用。 1、功能概述 DHT11数字温湿度传感器是一款含有已校准数…

外设驱动库开发笔记16:MS5536C压力变送器驱动

压力检测也是经常会遇到的需求&#xff0c;比如环境压力或者低压气体等都会用到压力检测。这类检测压力都比较低&#xff0c;一般不会超过大气压&#xff0c;有时甚至是负压。这一篇我们要讨论的MS5536C就属于这类器件。接下来我们将设计并实现MS5536C的驱动。 1、功能概述 M…

外设驱动库开发笔记17:MS5803压力变送器驱动

很多时候我们需要检测被控对象的绝对压力&#xff0c;而且在我们的多款产品中也有这样的需求。当然检测绝对压力的传感器有很多&#xff0c;我们经常使用MS5803来实现压力检测。本篇中我们将设计并实现MS5803系列压力传感器的驱动。 1、功能概述 MS5803系列产品包含压阻传感器…

通讯接口应用笔记1:RS485通讯上下拉电阻的选择

RS485是一种常见的通讯接口方式&#xff0c;在我们的实际产品中也是多次使用。但我们平常并不会去过多考虑某一实现的细节问题&#xff0c;不过最近我们遇到了一个因如上下拉电阻的选择问题而造成的通讯故障&#xff0c;所以在这一片中我们来讨论一下RS485总线上下拉电阻的选择…

外设驱动库开发笔记18:MS5837压力变送器驱动

绝对压力的检测是常见的需求。在我们的系统中也常常会遇到。而MS5837压力传感器也是我们进场会采用的方案。在这篇里我们将讨论并实现MS5837压力传感器的驱动。 1、功能概述 MS5837压力传感器是一种可用于电路板上&#xff0c;适用于检测10-1200mbar压力范围的传感器&#xf…

外设驱动库开发笔记19:BMP280压力温度传感器驱动

压力和温度监测在嵌入式系统开发中是非常常见的需求&#xff0c;特别是对环境大气压力和温度的检测需求就更常见了。我们一般都会选择一些封装较小操作比较方便的压力传感器。BMP280就是满足这一要求的器件。在这一篇中我们将设计并实现BMP280的驱动。 1、功能概述 BMP280是一…

一个简单的空气质量数据监测站项目

大气质量数据监测站用于测试空气质量监测及数据采集&#xff0c;实现野外或者室内空气质量的检测。并通过网络将数据上传到OneNet​显示。​ 1、项目概述 本项目是一个定制项目&#xff0c;要求采集大气的压力、温度、湿度、PM25、位置等数据并上传到指定的后台服务器。但有时…

一个基于STM32实现的多组分气体分析仪项目

本篇将简要的总结一下一个基于STM32F412ZG实现的多组分气体分析仪的项目。简要描述该项目的软硬件设计及其验证。 一、项目概述 多组分气体分析仪是我公司近期研发的三个主要产品之一。采用模块化设计&#xff0c;可增减配置&#xff0c;可分析混合气体中的氧气、氢气、甲烷、…

外设驱动库开发笔记20:BME280压力湿度温度传感器驱动

嵌入式产品开发中&#xff0c;我们常常会有检测环境温度、压力、湿度的需求。如果有一个集成有这3个传感器的元件&#xff0c;无疑将是很方便的。博世的BME280就能实现这一要求。在这一篇中我们将讨论BME280的驱动设计与实现。 1、功能概述 BME280是一款专为移动应用而开发的…

外设驱动库开发笔记21:BME680环境传感器驱动

环境传感器是一类我们很常用的传感器。它可以方便我们获取压力、温度、湿度以及空气质量等数据。在这一篇中&#xff0c;我们将分析BME680环境传感器的功能&#xff0c;并设计和实现BME680环境传感器的驱动。 1、功能概述 BME680是一款专为移动应用和可穿戴设备开发的集成环境…

外设驱动库开发笔记22:ADXL345三轴数字加速度计驱动

移动设备的广泛应用增加对移动过程中各种参数的检测需求。ADXL345三轴数字加速度计可以用来检测加速度、进而测量倾斜角度等。在这一篇中&#xff0c;我们将讨论ADXL345三轴数字加速度计驱动程序的设计与实现。 1、功能概述 ADXL345是一款小而薄的超低功耗3轴加速度计&#x…

外设驱动库开发笔记23:AT24Cxx外部存储器驱动

在我们的应用开发过程中&#xff0c;经常会使用到外部的EEPROM外部存储器来保存一些参数和配置数据等。而比较常用的就是AT24Cxx系列产品&#xff0c;这一节我们来开发用于操作AT24Cxx系列产品的驱动。 1、功能概述 AT24Cxx系列EEPROM包括从1Kbit到2Mbit的各种容量。AT24Cxx系…

外设驱动库开发笔记24:FM24xxx系列FRAM存储器驱动

虽然说使用EEPROM保存参数很有效&#xff0c;但操作及使用次数均有一下限制。当我们的一些参数需要不定时修改或存储时&#xff0c;使用FRAM就更为方便一点。这一节我们就来设计并实现FM24xxx系列FRAM的驱动。 1、功能概述 我们首先说一下铁电随机存取存储器&#xff0c;F-RA…

外设驱动库开发笔记25:FM25xxx FRAM存储器驱动

在我们的项目中&#xff0c;时常会有参数或数据需要保存。铁电存储器的优良性能和操作方便常常被我们选用。FM25xxx FRAM存储器就是我们经常使用到的一系列铁电存储器&#xff0c;这一篇我们将讨论FM25xxx FRAM存储器的驱动设计、实现及使用。 1、功能概述 FM25xxx FRAM存储器…

步进电机驱动技术1:基于TMC2660的步进电机驱动

步进电机的应用非常广泛&#xff0c;在各种设备中经常会遇到&#xff0c;而步进电机的驱动则是使用步进电机必不可少的部分&#xff0c;可以有多种方式来实现步进电机的驱动&#xff0c;在这里我们来考虑一下基于TMC2660驱动芯片的步进电机驱动。 1、功能概述 TMC2660是德国T…

外设驱动库开发笔记26:nRF24L01无线通讯驱动

现在无线在我们的生活中无处不在。而我们开发的物联网产品也大量使用无线通讯。在这一篇文章中&#xff0c;我们将讨论nRF24L01无线通讯模块驱动程序的开发与实现。 1、功能概述 nRF24L01是一款工作在2.4~2.5GHz世界通用ISM 频段的单片无线收发器芯片无线收发器包括&#xff…

外设驱动库开发笔记27:ESP8266无线通讯驱动

我们的物联网产品所使用的平台都支持无线通讯&#xff0c;而且无线通讯本身更的成本较低&#xff0c;受到大家的欢迎。在本篇文章中&#xff0c;我们将详细讨论并实现ESP8266无线通讯模块的驱动。 1、功能概述 ESP8266是由乐鑫公司出品的一款物联网芯片&#xff0c;因为价格较…