iRTU开源项目是iRTU开源模组的核心部分,它是iRTU硬件产品的灵魂。我们该做的就是怎么把这个开源项目利用好,让他发挥出应有的价值。在前几篇的文章里,我讲述了如何使用手机客户端和PC客户端通过UPWs服务器向iRTU控制器发送透传指令。 今天这篇文章是上两篇文章的一个实际应用,在本文中,我将介绍将iRTU与市面上的一款Modbus继电器相连实现远程开关继电器的功能。
Modbus简介
Modbus是由Modicon(现为施耐德电气公司的一个品牌)在1979年发明的,是全球第一个真正用于工业现场的总线协议。 直到如今,Modbus在各个工业场合依然被广泛采用,下面简单的介绍一下Modbus的报文格式
Modbus对设备的控制是通过对一系列寄存器的读写完成的。 设备地址是一个8bit的字节,规定了总线上要进行通讯的设备地址,最多可以有247个设备,地址为0的时候为广播地址,所有设备都应该进行解析,248-255是供用户扩展之用。 功能代码是具体执行的功能,数据部分是可变长度的整字节数据,报文尾部有一个双8Bit的CRC校验位。 当通讯命令发送至仪器时,符合相应地址码的设备接通讯命令,并除去地址码,读取信息,如果没有出错,则执行相应的任务;然后把执行结果返送给发送者。返送的信息中包括地址码、执行动作的功能码、执行动作后结果的数据以及错误校验码。如果出错就返回任何信息。
下面以我购得的一个具有4路输出的Modbus继电器模块所采用的通讯报文
--下行报文 (iRTU->Modbus继电器)
01 05 00 00 FF 00 98 35
01->地址码,购买的设备默认起始为01,模块上有一个5位的拨码开关,通过调节增加地址,比如 ON|OFF|OFF|OFF|OFF的地位为02
05->功能码,控制打开继电器
00 00->寄存器起始位,00 00 代表第一个继电器, 00 01 代表第二个, 00 10 代表第三个,0011 代表第四个
98 35->CRC16校验和
--上行报文 (Modbus->iRTU)
FE 05 00 00 FF 00 98 35
返回内容与发送内容相同,证明执行成功,如果执行不成功,则没有返回
##电路连接方式
本次试验电路测试中采用了合宙生态企业深圳飞思创生产的DTU400-485 4G三模iRTU,不久前商家搞活动促销以99元购得。
该DTU终端内部采用合宙出品的Air720G全网通4G模块,功能与合宙出品的4G DTU大板基本相同,但额外外置一个5-36V的电源输入接口,使用起来非常方便。
下图是本次实验用到的物料
DTU400-485 X1
CS-IO404 Modbus继电器 X1
USB转RS485转接头 X1
电话线 1盘
导线 X 4
下面是连线方式,其中RS485转换头和传输线仅供配置用,配置完成后可以移除。
##实现方法
第一步:按照上图将电路连接完成,完成后如下图所示效果
第二步:编写上下行数据流模板
下行数据流模板(DTU->Modbus继电器),该模板用于将手机发送的继电器控制指令翻译为Modbus继电器的控制报文。
--Download steam
function
local str=...
--从MTCP协议中拆出命令
local dat=str:sub(40,-3)
local ret=""
--判断发送的指令,是否与预置指令一致,如果一致则下发响应的Modbus命令
if (dat:sub(1,8)=="relay1on") then
--Modbus地址 01,命令:控制继电器 05,第一个继电器 0000,动作:打开 FF00 ,校验和 8C3A
ret= string.fromHex("01 05 00 00 FF 00 8C 3A")
elseif (dat:sub(1,8)=="relay2on") then
ret= string.fromHex("01 05 00 01 FF 00 DD FA")
elseif (dat:sub(1,8)=="relay3on") then
ret= string.fromHex("01 05 00 02 FF 00 6D FB")
elseif (dat:sub(1,8)=="relay4on") then
ret= string.fromHex("01 05 00 03 FF 00 3C 3B")
elseif (dat:sub(1,9)=="relay1off") then
--Modbus地址 01,命令:控制继电器 05,第一个继电器 0000,动作:关闭 0000 ,校验和 CDCA
ret= string.fromHex("01 05 00 00 00 00 CD CA")
elseif (dat:sub(1,9)=="relay2on") then
ret= string.fromHex("01 05 00 01 00 00 9C 0A")
elseif (dat:sub(1,9)=="relay2on") then
ret= string.fromHex("01 05 00 02 00 00 6C 0A")
elseif (dat:sub(1,9)=="relay2on") then
ret= string.fromHex("01 05 00 03 00 00 3D CA")
else
ret =dat
end
return ret
end
上行数据流模板(Modbus继电器->DTU),该模板用于将Modbus继电器返回的报文翻译成手机的回报信息。
--Upload stream
function
local a=...
local ret=""
local str=""
--判断报文是否为继电器状态返回
if (a:sub(1,2)==string.fromHex("01 05")) then
--第4位是继电器编号
local relayNO=a:sub(4,4):byte()
--第5位是继电器状态,0为关闭 255是打开
local relayStatus=a:sub(5,5):byte()
local no=tostring(relayNO,10)
local stat
if (relayStatus==255) then stat="ON" else stat="OFF" end
str="Relay NO.:"..no.." Status is:"..stat
else
str=string.toHex(a, " ")
end
local totallen=41+str:len()
local ret=string.format("%04d",totallen).."01".."C".."01".."0000000001".."0000000000000001".."1234"..str.."05"
return ret
end
第三步:配置iRTU
将编写好的上下行数据流模板和Upws服务器参数通过串口工具配置到DTU
服务器设置:
1) 配置iRTU为UDP传输模式,服务器地址为 box.miuser.net,DPU端口为7101
2) 每隔10S发送一次心跳包,心跳包的内容为 005501B01000000000100000000000000011234iRTUUPWs 1.0.000
3) 使用数据通道1通过数据模板进行透传,并绑定到到iRTU串口1
4) 串口1 波特率设置为9600bps,停止位1,奇偶校验无
第四步,打开LLCCOM调试工具,将以上配置信息通过串口工具写入iRTU
config,writeconfig,{"fota":0,"uartReadTime":"25","flow":"","param_ver":"1","pwrmod":"normal","password":"","netReadTime":"300","passon":1,"nolog":"0","plate":0,"reg":0,"convert":0,"uconf":[[1,"9600",8,2,0,""],[2,"115200",8,2,0,""]],"conf":[["udp","005501B01000000000100000000000000011234iRTUUPWs 1.0.000",10,"box.miuser.net",7101,1,"","",""],[],[],[],[],[],[]],"preset":{"number":"","delay":"","smsword":""},"apn":["","",""],"cmds":[[],[]],"pins":[],"gps":{"pio":[],"fun":[]},"upprot":["--Upload stream\nfunction \n\n local a=...\n\n local ret=\"\"\n local str=\"\"\n\n if (a:sub(1,2)==string.fromHex(\"01 05\")) then \n local relayNO=a:sub(4,4):byte() \n local relayStatus=a:sub(5,5):byte()\n local no=tostring(relayNO,10)\n local stat\n if (relayStatus==255) then stat=\"ON\" else stat=\"OFF\" end \n str=\"Relay NO.:\"..no..\" Status is:\"..stat \n else\n str=string.toHex(a, \" \")\n end\n\n local totallen=41+str:len()\n local ret=string.format(\"%04d\",totallen)..\"01\"..\"C\"..\"01\"..\"0000000001\"..\"0000000000000001\"..\"1234\"..str..\"05\"\n\n return ret\n \nend ","","","","","",""],"dwprot":["--Download steam\nfunction\n\n local str=...\n local dat=str:sub(40,-3)\n local ret=\"\"\n if (dat:sub(1,8)==\"relay1on\") then\n ret= string.fromHex(\"01 05 00 00 FF 00 8C 3A\")\n elseif (dat:sub(1,8)==\"relay2on\") then\n ret= string.fromHex(\"01 05 00 01 FF 00 DD FA\")\n elseif (dat:sub(1,8)==\"relay3on\") then\n ret= string.fromHex(\"01 05 00 02 FF 00 6D FB\")\n elseif (dat:sub(1,8)==\"relay4on\") then\n ret= string.fromHex(\"01 05 00 03 FF 00 3C 3B\")\n\n elseif (dat:sub(1,9)==\"relay1off\") then\n ret= string.fromHex(\"01 05 00 00 00 00 CD CA\")\n elseif (dat:sub(1,9)==\"relay2on\") then\n ret= string.fromHex(\"01 05 00 01 00 00 9C 0A\")\n elseif (dat:sub(1,9)==\"relay2on\") then\n ret= string.fromHex(\"01 05 00 02 00 00 6C 0A\")\n elseif (dat:sub(1,9)==\"relay2on\") then\n ret= string.fromHex(\"01 05 00 03 00 00 3D CA\")\n else \n ret =dat\n end\n\n return ret\n\nend","","","","","",""],"warn":{"adc0":[],"adc1":[],"vbatt":[],"gpio":[]} }
默认串口速率为115200,打开LLC,把以上内容粘贴到发送框里,点击发送,即可。
第五步,通过扫描二维码,对继电器进行控制。在命令行里输入relay1on,可以看到继电器被打开。再输入relay1off,可以看到继电器被关闭。
第六步,最终效果
网络继电器的用途很广,现代农业里面的浇水施肥,基本上都是靠这个来控制的,不到两百块钱就可以控制220V水泵给自己家的地远程浇水了! 您看过本文以后是不是心动了呢,那就赶快行动吧。 下一篇文章,我们将尝试使用同样的原理通过另一款温度传感器采集环境温湿度信息。
参考资料
本文所提及的文档及工具资料包:
https://pan.baidu.com/s/15QICk163bI5NCB8M0SSDpA 提取码:a610
本文参考资料如下:
1 iRTU项目开源地址
https://github.com/hotdll/iRTU
2 UPWS项目开源地址
https://github.com/miuser00/UdpPlugWebsocket
3 LLC能跑Lua脚本的串口调试工具项目开源地址
https://github.com/chenxuuu/llcom
技术咨询方式
合宙Luat(稀饭放姜iRTU) QQ群:952343033