用几行Lua代码实现Modbus RS485和LoRa透传

122 阅读7分钟

用几行Lua代码实现Modbus RS485和LoRa透传

[TOC]

前言

Modbus RS485和LoRa透传的实现可以用 Lua 语言编程低代码实现,FlexLua 的可编程 DTU01 万能采集器同时具备 RS485接口和LoRa接口,所以用它再结合几行 Lua 代码即可实现透传。因为该采集器内置 Lua 编译器,开发者只需要将本文提供的代码文件烧录进该采集器即可运行。

Part1 透传描述

大致流程是:云端通过网关下发 Modbus Hex 字节流查询消息,Lora 子节点通过网关向云端返回 Modbus Hex 字节流响应消息。

show4

(1)Lora网络角色定义:

  • 《DTU02万能网关》 作为 Lora 中心点
  • 《DTU01万能采集器》 作为 Lora 子节点

(2)下行通道透传说明(Modbus查询):

下行HEX数据格式举例说明(01 02 55 AA 02 01 01 01 03 00 00 00 02 C4 0B):

RS485通信参数信息说明:例如当 5 -7 字节为 02 01 01时,表示需要 Lora子节点将其 RS485 接口设置为:波特率=9600,无校验,1位停止位。关于如何配置该值请参考《软件使用指导书(RS485_LORA_PASSIVE_HEX)》文档。

通信过程描述:

云端通过 以太网 下发一包 Hex 字节流消息,DTU02 Lora 中心点网关收到该消息后从该消息的前两个字节解析出需要转发的 Lora子节点地址,然后根据该地址通过Lora无线传输将后面的字节全部转发给对应的 DTU01 Lora 子节点,DTU01 Lora 子节点收到这些数据后,便可以通过RS485 Modbus读取相应传感器/仪器/设备的数据,并将数据原封不动返回给DTU02 Lora 中心点网关,具体流程举例如下:

--step1: 云端下发数据:01 02 55 AA 02 01 01 01 03 00 00 00 02 C4 0B,其中01 02 = 258,表示目标是地址=258的Lora子节点
--step2: 地址=258的Lora子节点将收到:55 AA 02 01 01 01 03 00 00 00 02 C4 0B
--step3: 55 AA 是固定值,02 01 01表示需要Lora子节点配置其RS485接口以<9600 N 1>参数通信
--step4: 随后Lora子节点将Modbus数据01 03 00 00 00 02 C4 0B通过RS485发送给相应的RS485设备以读取传感器/仪器/设备的s数据

云端 -> 以太网 -> Lora中心点网关 -> Lora子节点 -> RS485 Modbus

(3)上行通道透传说明(Modbus响应):

上行HEX数据格式举例说明(01 02 01 03 04 01 E6 FF 9F 1B A0):

通信过程描述:

由上面的内容可知,DTU01 Lora 子节点通过RS485 Modbus读取到相应传感器/仪器/设备的Modbus响应数据后,会将该数据原封不动转发给DTU02 Lora 中心点网关,然后Lora中心点网关在该数据的基础上在前端插入两个字节的Lora子地址后,便将该数据通过以太网接口转发给云端,具体流程举例如下:

--step1: Lora 子节点通过RS485 Modbus获取到: 01 03 04 01 E6 FF 9F 1B A0 (Modbus响应数据)
--step2: 然后再将该数据原封不动发送给Lora中心点网关
--step3: Lora中心点网关在该数据的基础上在前端插入两个字节的Lora子地址(比如258)得到:01 02 01 03 04 01 E6 FF 9F 1B A0
--step4: 随后Lora中心点网关将01 02 01 03 04 01 E6 FF 9F 1B A0通过以太网接口发送给云端

RS485 Modbus -> Lora子节点 -> Lora中心点网关 -> 以太网 -> 云端

Part2 源代码和硬件

----------------------配置信息----------------------
--Part1:Lora通信配置 
--本机Lora子节点地址(范围:1-65535),用户可设置
LoraAddr = 1
--Lora通信信道(范围:410-441MHz)
LoraChn = 433
--Lora无线速率(范围:0.3, 1.2, 4.8, 9.6, 19.2kpbs)
LoraDdr = "9.6kpbs"
--Lora发射功率(范围:11, 14, 17, 20dB)
LoraTxPwr = "22dB"
--只有NetID相同的lora主从机之间才可通信(范围:0-255),该参数在多个Lora星型网络共存时有用
LoraSubNetID = 0 
--等待RS485设备的最长应答时间,单位:毫秒
MbWaitTimeMs = 1000 

----------------------固定值----------------------
--UART相关信息
BdrMap = {"BAUDRATE_4800","BAUDRATE_9600","BAUDRATE_19200","BAUDRATE_38400","BAUDRATE_115200","BAUDRATE_230400","BAUDRATE_460800","BAUDRATE_921600"}--1~8
PrtyMap = {"NoneParity","EvenParity","OddParity"}--1~3
StpBtMap = {"StopBit_1","StopBit_1_5","StopBit_2"}--1~3


--LIB_SystemLogEnable()
--配置D0,D1,D3为普通GPIO输出,控制LED_R,LED_G,LED_B
LIB_GpioOutputConfig("D0","STANDARD")
LIB_GpioOutputConfig("D1","STANDARD")
LIB_GpioOutputConfig("D3","STANDARD")
LIB_GpioWrite("D0",1)
LIB_GpioWrite("D1",1)
LIB_GpioWrite("D3",1)
--配置D11为普通输出,控制看门狗 
LIB_GpioOutputConfig("D11","STANDARD")
--设置Lora模块占用TX0、RX0、Aux接D5引脚,Md0接D6引脚
--Lora通信参数:地址=1,通信信道=433M,无线速率=9.6kbps,发射功率=20dBm
LIB_LoraConfig("UART0","D5","D6",LoraAddr,LoraChn,LoraDdr,LoraTxPwr,LoraSubNetID)
--配置Uart1开始工作,并且D8引脚作为自动切换485收发芯片的引脚
--当用LIB_Uart1BlockSend发送时,D8会自动变成低电平,发送完后会立刻变成高电平
LIB_Uart1Rs485Config("BAUDRATE_9600","D8","NoneParity","StopBit_1")
--使能系统10毫秒定时器开始工作
LIB_10msTimerConfig("ENABLE")
LED_G_OnTimeMsCnt = 0
LED_R_OnTimeMsCnt = 0 
DelayTimeMs = 0

--定义10毫秒定时器的回调函数,函数名字必须是LIB_10msTimerCallback
function LIB_10msTimerCallback()
	LIB_GpioToggle("D11") --喂硬件看门狗
	--绿色LED灯处理程序
	if LED_G_OnTimeMsCnt >= 10 then
		LED_G_OnTimeMsCnt = LED_G_OnTimeMsCnt - 10
		LIB_GpioWrite("D1",0) --亮
	else
		LIB_GpioWrite("D1",1) --灭
	end
	--红LED灯处理程序
	if LED_R_OnTimeMsCnt >= 10 then
		LED_R_OnTimeMsCnt = LED_R_OnTimeMsCnt - 10
		LIB_GpioWrite("D0",0) --亮
	else
		LIB_GpioWrite("D0",1) --灭
	end
	DelayTimeMs = DelayTimeMs + 10
end

--开始大循环
while(GC(1) == true)
do
    --查询是否收到Lora中心点发来的无线数据
    lora_flag,lora_addr,lora_data = LIB_LoraRecv()
    if lora_flag == 1 then
		--绿灯闪0.1秒
		LED_G_OnTimeMsCnt = 100
		--调试打印收到的Lora Hex数据
		print("Recv(Lora):"..LIB_HexTabToHexStr(lora_data))
		--提取出前5字节包含的baudrate、校验、停止位配置信息
		if lora_data[1] == 0x55 and lora_data[2] == 0xaa and #lora_data > 5 then
			--解析Uart参数:波特率,1~8
			BdrSel = lora_data[3]
			if BdrSel < 1 or BdrSel > 8 then
				Baudrate = BdrMap[2]--9600bps
			else
				Baudrate = BdrMap[BdrSel]
			end
			--解析Uart参数:校验方式,1~3
			PrtSel = lora_data[4]
			if PrtSel < 1 or PrtSel > 3 then
				Parity = PrtyMap[1]--NoneParity
			else
				Parity = PrtyMap[PrtSel]
			end
			--解析Uart参数:停止位,1~3
			StpSel = lora_data[5]
			if StpSel < 1 or StpSel > 3 then
				StopBit = StpBtMap[1]--StopBit_1
			else
				StopBit = StpBtMap[StpSel]
			end
			
			--将收到的Lora无线数据从第6个字节开始原封不动的通过RS485串口发出去
			--设置读取485传感器的波特率,校验方式,停止位
			LIB_Uart1SetParam(Baudrate, Parity, StopBit)
			SendTab = {}
			for i=6,#lora_data do
				SendTab[#SendTab+1] = lora_data[i]
			end
			LIB_Uart1BlockSend(SendTab)

			--最多等待DelayTimeMs毫秒的应答时间
			DelayTimeMs = 0
			while DelayTimeMs < MbWaitTimeMs do
				--判断是否收到485应答数据
				rs485_flag,rs485_tab = LIB_Uart1Recv()
				if rs485_flag == 1 then
					--红灯闪0.1秒
					LED_R_OnTimeMsCnt = 100
					--调试打印收到的串口Hex数据
					print("Recv(Rs485):"..LIB_HexTabToHexStr(rs485_tab))
					--将收到的485串口Hex数据原封不动的通过Lora发回去
					LIB_LoraSend(lora_addr, rs485_tab)
					DelayTimeMs = MbWaitTimeMs --即然收到Lora数据了就提前退出等待
				end
			end
			if rs485_flag ~= 1 then--通信超时
				print(string.format("None RS485 data response in %d ms!", MbWaitTimeMs))
			end
		end
    end
end