modbus rtu如何读取数据??
7 个回答
1、简述
本篇博文分享一款开源的Modbus协议栈。
协议栈支持Modbus主机和从机两种模式,并且支持两种模式同时开启。从机支持Modbus RTU 、Modbus ASCII及Modbus TCP 3种模式,主机现在只支持常用的Modbus RTU模式。
资源下载: ModbusRTU、ModbusASCII及ModbusTCP驱动代码,支持主机和从机两种模式资源-CSDN文库
|源文件 |描述 |
|:------------------------------ |:----- |
|FreeModbus\modbus\mb.c |给应用层提供Modbus从机设置及轮询相关接口|
|FreeModbus\modbus\mb_m.c |给应用层提供Modbus主机设置及轮询相关接口|
|FreeModbus\modbus\ascii\mbascii.c |ASCII模式设置及其状态机|
|FreeModbus\modbus\functions\mbfunccoils.c |从机线圈相关功能|
|FreeModbus\modbus\functions\mbfunccoils_m.c |主机线圈相关功能|
|FreeModbus\modbus\functions\mbfuncdisc.c |从机离散输入相关功能|
|FreeModbus\modbus\functions\mbfuncdisc_m.c |主机离散输入相关功能|
|FreeModbus\modbus\functions\mbfuncholding.c |从机保持寄存器相关功能|
|FreeModbus\modbus\functions\mbfuncholding_m.c |主机保持寄存器相关功能|
|FreeModbus\modbus\functions\mbfuncinput.c |从机输入寄存器相关功能|
|FreeModbus\modbus\functions\mbfuncinput_m.c |主机输入寄存器相关功能|
|FreeModbus\modbus\functions\mbfuncother.c |其余Modbus功能|
|FreeModbus\modbus\functions\mbutils.c |一些协议栈中需要用到的小工具|
|FreeModbus\modbus\rtu\mbcrc.c |CRC校验功能|
|FreeModbus\modbus\rtu\mbrtu.c |从机RTU模式设置及其状态机|
|FreeModbus\modbus\rtu\mbrtu_m.c |主机RTU模式设置及其状态机|
|FreeModbus\modbus\tcp\mbtcp.c |TCP模式设置及其状态机|
|FreeModbus\port\port.c |实现硬件移植部分接口|
|FreeModbus\port\portevent.c |实现从机事件移植接口|
|FreeModbus\port\portevent_m.c |实现主机事件及错误处理移植接口|
|FreeModbus\port\portserial.c |从机串口移植|
|FreeModbus\port\portserial_m.c |主机串口移植|
|FreeModbus\port\porttimer.c |从机定时器移植|
|FreeModbus\port\porttimer_m.c |主机定时器移植|
|FreeModbus\port\user_mb_app.c |定义从机数据缓冲区,实现从机Modbus功能的回调接口|
|FreeModbus\port\user_mb_app_m.c |定义主机数据缓冲区,实现主机Modbus功能的回调接口|
> 注:所有带_m后缀的文件为主机模式下必须使用的文件,如使用从机模式则无需这些文件。
----------
2、移植
对于协议栈的移植主要包括两个方面,硬件及软件。用户需要根据自己的需求进行自行选择。
> 注:以下所有说明都主要针对Modbus主机模式进行介绍。
2.1、软件
软件方面支持基于裸机及实时操作系统的移植;支持单个主机与单个从机同时独立运行。另外用户也可以修改协议栈的事件回调接口,使主机请求的接口采用阻塞及非阻塞模式;主机资源等待方面,用户也可以设置等待超时时间等等,诸多功能将会一一介绍。
2.1.1、操作系统与裸机
对于操作系统与裸机目前协议栈都是支持的,但个人更加推荐采用实时操作系统,因为这样会使得接口调用及接口移植变得更加简单。目前移植完成的操作系统包括国人的 [RT-Thread][1] (详见项目源码) 、 UCOS 及 FreeRTOS。
操作系统与裸机移植的过程中涉及的文件为`FreeModbus\port\portevent_m.c`
该文件主要有以下需要用户移植的接口:
|接口 |功能描述|
|:----- |:----|
|xMBMasterPortEventInit |主机事件初始化|
|xMBMasterPortEventPost |主机发送事件|
|xMBMasterPortEventGet |主机获取事件|
|vMBMasterOsResInit |主机操作系统资源初始化|
|xMBMasterRunResTake |主机资源获取|
|vMBMasterRunResRelease |主机资源释放|
|vMBMasterErrorCBRespondTimeout |主机响应超时回调接口|
|vMBMasterErrorCBReceiveData |主机接收数据出错回调接口|
|vMBMasterErrorCBExecuteFunction |主机执行Modbus方法出错回调接口|
|vMBMasterCBRequestScuuess |主机请求执行成功回调接口|
|eMBMasterWaitRequestFinish |主机等待请求完成处理回调接口|
在 **基于操作系统移植** 时,主要用到操作系统线程同步方面的技术,Modbus 协议栈自身需要使用操作系统自带的事件机制来实现事件的发送通知与等待获取,同时用户请求 Modbus 功能的线程与 Modbus 协议栈自身线程(Modbus Poll 线程)需要通过事件机制实现两个线程的同步;主机协议栈还需要一个主机资源占用的信号量,初始化默认为1,采用信号量保证了多线程同时发送主机请求时,只有一个线程可以使用主机。
在 **基于裸机移植** 时,需要通过软件模拟方式实现事件通知机制,事件等待及资源等待都得采用用户自定义延时及标志变量来实现,实现起来比操作系统模式下的线程同步机制要复杂很多。
2.1.2、数据缓冲区
数据缓冲区定义的位置位于 `FreeModbus\port\user_mb_app_m.c` 文件顶部,共计 **4种** 数据类型。
FreeModbus从机默认使用 **一维数组** 作为缓存区数据结构,主机可以存储所有网内从机的数据,所以主机采用 **二维数组** 对所有从机节点数据进行存储。二维数组的列号代表寄存器、线圈及离散量地址,行号代表从机节点ID,但需要做减一处理,例如`usMRegHoldBuf[2][1]`代表从机ID为 3,保持寄存器地址为 1 的从机数据。
2.1.3、Modbus数据处理回调接口
Modbus 一共有4种不同的数据类型,所有的 Modbus 功能都围绕这些数据类型进行操作。由于不同的用户数据缓冲区结构可能有所不同,那么对应的 Modbus 数据处理方式也就存在差异,所以用户需要把每种数据类型对应的操作,按照自己的数据缓冲区结构进行定制实现。
所有的 Modbus 数据处理回调接口如下:
|接口 |功能描述|
|:----- |:----|
|eMBMasterRegInputCB |输入寄存器回调接口|
|eMBMasterRegHoldingCB |保持寄存器回调接口|
|eMBMasterRegCoilsCB |线圈回调接口|
|eMBMasterRegDiscreteCB |离散输入回调接口|
2.2、硬件
移植 FreeModbus 协议栈主机部分时,在硬件方面需要修改串口及定时器配置,文件位于port文件下,用户需要根据自己的CPU进行移植修改。
> 注:协议栈默认自带STM32F103X移植文件,用户可以参考移植
这里提一下基于操作系统设备驱动框架的移植,后期协议栈会增加对 [RT-Thread][1] 自带设备驱动框架的移植,只要是 RT-Thread 的 BSP 支持的 MCU,用户都无需考虑底层的移植过程,减低移植成本。
2.2.1、串口
涉及到串口的移植文件位于`FreeModbus\port\portserial_m.c`,在这个文件中用户需要对以下接口方法进行修改
|接口 |功能描述|
|:----- |:----|
|vMBMasterPortSerialEnable |使能和失能串口的发送及接收功能,如使用485总线,需要注意收发模式切换|
|vMBMasterPortClose |关闭串口|
|xMBMasterPortSerialInit |串口初始化,如果使用485,收发模式切换引脚也要在此初始化|
|xMBMasterPortSerialPutByte |串口发送单字节数据|
|xMBMasterPortSerialGetByte |串口接收单字节数据|
|prvvUARTTxReadyISR |串口发送完成中断服务程序接口,按照默认方式,直接引用`pxMBMasterFrameCBTransmitterEmpty`方法即可|
|prvvUARTRxISR |串口接收中断服务程序接口,按照默认方式,直接引用`pxMBMasterFrameCBByteReceived`方法即可|
> 还需要在文件末尾增加 CPU 的自带的串口服务程序,将上表中的发送及接收中断程序接口,放到对应的中断服务程序中去即可。
2.2.2、定时器
涉及到定时器的移植文件位于`FreeModbus\port\porttimer_m.c`,在这个文件中用户需要对以下接口方法进行修改
|接口 |功能描述|
|:----- |:----|
|xMBMasterPortTimersInit |定时器初始化,将定时器预分频数及T3.5时间计数值分别备份到`usPrescalerValue`及`usT35TimeOut50us`|
|vMBMasterPortTimersT35Enable |设置定时器按照T3.5时间开始计数|
|vMBMasterPortTimersConvertDelayEnable |设置定时器按照广播帧的转换延时时间开始计数|
|vMBMasterPortTimersRespondTimeoutEnable |设置定时器按照响应超时时间开始计数|
|vMBMasterPortTimersDisable |失能定时器,定时器将停止计数|
|prvvTIMERExpiredISR |定时器中断服务程序接口,按照默认方式,直接引用`pxMBMasterPortCBTimerExpired`方法即可|
> 注:
> 1、`usPrescalerValue`及`usT35TimeOut50us`在文件顶部有定义
> 2、转换延时时间及响应超时时间在`FreeModbus\modbus\include\mbconfig.h`,用户可以根据自己系统的特点自行设置。
除上面接口方法外,用户需要在文件末尾增加 CPU 的自带的定时器中断服务程序,将上表中的定时器中断服务程序接口放进去。
3、API
Modbus 主机使用过程中与从机有很大不同,从机是需要被动等待主机请求,而主机则是主动发出请求,并接收处理从机响应。在主机发送广播请求的时候,从机不需要返回响应,所以广播请求适合主机的写从机数据命令,不适合读从机数据命令。
主机请求API中的所有方法的返回值格式都相同,返回值意义如下。
|返回值 |描述|
|:----- |:----|
|MB_MRE_NO_ERR |正常,没错误|
|MB_MRE_NO_REG |寄存器、线圈或离散输入地址出错|
|MB_MRE_ILL_ARG |入参格式有误|
|MB_MRE_REV_DATA |接收数据出错|
|MB_MRE_TIMEDOUT |响应超时。主机在设定的时间内未收到从机响应。|
|MB_MRE_MASTER_BUSY |主机忙。在设定的时间内,没有请求没有被发送。|
|MB_MRE_EXE_FUN |主机收到响应后,执行Modbus方法(功能)出错。|
> 所有的主机请求方法都是 **线程安全** 的也是 **阻塞模式** 的。在使用过程中,只要在设定的超时时间内没有得到主机资源,就会返回主机忙;如果在设定的超时时间内得到主机资源,那么必须等待得到请求结果后才会返回。
3.1、写单个保持寄存器
往从机某个保持寄存器中写入数据
```C
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usRegData,
LONG lTimeOut );
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usRegAddr |写寄存器的地址|
|usRegData |写寄存器的数据|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.2、写多个保持寄存器
往从机多个保持寄存器中写入数据。
```C
eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
USHORT * pusDataBuffer,
LONG lTimeOut )
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usRegAddr |写寄存器的起始地址|
|usNRegs |写寄存器的总数|
|pusDataBuffer |写寄存器的数据|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.3、读多个保持寄存器
读取多个保持寄存器中的数据
```C
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
LONG lTimeOut );
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usRegAddr |读寄存器的地址|
|usRegData |读寄存器的数量|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.4、读写多个保持寄存器
先读多个寄存器,然后再写多个寄存器。
```C
eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usReadRegAddr,
USHORT usNReadRegs,
USHORT * pusDataBuffer,
USHORT usWriteRegAddr,
USHORT usNWriteRegs,
LONG lTimeOut )
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usReadRegAddr |读寄存器的地址|
|usNReadRegs |读寄存器的数量|
|pusDataBuffer |写寄存器的数据|
|usWriteRegAddr |写寄存器的地址|
|usNWriteRegs |写寄存器的数量|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.5、读多个输入寄存器
读取多个输入寄存器中的数据
```C
eMBMasterReqErrCode eMBMasterReqReadInputRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
LONG lTimeOut );
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usRegAddr |读寄存器的地址|
|usRegData |读寄存器的数量|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.6、写单个线圈
往从机某个线圈中写入数据
```C
eMBMasterReqErrCode eMBMasterReqWriteCoil( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usCoilData,
LONG lTimeOut )
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usCoilAddr |写线圈的地址|
|usCoilData |写线圈的数量|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.7、写多个线圈
往从机多个线圈中写入数据。
```C
eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usNCoils,
UCHAR * pucDataBuffer,
LONG lTimeOut)
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usCoilAddr |写线圈的起始地址|
|usNCoils |写线圈的总数|
|pucDataBuffer |写线圈的数据|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.8、读多个线圈
读取多个线圈中的数据
```C
eMBMasterReqErrCode eMBMasterReqReadCoils( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usNCoils ,
LONG lTimeOut )
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usCoilAddr |读线圈的地址|
|usNCoils |读线圈的数量|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
3.9、读多个离散输入
读取多个离散输入中的数据
```C
eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr,
USHORT usDiscreteAddr,
USHORT usNDiscreteIn,
LONG lTimeOut )
```
|参数 |描述|
|:----- |:----|
|ucSndAddr |请求的从机地址,0代表广播。|
|usDiscreteAddr |读离散输入的地址|
|usNDiscreteIn |读离散输入的数量|
|lTimeOut |请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。|
4、流程
4.1、初始化配置流程
本协议栈所有配置参数都位于`FreeModbus\modbus\include\mbconfig.h`,目前协议栈支持主机及从机两种模式,并且支持**两种模式同时开启**。从机支持Modbus RTU 、Modbus ASCII 及Modbus TCP 3种模式,主机现在只支持常用的**Modbus RTU**模式。在使用主机的过程中,用户需要对广播的转换延时时间、命令响应超时时间及从机数量做以配置。需要注意的是,目前协议栈只支持**从机地址连续**,并且起始地址**从1开始**。
4.2、正常使用流程
这里只介绍主机的正常使用流程,在使用主机前,需要先把协议栈移植到自己的项目中去,包括上述的软件及硬件部分,移植完成后的使用流程如下
- 1、调用`eMBMasterInit`方法初始化Modbus主机协议栈,主机涉及到的一些硬件就在这个时候做了初始化
- 2、调用`eMBMasterEnable`方法启动Modbus主机
- 3、通过在线程或者定时器轮询调用`eMBMasterPoll`方法,轮询周期决定了命令的响应时间。
- 4、调用主机请求API方法,设定一定的请求超时时间,直到方法有结果后才会返回。如果方法执行成功并且命令是读命令,可以通过查看Modbus主机的数据缓冲区,获取最新从机数据。
4.3、异常处理流程
异常处理主要出现在主机正常使用过程中,所有的主机请求API的错误码都在第三章开头已经做以描述,针对的这些错误码,用户需要根据自己的产品特征去完成不同的动作。建议用户自己封装实现主机请求方法的重发机制,这样实现方式比较灵活,一般是在接收到帧数据出错及命令响应超时的错误码时需要重发,重发次数自动加一,如果重发次数超过设定值则认为从机掉线,以后所有只要是发给这个从机命令都被提前拦截掉;如果第二次重发命令响应成功,则**自动清零**该从机重发次数。
上述所有功能可以利用主机请求方法或者使用`FreeModbus\port\portevent_m.c`中的回调接口来实现,用户可以根据自己的需求灵活选择。
资源下载: ModbusRTU、ModbusASCII及ModbusTCP驱动代码,支持主机和从机两种模式资源-CSDN文库
MODBUS应用实例——使用MODBUS通信协议实现PLC对模拟量信号的采集
作者:秋实君 公众号:工控实践课
0 引言
MODBUS是一种串行 通信协议 ,是Modicon公司(现在的 施耐德电气 Schneider Electric)于1979年为使用 可编程逻辑控制器 (PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。 [1] Modbus比其他通信协议使用的更广泛的主要原因有: [2]
- 公开发表并且无版权要求;
- 易于部署和维护;
- 对供应商来说,修改移动本地的比特或字节没有很多限制。
MODBUS协议目前存在用于 串口 、 以太网 以及其他支持 互联网协议 的网络的版本。大多数MODBUS设备通信通过串口 RS-485 物理层进行。RS485有两线制和四线制两种接线,四线制只能实现点对点的通信方式,现很少采用,多采用的是两线制接线方式,这种接线方式为总线式拓扑结构,在同一总线上最多可以挂接32个节点。两线制RS-485通信链路采用双绞线进行联接,连接时只是简单地用一对双绞线将各个接口的“A”、“B”端连接起来。RS-485接口采用差分方式传输信号方式,并不需要相对于某个参照点来检测信号,系统只需检测两线之间的电位差就可以了,但收发器有一定的共模电压范围,RS-485收发器共模电压范围为-7到+12V,只有满足上述条件,整个网络才能正常工作;当网络线路中共模电压超出此范围时就会影响通信的稳定可靠,甚至损坏接口,因此需要注意信号地的连接。RS485总线传输距离较远,可达1000米,抗干扰性能比较好,在工业控制设备的通讯中被广泛使用,现在众多厂家的变频器、控制器都采用了该协议。
MODBUS协议对于串行连接。是一个用于RS485的应用最广泛的通信协议,其总线传送数据格式有HEX码数据和ASCII码两种,分别称为MODBUS-RTU和MODBUS-ASC 协议,前者为数据直接传送,而后者需将数据变换为ASCII码后传送,因此MODBUS-RTU协议的通讯效率较高,处理简单,使用得更多。MODBUS为单主多从通讯方式,采用的是主问从答方式,每次通讯都是由主站首先发起,从站被动应答。因此,如变频器之类的被控设备,一般内置的是从站协议,而PLC之类的控制设备,则需具有主站协议、从站协议。
本文通过汇川H2u系列PLC采集一个模拟量光电接近开关的应用为例,说明MODBUS协议的使用方法。
1 MODBUS协议
MODBUS协议是一个主从架构的协议。有一个节点主战,其他使用MODBUS协议参与通信的节点都是从站。每一个从站都有一个唯一的地址。在串行网络中,只有主站可以启动和发送一个命令。这些指令包括写入、读取、广播指令等。
一个MODBUS命令包含了打算执行的设备的MODBUS地址。所有设备都会收到指令,但只有指定位置的设备会执行及回应指令(地址0例外,指定地址0的指令是广播指令,所有收到指令的设备都会运行,不过不回应指令)。所有的MODBUS指令包含了检查码,以确定到达的命令没有被破坏。若存在多条MODBUS指令,其执行顺序是这样的:从开机开始,扫描第一条被驱动的MODBUS指令,若扫描到,把该MODBUS的参数记录下来,在后台执行。执行完后,返回用户程序,从刚执行的MODBUS指令位置开始扫描下一条被驱动的MODBUS指令并执行,周而复始。
主站一般为PLC,PLC中有相应的通信设置寄存器,可以选择MODBUS-RTU或MODBUS-ASC等,以及设置串口波特率、数据长度、停止位、奇偶校验等。PLC中有相应的通信发送指令以及相应数据格式。MODBUS-RTU发送的数据格式一般如下所示:
从站地址 | 功能码 | 要读写的从站的线圈或寄存器地址 | 所要读写的从站线圈或寄存器个数 | CRC校验码 |
8bit | 8bit | 16bit | 16bit | 16bit |
1)从站地址:要操作的目标设备地址。
2)功能码,由标准MODBUS协议定义,目前支持功能码有0x01,0x02,0x03,0x04,0x05,0x06,0x0f,0x10。具体含义请参照标准MODBUS协议或目标设备MODBUS协议。
3)要读或写的从机线圈(1位)或寄存器(16位)地址,取值参考从机MODBUS协议。
4)所要读写的从机线圈或寄存器个数,可为元件或常数。
5)CRC校验码。
从站返回的数据格式如下:
从站地址 | 功能码 | 回复数据的字节数量 | 回复的数据内容 | CRC校验码 |
8bit | 8bit | 16bit | 16bit×n | 16bit |
2 系统构建
本文建立了一个简单的系统来说明MODBUS的用法,系统的主站是汇川H 2u系统PLC,从站为一台模拟量转485模块带一个模拟量接近开关。模拟量接近开关输出信号为0-10V直流电压信号,模拟量转485模块输入信号为0-10V。系统的接线原理图如图1所示。
图1 PLC读取模拟量接近开关系统接线原理图
其中的PLC只绘制了与系统有关的部分,I/O信号及其他接口部分已省略。这样一个小系统有什么用途呢?他可以使用廉价的模拟量开关对运动的系统进行定位,例如下图的例子:
图2 模拟量接近开关使用场合
3 PLC编程
汇川H1U /H2U系列PLC的COM1通讯口可以使用MODBUS-RTU和MODBUS-ASC指令,可做主站也可做从站,通过系统寄存器D8126选择具体的通信模式。
H2U系列PLC中MODBUS主站通信有两种通信指令,当D8126设置为10h时为RS扩展指令、当D8126设置为20h时为MODBUS指令。两种方式都要设置D8120确定通信参数。
使用RS指令时需要设置D8120的b10位,而使用MODBUS指令时不需要设置此位。
- RS指令格式:
RS指令格式为:
RS(TXDADDR,TXDLEN,RXDADDR,RXDLEN);
TXDADDR:要发送数据地址,必须是D元件;
TXDLEN:发送数据长度,可以是变量和常数;
RXDADDR:接收数据地址:必须是D元件,编程时要留够空间;
RXDLEN:接收数据长度,可以是变量和常数。
发送请求命令:M8122,若程序把M8122置为ON,并且RS指令被驱动,即从TXDADDR指定的D元件地址起,发送TXDLEN个数据到COM1(若指定有起始符或中止符,会一起发出)。发送完成后系统自动复位M8122。接收标志:M8123,接收数据完成后,M8123自动置为on,复位将进入下一次接收状态。
RS指令之前需要编程人员事先将要发送的数据按照MODBUS-RTU发送的数据格式保存在TXDADDR中。
- MODBUS指令
此指令只能用于COM1通信,若D8126=20h,COM1协议为MODBUS-RTU主站(指令);若D8126=30h,COM1协议为MODBUS-ASC主站(指令);用哪种指令由从站所支持的协议格式定,若从站两种协议都支持而用户要求较快速的通信,建议选用RTU协议。两种协议只是通信格式不一样,对用户编程都一样,下面仅就RTU协议做说明。
MODBUS指令的语句也叫RS,其指令格式如下:
RS(ADDR&CMD,REGADDR,REGLEN,DATABUF)
- ADDR&CMD:从机地址和MODBUS功能码,高8位表示从机地址,即目标设备地址。低8位表示MODBUS功能码,0x01,0x02表示读线圈,0x03,0x04表示读寄存器,0x05表示写单个线圈,0x06表示写单个寄存器,0x0f表示写多个线圈,0x10表示写多个寄存器。
- REGADDR:所要读或写的从机线圈(1位)或寄存器(16位)地址,取值参考从机MODBUS协议。可为元件或常数。
- REGLEN:所要读写的从机线圈或寄存器个数,可为元件或常数。
DATABUF:只能为D元件。本机用于存放数据的起始寄存器,即数据缓冲区。缓冲区长度与REGLEN相关,至少取1。若MODBUS命令为读,指令成功执行完后,把从机数据读到缓冲区中,若MODBUS命令为写,把缓冲区发送给从机。用户在设计程序时需要计算缓冲区长度,预留足够的寄存器作缓冲区。
具体到本例,通信方式选择主站MODBUS-RTU,因此为D8126赋值20h,D8120设置串口参数为8位数据,无校验,1位停止位,波特率为4800bps。从站地址为1,功能码为03(读寄存器),从站中存放模拟量的地址为H40(需要从模拟量转485模块的说明书中获得),读取2个字,存放在D210中。HC5DF为指令的CRC校验码,存放在D203中,即发送数据的最后一个字,低位在前,高位在后。CRC校验码可以在网上下载专用的计算器计算。PLC程序如下图所示。
- MODBUS从站。
最后说一下MODBUS从站的用法,一般系统中除了工控机、HMI设备和PLC以外的设备都处于从站模式,当PLC由工控机或者另外一个PLC控制时也可以设置成从站模式,此时寄存器D8126的值为02h。寄存器D8120的设置与主站一致。
从站的编程比较简单,如果是读操作只要将需要需要被读取的数据写入约定好的寄存器即可,如果是写操作,直接使用约定好的寄存器的数据即可,不需要向主站发送指令。
以下指令表示将X0-X7,X10-X17的状态放置在D120中供主站读取,同时将主站发送到D106中的数据分解到Y10-Y17各位上,作为输出。
4 总结
RS485是硬件简单、通信距离比较长的串口总线,总线上可以携带32个站点,因此可以满足小型的工业现场系统的应用。MODBUS是广泛应用的用于RS485串口总线的通信协议,MODBUS采用主从模式,只有一台设备作为主站,其他设备作为从站。指令全部由总站发出,可以对从站进行读写。从站不能够主动向其他设备发送指令,只需要将需要发送的数据放入约定好的寄存器中,并从约定好的寄存器中直接使用接收的数据。发送指令的格式一般包括从站地址+功能码+从站寄存器地址+数据长度+CRC校验码,反馈指令的格式一般包括从站地址+功能码+数据长度+从站数据+CRC校验码。具体的指令格式、寄存器地址、通信参数设置要参照各个设备的使用说明书。
如果觉得喜欢我的文章,请关注“工控实践课”微信公众号。