查看: 1059|回复: 0

UIFLOW ModbusMaster介绍及实例测试

[复制链接]

该用户从未签到

发表于 2021-8-20 18:36 | 显示全部楼层 |阅读模式
本帖最后由 MASH1R0 于 2021-8-23 16:49 编辑

UIFLOW Modbus Master

1.Modbus Rtu和RS-485

简介
MODBUS是一种串行的通信协议,是工业电子设备之间常用的连接方式。modbus协议包括modbus RTU、modbus ASCII和modbus TCP,其中以为modbusRTU的成本低于modbustcp和传输效率高于modbusASCII使其更为常用。Modbus是一种通信协议,相当于只是约定好了收发两端通信的格式,实现数据的传输还需要传输的媒介。RS485采用半双工工作方式,支持多点数据通信。传输距离长、多节点和传输线成本低,多优点集于一身的rs485在自动化领域应用广泛,所以软件协议的modbusRTU也经常和硬件总线的rs485搭配在一起使用。

ModbusRTU协议

地址区
功能码
数据
CRC16
1字节(8位)
1字节(8位)
N字节(N×8位)
2字节(16位)

(1)地址区:
信息帧的地址区在帧开的始部分,由8位组成,主机把从机地址放入信息帧的地址区,并向从机寻址。从机响应时,把自己的地址放入响应信息的地址区,让主机识别已作出响应的从机地址。地址0为广播地址,所有从机均能识别。当Modbus协议用于高级网络时,则不允许广播或其它方式替代。

(2)功能码:
代码
名称
功能
0x01
读取线圈状态
读取一路或多路线圈的开闭状态
0x02
读取输入状态
读取一路或多路线圈当前的输入状态
0x03
读取保持寄存器
读取一个或多个保持寄存器(可读写)中的数据
0x04
读取输入寄存器
读取一个或多个输入寄存器(只读)中的数据
0x05
写单个线圈
强制单个线圈的开闭状态
0x06
写单个保持寄存器
把一个值预置到一个保持寄存器中
0x0f
写多个线圈
按线圈的顺序强制各线圈开闭状态
0x10
写多个保持寄存器
把数据按顺序预置到各寄存器中


(3)数据:
根据功能码的不同,在数据区填入的数据也会不同。(以从机17(0x11)为例)

0x01和0x02:
从机id
功能
数据
CRC16
0x11
0x01
0x02
起始地址
高位
起始地址
低位
读取个数
高位
读取个数
低位
CRC
高位
CRC
低位
例:主机 0x11 0x01 0x00 0x00 0x00 0x06 + CRC16(Hi) + CRC16(Lo)
       从机 0x11 0x01 0x01 0x1a + CRC16(Hi) + CRC(Lo)

“指令为从00开始读6个线圈的状态,从机返回的0x01表示返回的数据位为1字节,0x2a转换为2进制为00011010,表示01和03和04处的状态为1”

0x03和0x04:
从机id
功能
数据
CRC16
0x11
0x03
0x04
寄存器起始地址高位
寄存器起始地址低位
读取寄存器
高位
读取寄存器
低位
CRC
高位
CRC
低位
例:主机 0x11 0x03 0x00 0x02 0x00 0x03 + CRC16(Hi) + CRC16(Lo)
       从机 0x11 0x03 0x06 0x0A 0x01 0x0A 0x02 0x0A 0X03 +CRC16(Hi) + CRC16(Lo)

“指令为从寄存器0002开始读3个寄存器中的数据,从从机返回的报文中可以看到返回了6(0x06)个字节的数据,其中0002中的数据为0A01,0003的是0A02,0004的是0A03”

03和04的报文的格式相同,但面向的寄存器不同。(保持寄存器可读写,输入寄存器只读)

0x05:
从机id
功能
数据
CRC16
0x11
0x05
线圈地址
高位
线圈地址
低位
写入状态
高位
写入状态
低位
CRC
高位
CRC
低位
例:主机 0x11 0x05 0x00 0x02 0xFF 0x00 + CRC16(Hi) + CRC16(Lo)
       从机 与主机报文一致
“指令为闭合02线圈,主从报文格式一致,从机在响应后发送报文”
0xFF00为闭合指令0x0000为开指令

0x06:

从机id
功能
数据
CRC16
0x11
0x06
寄存器地址
高位
寄存器地址
低位
写入数据
高位
写入数据
低位
CRC
高位
CRC
低位
例:主机 0x11 0x06 0x00 0x01 0x0A 0x00 + CRC16(Hi) + CRC16(Lo)
       从机 与主机报文一致
“指令为写入0A00到0001寄存器中”

0x0f:
例:
从机ID
功能
线圈开始地址
线圈个数
写入字节数
写入的数据
CRC16
0x11
0x0f
0x00 0x01
0x00 0x09
0x02
0x68 0x01
“指令为从线圈01开始写9个线圈状态,0x68(0110 1000)表示将04、06、07线圈置1,0x01(0000 0001)表示将09置1”
0x10:例:
从机ID
功能
寄存器地址
寄存器个数
写入字节数
写入的数据
CRC16
0x11
0x10
0x00 0x01
0x00 0x02
0x04
0x00 0xAA 0x00 0xBB
“指令为向0001和0002寄存器分别写入0x00AA和0x00BB”


(4)CRC校验:
在数据传输的过程中有时会因为噪声或其他干扰的影响而发生错误,将主机要发送的数据后面加上CRC校验,从机接收到数据后将数据再进行一次CRC校验,将得出的结果与接收到数据的后两位CRC校验位相比,若计算结果与接收结果相同则证明数据正确,反之则舍弃这次数据。

2.UIFLOW Modbus Master API
READ:
.读取1路或多路线圈状态(01)
01.png
参数:

slave address(从机地址)
starting address(线圈起始地址)
coil qty(线圈个数)

.读取一路或多路线圈输入状态(02)
02.png
参数:

slave address (从机地址)
starting address(输入起始地址)
input qty(输入个数)

.读取保持寄存器(03)
03.png
参数:

slave address(从机地址)
starting address(保持寄存器起始地址)
register qty(寄存器个数)
signed(接收的数据是否有符号位)

.读取输入寄存器(04)
04.png
参数:

slave address(从机地址)
starting address(输入寄存器起始地址)
register qty(寄存器个数)
signed(接收的数据是否有符号)

WRITE:
.写单个线圈状态(05)
05.png
参数:

slave address(从机地址)
output address(线圈地址)
output value(线圈状态)

.写单个寄存器状态(06)
06.png
参数:

slave address(从机地址)
register address(寄存器地址)
register value(写入内容)
signed(是否有符号)

.写多个线圈状态(0f)
0f.png
参数:

slave address(从机地址)
starting address(线圈起始地址)
output value(线圈状态)
Tips:可用数组设定多个线圈的状态。

.写多个寄存器状态(10)
10.png
参数:

slave address(从机地址)
starting address(线圈起始地址)
register value(写入内容)
Tips:可用数组设定多个寄存器中的内容。

以上函数会完成发送和接收两个步骤,在接收到从机的报文后将数据(不包括从机地址、功能码、字节数和CRC校验位)作为函数的返回值。


3.应用实例

8路485开关量采集模块
硬件:开关量采集模块、M5STACK(主控)、M5-UNIT-485(串口转485模块)

代码:
8in.png
配置串口后,在循环中调用modbus库中02功能(Read discrete inputs)的API,默认从机地址为1,起始输入地址为0,往后读8个输入,将返回值写入“READ”中。

8IN1.png

8IN2.png

8IN3.png
模拟量转485模块:
硬件:模拟量转485模块(0-5v/4-20mA)、M5STACK(主控)、M5-UNIT-RS485 (串口转485模块)
代码:
ADC.png
初始化串口后,在循环中调用03功能(Read holding registers)的api。查看模块说明书,两个模拟量输入转换的数据保存在0x0000和0x0001中,将起始地址设为0x0000,读取的寄存器个数为2,完成读取报文的设定。模块返回的值被保存到“READ”中,其第一第二个元素分别对应IN0、IN1的数据。

0-5V模拟量转换

V1.png
1.3V
读数:IN1:1066

V2.png
2.7V
读数:IN1:2215

V3.png
3.5V
读数:IN1:2870

4-20mA模拟量转换


I1.png
8mA
读数:1204

I2.png
14mA
读数:2177

I3.png
18mA
读数:2770

2路485继电器模块:
硬件:2路485继电器模块、M5STACK(主控)、M5-UNIT-RS485(串口转485模块)

代码:
2RELAY.png
设置好串口后就可以开始进行modbus通信了,该继电器模块中继电器1的地址为0,继电器2的地址为1,控制线圈闭合即打开继电器只需向其地址输入0xFF00,反之则输入0x0000。为展示功能码01和0f的用法,将两继电器状态按下表设定,可根据实际情况选用合适的功能码。

STATE
RELAY1
RELAY2
0
0
0
1
0
1
2
1
1
3
1
0

RELAY1.png
状态1


RELAY2.png
状态2


RELAY3.png
状态3

4.UIFLOW MODBUS MASTER测试

8IN_TEST.png
8路485开关量采集模块

ADC_TEST.png
模拟量转485模块

2RELAY_TEST.png
2路485继电器模块

TEST.png
更新频率:
将函数执行前后时间记录下来后,用串口打印出时间的间隔,各个模块均采样了180次。

更新时间与主机从机的响应都有关系,从图表中可以看出这几个实例中的更新时间是比较稳定的。ADC(I)和ADC(V)的实例中采用同一份代码,在两个从机不同的情况下仍然保持相近的更新频率;在485继电器实例中有意用0x05的功能码和0X0F功能码分开处理两个继电器。可以发现在处理多个线圈或寄存器时,两个0x05功能码的效率是远远不及一个0x0F功能码的高,在处理多个线圈或寄存器时应优先考虑0x0F和0x10功能。

稳定性:

在采集数据的过程及其之后的时间内均没有因“CRC错误”或“接收不到从机报文”而使得代码无法运行的情况。

5.总结
UIFLOW的modbus库稳定性和实时性均能满足大部分需求,按照常用的功能码进行分类,只需了解基础的modbus原理便能灵活应用。UIFLOW直观、简洁和便利,无论是用于做测试或做工程均能有效缩短研发周期提升效率。






您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

热门推荐

Arduino数字与字母字体应该如何设置?
Arduino数字与字母字体应
尝试用Arduino uno 做了个小工具,用来控制电脑水冷的运行。 洞洞板已经测试成功,完
WEMOS LOLIN32Lite(ESP32v1.0.0Rev1)入手+引脚图
WEMOS LOLIN32Lite(ESP32v
突发奇想做个精致的蓝牙遥控平衡小车(大学时做过一次,比较笨,用洞洞板焊电路做的比
【Arduino】168种传感器模块系列实验(129)---BH1750光照传感器
【Arduino】168种传感器模
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是
16度双足机器人舵机驱动板pca9685连接舵机,舵机没反应
16度双足机器人舵机驱动板
各位同为arduino爱好者的大佬们大家好!想请教一下大家有关舵机驱动板pca9685
pca9685+arduino驱动舵机失败
pca9685+arduino驱动舵机
我网上别人的代码,编译通过且上传,但舵机不转,怎么解决?Arduino uno使用PCA9685模
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
快速回复 返回顶部 返回列表