目录
Modbus
简介
Modbus对设备的控制是通过对一系列寄存器的读写完成的,是一种常用的串行通信协议,现在Modbus协议已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。
API说明
Modbus在luat lib没有对应的API封装,主要应用串口函数,对数据按照一定协议进行打包发送。
相应的串口API如下:
API接口 | 描述 |
---|---|
uart.on() | 注册串口的数据接收或发生函数 |
uart.setup() | 配置并且打开串口,可设置使用模块的串口ID号,波特率,数据位,奇偶校验位等 |
uart.write() | 向串口写字符串或者整型数据 |
uart.read() | 从串口读取字符串 |
uart.close() | 关闭uart对应接口 |
详细的API介绍见uart API章节
实现流程
- 注册使用对应的串口
- modbus通信协议封装
- modbus数据接收处理
- 启动任务循环发送数据
示例
相关实例程序在脚本库的demo\modbus文件夹下,包含modbus协议通信实例。可以根据实际需要选择demo进行测试研究。
Modbus发送消息
一条modbus报文,通常包含从机地址、功能码、数据地址、数据、CRC校验这几个数据结构,一个报文就是一帧数据,指的是一串完整的指令数据,如
从机地址 | 功能代码 | 数据地址 | 数据 | CRC校验 |
---|---|---|---|---|
8 位 | 8 位 | Nx8 位 | Nx8 位 | 16 位 |
01 | 06 | 00 01 | 00 17 | 98 04 |
通过pack.pack()对检验数据以十六进制格式进行打包,然后与前面数据结构中的数据进行拼接发送:
local function modbus_send(slaveaddr,Instructions,reg,value)
local data = (string.format("%02x",slaveaddr)..string.format("%02x",Instructions)..string.format("%04x",reg)..string.format("%04x",value)):fromHex()
local modbus_crc_data= pack.pack('<h', crypto.crc16("MODBUS",data))
local data_tx = data..modbus_crc_data
uart.write(uart_id,data_tx)
end
Modbus接收消息
此处代码演示使用串口1作为modbus协议通信接口,所以使用uart.read(uart_id,1)来读取串口1接收到的数据,并将数据转换为十六进制,对接收到的数据用户可以自己定义解析做功能扩展,在每次打印和处理完之后,通过cacheData = ""清空串口接收数据缓存。
local function modbus_read()
local cacheData = ""
while true do
local s = uart.read(uart_id,1)
if s == "" then
if not sys.waitUntil("UART_RECEIVE",35000/uart_baud) then
-- 3.5个字符的时间间隔,只是用在RTU模式下面,因为RTU模式没有开始符和结束符,
-- 两个数据包之间只能靠时间间隔来区分,Modbus定义在不同的波特率下,间隔时间是不一样的,
-- 所以就是3.5个字符的时间,波特率高,这个时间间隔就小,波特率低,这个时间间隔相应就大
-- 4800 = 7.297ms
-- 9600 = 3.646ms
-- 19200 = 1.771ms
-- 38400 = 0.885ms
--uart接收数据,如果 35000/uart_baud 毫秒没有收到数据,则打印出来所有已收到的数据,清空数据缓冲区,等待下次数据接收
--注意:
--因为在整个GSM模块软件系统中,软件定时器的精确性无法保证,例如本demo配置的是100毫秒,在系统繁忙时,实际延时可能远远超过100毫秒,达到200毫秒、300毫秒、400毫秒等
--设置的延时时间越短,误差越大
if cacheData:len()>0 then
local a,_ = string.toHex(cacheData)
log.info("modbus接收数据:",a)
--用户逻辑处理代码
--
cacheData = ""
end
end
else
cacheData = cacheData..s
end
end
end
Modbus循环消息发送测试
注册一个任务sys.taskInit(),每隔5S钟由modbus_send()函数向串口发送数据
sys.taskInit(function ()
while true do
sys.wait(5000)
modbus_send("0x01","0x01","0x0101","0x04")
end
end)
常见问题
字符数组的CRC校验值怎么转换成16进制数据的的CRC校验值?
答:https://doc.openluat.com/question_detail/225。
相关资料以及购买链接
相关开发板购买链接
Air724UG开发板
Air724 开发板使用说明
来自转载:https://doc.openluat.com/wiki/21?wiki_page_id=2362