跳到主要内容

RS485 Modbus主机案例(繁版)

前言

本教程以读取一个支持 Modbus-RTU 协议的 RS485 温湿度传感器为例,演示了 RS485 Modbus-RTU 主机通信(繁版)实现的几个相关主要函数的使用方法:

LIB_Uart1Rs485Config("BAUDRATE_4800","D6") --RS485初始化
LIB_MbRtuMasterSendTrans("03", 0x01, 0x0000, 2) --Modbus发送内容解析
LIB_Uart1BlockSend(ModbusSendTab) --发送
LIB_Uart1Recv() --接收
LIB_MbRtuMasterRecvTrans(MbFuncCode,recv_tab) --Modbus接收内容解析

一、本例程实现功能

通过 03 功能码(读保持寄存器)每隔1秒读取一个市面上常见的 RS485 温湿度传感器(例如:建大仁科的)的温度值和湿度值:

  • 从机地址:0x01

  • 湿度值寄存器地址:0x0000(16bit 整数,扩大十倍)

  • 温度值寄存器地址:0x0001(16bit 整数,扩大十倍)

  • RS485通信参数:4800,N,8,1

最后将读取到的温湿度值在 log.txt 中 print 打印出来。

wsd

product0

product1

二、接线图

layout3

三、源码

--配置Uart1作为485接口,初始默认波特率4800,并且D6作为自动收发切换引脚
LIB_Uart1Rs485Config("BAUDRATE_4800","D6")
--使能系统10毫秒定时器开始工作
LIB_10msTimerConfig("ENABLE")

--全局变量
MbDelayMs = 0
WorkMs = 0
temp = 0.0 --温度
humi = 0.0 --湿度

--定义10毫秒定时器的回调函数,函数名字必须是LIB_10msTimerCallback
function LIB_10msTimerCallback()
MbDelayMs = MbDelayMs + 10
WorkMs = WorkMs + 10
end

--进入大循环
while(GC(1) == true)
do
--每隔1秒(1000ms)读取一次传感器的值
if WorkMs >= 1000 then
WorkMs = 0
print("Start")
--转换出需要下发的Modbus格式数据(功能码03,读取地址为0x01的温湿度传感器的0x0000和0x0001寄存器)
ModbusSendTab = LIB_MbRtuMasterSendTrans("03", 0x01, 0x0000, 2)
--log.txt中打印ModbusSendTab数据
print("Tx:"..LIB_HexTabToHexStr(ModbusSendTab))
--通过RS485串口下发Modbus格式数据
LIB_Uart1BlockSend(ModbusSendTab)
MbDelayMs = 0
Finish = 0
--等待传感器回应,最多等500毫秒
while MbDelayMs < 500 and Finish == 0 do
--判断是否收到modbus应答数据
recv_flag,recv_tab = LIB_Uart1Recv()
if recv_flag == 1 then
Finish = 1
--解析Modbus从机(温湿度传感器)发来的应答数据
result,r = LIB_MbRtuMasterRecvTrans("03", recv_tab)
--log.txt中打印Modbus收到的数据
print("Rx:"..LIB_HexTabToHexStr(recv_tab))
--Modbus通信正确
if result > 0 then
humi = r[1] * 0.1 --湿度值,湿度值寄存器地址:0x0000(16bit整数,扩大十倍)
temp = r[2] * 0.1 --温度值,温度值寄存器地址:0x0001(16bit整数,扩大十倍)
print(string.format("humi = %.1f, temp = %.1f", humi, temp)) --打印温湿度值结果
--Modbus通信出错
else
err_code = -128 - result
--记录错误日志
print(string.format("modbus ack err=%d, data=%s",err_code, LIB_HexTabToHexStr(recv_tab)))
end
end
end
--Modbus通信超时
if Finish == 0 then
--记录错误日志
print("modbus poll timeout")
end
end -- if WorkMs >= 1000 then
end
如果感兴趣,上面代码中出现的LIB开头的库函数可以在 API文档 中通过Ctrl+F查询。

四、实验结果

代码运行一段时间后,打开 log.txt 文件可以看到运行过程中 print() 打印输出的日志信息如下图:

result_m