零门槛实现 RS485 Modbus 主从机多点组网通信

96 篇文章 0 订阅
66 篇文章 0 订阅

RS485 Modbus 从机通信

本教程参考 FlexLua 官网 ShineBlink 开发板栏目,FlexLua技术可降低 IoT 硬件开发难度,零门槛开发 IoT 硬件。

简介:

下文介绍了如何用 ShineBlink C1 或 C2 开发板作为设备端(Modbus从机)来和上位机 (Modbus 主机) 来通信,并在 ShineBlink 设备端实现了 0x03 功能码(读取多个保持寄存器)和 0x05 功能码(写单个线圈)的程序代码。

一、实现环境

ShineBlink C1 或 C2 开发板设备作为Modbus从机通过RS485总线和上位机通信,我们在电脑上运行知名的Modbus Poll调试软件作为上位机来模拟Modbus主机,Modbus Poll软件可以到其官网上下载。

二、接线图

d1f0292e456b608fd0bb00d6c21d474f.jpeg

三、Modbus从机设备介绍

ShineBlink C1 或 C2 开发板设备作为Modbus网络中的其中一个节点有如下特性:

串口属性:19200、N、8、1

设备地址:21(0x15)

设备支持的Modbus功能码:

  • 0x05 写单个线圈
  • 0x03 读取多个保持寄存器

功能介绍:

  • 0x05,上位机通过向设备发送0x05功能码,对线圈地址为0x0000的线圈写入值0xFF00时,设备开始运行,
  • 对线圈地址为0x0000的线圈写入值0x0000时,设备停止运行。
  • 0x03,上位机通过向设备发送0x03功能码,读取保持寄存器起始地址为0x0000的9个保持寄存器(每个保持寄存器值为16bit无符号数据

三、Modbus通信实现代码实例

以下代码不仅实现了03和05功能码,并实现了将各种异常情况回复给Modbus主机。

--程序中用到的全局变量定义
Pm25Percent = 0
HchoPercent = 0
TvocPercent = 0
MeshPercent = 0.0
Temprature1 = 0.00
Temprature2 = 0.00
Wind485DisSpeed = 0
DevIsRunning = 0 --控制设备运行或停止
FaultCode = 0 --故障代码

--ModBus通信函数定义
function ModbusProcess()
local sdata = {}

--查询是否收到Modbus主机发来的消息
flag, data = LIB_Uart1Recv()
if flag == 1 then
--判断消息是不是发给本机,是本机的才理会
if data[1] == PI[2] then --PI[2], Modbus本机地址(1-247)
--判断Modbus功能码
if data[2] == 0x05 then -- 0x05 写单个线圈
--这里定义线圈地址为0x0000的线圈为开机/关机控制信号
if data[3] == 0x00 and data[4] == 0x00 then
if data[5] == 0xff and data[6] == 0x00 then --ON
DevIsRunning = 1 --置1开机全局变量
elseif data[5] == 0x00 and data[6] == 0x00 then --OFF
DevIsRunning = 0 --置0开机全局变量
else
--这里需回复非法数据03异常消息(非法数据值),读者可自行完成
end
--回复OK,把收到的数据原封不动回传
LIB_Uart1BlockSend(data)
else
--回复异常消息(非法数据地址)
sdata[1] = data[1] --本机地址
sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
sdata[3] = 0x02 --异常码0x02表示设备不支持此数据地址
CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
sdata[4] = CRC & 0x00ff --低位在前
sdata[5] = CRC >> 8 --高位在后
LIB_Uart1BlockSend(sdata)
end
elseif data[2] == 0x03 then --0x03 读多个保持寄存器
--这里定义起始地址为0x0000的这些寄存器存放传感器数据,且读取的寄存器个数必须是9个
if data[3] == 0x00 and data[4] == 0x00 and data[5] == 0x00 and data[6] == 0x09 then
sdata[1] = data[1] --本机地址
sdata[2] = data[2] --功能码
sdata[3] = 18 --数据域字节数: 9个寄存器一共18字节
sdata[4] = Pm25Percent >> 8
sdata[5] = Pm25Percent & 0x00ff
sdata[6] = HchoPercent >> 8
sdata[7] = HchoPercent & 0x00ff
sdata[8] = TvocPercent >> 8
sdata[9] = TvocPercent & 0x00ff
sdata[10] = math.floor(MeshPercent) >> 8
sdata[11] = math.floor(MeshPercent) & 0x00ff
sdata[12] = math.floor(Temprature1) >> 8
sdata[13] = math.floor(Temprature1) & 0x00ff
sdata[14] = math.floor(Temprature2) >> 8
sdata[15] = math.floor(Temprature2) & 0x00ff
sdata[16] = Wind485DisSpeed >> 8
sdata[17] = Wind485DisSpeed & 0x00ff
sdata[18] = DevIsRunning >> 8
sdata[19] = DevIsRunning & 0x00ff
sdata[20] = FaultCode >> 8
sdata[21] = FaultCode & 0x00ff
CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
sdata[22] = CRC & 0x00ff --低位在前
sdata[23] = CRC >> 8 --高位在后
--回复传感器数据
LIB_Uart1BlockSend(sdata)
else
--回复异常消息(非法数据地址)
sdata[1] = data[1] --本机地址
sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
sdata[3] = 0x02 --异常码0x02表示设备不支持此数据地址
CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
sdata[4] = CRC & 0x00ff --低位在前
sdata[5] = CRC >> 8 --高位在后
LIB_Uart1BlockSend(sdata)
end
else
--回复异常消息(非法功能码)
sdata[1] = data[1] --本机地址
sdata[2] = data[2]+0x80 --异常的时候功能码加0x80
sdata[3] = 0x01 --异常码0x01表示设备不支持此功能码
CRC = LIB_CrcCalculate("CRC16_MODBUS", sdata)
sdata[4] = CRC & 0x00ff --低位在前
sdata[5] = CRC >> 8 --高位在后
LIB_Uart1BlockSend(sdata)
end
end
end
end

--配置Uart1作为485接口,初始默认波特率19200,并且D6作为自动收发切换引脚
LIB_Uart1Rs485Config("BAUDRATE_19200","D6")

--开始大循环
while(GC(1) == true)
do
--Modbus通信处理
ModbusProcess()
end


四、Modbus Poll 上位机实验流程

(1)配置0x03读取保持寄存器功能(Setup)

26935e08515cb1152ba7db15a9bdaa23.jpeg

(2)建立Modbus串行通信连接(Connectiong)

8ad0e860415ab9e6f8e7423e80b8cfa6.jpeg

(3)建立连接后的数据通信

1. 上位机每秒钟自动下发0x03指令读取设备的起始地址为0x0000的9个保持寄存器的值

50d79b5352aae23cd34f72ddeef7d797.jpeg

通信数据日志:

119dcf760a30b14dffeb68b4c572f67f.jpeg

上面设备回复的23个字节数据举例说明:

例如:15 03 12 <u>00 06</u> <u>00 00</u> <u>00 01</u> <u>00 00</u> <u>00 16</u> <u>00 16</u> <u>00 00</u> <u>00 00</u> <u>00 00</u> D5 16

数据结尾的CRC算法采用Modbus Crc16

本机地址:0x15
功能码:0x03
字节数:18字节(9个16bit无符号寄存器)
寄存器1:0x0006 表示pm25=6
寄存器2:0x0000 表示hch0=0
寄存器3:0x0001 表示tvoc=1
寄存器4:0x0000 表示mesh=6
寄存器5:0x0016 表示temprature1=21度
寄存器6:0x0016 表示temprature2=21度
寄存器7:0x0000 表示windspeed=0
寄存器8:0x0000 表示running=0
寄存器9:0x0000 表示faultcode=0
CRC_L:0xD5
CRC_H:0x16

2. 上位机下发开机命令(功能码0x05,向线圈地址为0x0000处写单个线圈值0xFF00)

bd2ce78891ca588dcc9265dce3e7f605.jpeg

通信数据日志:

44f08f68ac07b259906c834e444b023d.jpeg

3. 上位机下发停机命令(功能码0x05, 向线圈地址为0x0000处写单个线圈值0x0000)

上位机发送: 15 05 00 00 00 00 CE DE
设备应回复: 15 05 00 00 00 00 CE DE

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值