init: Air780EPM 官方 LuatOS 项目代码基线
- 来源: 合宙 LuatOS 官方仓库 air780epm 模块完整代码 - 路径: luatos/air780epm/module/Air780EPM/demo 含官方 demo(含 mqtt/mqtts/socket/uart 等) - 后续: 基于 demo 开发 UART<->MQTT 数据上报功能
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
--[[
|
||||
@module main
|
||||
@summary LuatOS 用户应用脚本文件入口,总体调度应用逻辑
|
||||
@version 1.0
|
||||
@date 2025.12.29
|
||||
@author 马梦阳
|
||||
@usage
|
||||
|
||||
本 demo 演示的核心功能为:
|
||||
1、将设备配置为 modbus RTU 从站模式
|
||||
2、等待并且应答主站请求
|
||||
|
||||
注意事项:
|
||||
1、该示例程序需要搭配 exmodbus 扩展库使用
|
||||
2、设备作为 modbus RTU 从站模式时,仅支持接收 modbus RTU 标准格式的请求报文
|
||||
3、进行回应时也需要符合 modbus RTU 标准格式
|
||||
|
||||
更多说明参考本目录下的 readme.md 文件;
|
||||
]]
|
||||
|
||||
--[[
|
||||
必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
|
||||
PROJECT:项目名,ascii string类型
|
||||
可以随便定义,只要不使用,就行
|
||||
VERSION:项目版本号,ascii string类型
|
||||
如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
|
||||
X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
|
||||
因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为999
|
||||
如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
|
||||
]]
|
||||
PROJECT = "RTU_SLAVE"
|
||||
VERSION = "001.999.000"
|
||||
|
||||
|
||||
-- 在日志中打印项目名和项目版本号
|
||||
log.info("main", PROJECT, VERSION)
|
||||
|
||||
-- 硬件环境配置说明
|
||||
-- 本Demo支持两种硬件环境,请根据实际使用情况修改HARDWARE_ENV变量:
|
||||
-- "DEV_BOARD_V1.3" - V1.3开发板(默认)
|
||||
-- 控制485接收和发送的使能脚:GPIO24
|
||||
-- "DEV_BOARD_V1.2" - V1.2开发板
|
||||
-- 控制485接收和发送的使能脚:GPIO25
|
||||
HARDWARE_ENV = "DEV_BOARD_V1.3" -- 修改此值适配不同开发板版本:"DEV_BOARD_V1.3"=V1.3开发板, "DEV_BOARD_V1.2"=V1.2开发板
|
||||
|
||||
|
||||
|
||||
-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
|
||||
-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
|
||||
-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
|
||||
-- 启动errDump日志存储并且上传功能,600秒上传一次
|
||||
-- if errDump then
|
||||
-- errDump.config(true, 600)
|
||||
-- end
|
||||
|
||||
|
||||
-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
|
||||
-- 可以使用合宙的iot.openluat.com平台进行远程升级
|
||||
-- 也可以使用客户自己搭建的平台进行远程升级
|
||||
-- 远程升级的详细用法,可以参考fota的demo进行使用
|
||||
|
||||
|
||||
-- 启动一个循环定时器
|
||||
-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
|
||||
-- 方便分析内存使用是否有异常
|
||||
-- sys.timerLoopStart(function()
|
||||
-- log.info("mem.lua", rtos.meminfo())
|
||||
-- log.info("mem.sys", rtos.meminfo("sys"))
|
||||
-- end, 3000)
|
||||
|
||||
|
||||
-- 加载 RTU 从站应用模块(字段参数方式)
|
||||
require "rtu_slave_manage"
|
||||
|
||||
-- 用户代码已结束---------------------------------------------
|
||||
-- 结尾总是这一句
|
||||
sys.run()
|
||||
-- sys.run()之后后面不要加任何语句!!!!!
|
||||
@@ -0,0 +1,176 @@
|
||||
## 一、演示模块概述
|
||||
|
||||
1、main.lua:主程序入口;
|
||||
|
||||
2、rtu_slave_manage.lua:RTU 从站应用模块;
|
||||
|
||||
## 二、演示功能概述
|
||||
|
||||
本 demo 演示的核心功能为:
|
||||
|
||||
1、将设备配置为 modbus RTU 从站模式
|
||||
|
||||
2、等待并且应答主站请求
|
||||
|
||||
|
||||
|
||||
注意事项:
|
||||
|
||||
1、该示例程序需要搭配 exmodbus 扩展库使用
|
||||
|
||||
2、设备作为 modbus RTU 从站模式时,仅支持接收 modbus RTU 标准格式的请求报文
|
||||
|
||||
3、进行回应时也需要符合 modbus RTU 标准格式
|
||||
|
||||
|
||||
## 三、演示硬件环境
|
||||
|
||||
### 3.1 硬件环境说明
|
||||
|
||||
本Demo支持两种硬件环境,请根据实际使用的开发板版本选择对应的配置:
|
||||
|
||||
| 硬件环境 | HARDWARE_ENV值 | 控制485接收和发送的使能脚 |
|
||||
|---------|---------------|----------|
|
||||
| V1.3开发板 | "DEV_BOARD_V1.3" | GPIO24(默认) |
|
||||
| V1.2开发板 | "DEV_BOARD_V1.2" | GPIO25 |
|
||||
|
||||
**配置方法:** 在`main.lua`中修改`HARDWARE_ENV`变量的值即可切换硬件环境。
|
||||
|
||||
#### 3.1.1 V1.3开发板(DEV_BOARD_V1.3,默认)
|
||||
|
||||
**配置说明**
|
||||
|
||||
在`main.lua`中设置:
|
||||
```lua
|
||||
HARDWARE_ENV = "DEV_BOARD_V1.3"
|
||||
```
|
||||
|
||||
485_uart驱动会自动完成以下操作:
|
||||
- 使用 **GPIO24** 作为485使能脚
|
||||
|
||||
#### 3.1.2 V1.2开发板(DEV_BOARD_V1.2)
|
||||
|
||||
**配置说明**
|
||||
|
||||
在`main.lua`中设置:
|
||||
```lua
|
||||
HARDWARE_ENV = "DEV_BOARD_V1.2"
|
||||
```
|
||||
|
||||
485_uart驱动会自动完成以下操作:
|
||||
- 使用 **GPIO25** 作为485使能脚
|
||||
|
||||
### 3.2 硬件清单
|
||||
|
||||
下面以Air780EPM V1.3开发板为例进行演示:
|
||||
|
||||
1、Air780EPM V1.3 开发板一块
|
||||
|
||||
2、TYPE-C USB数据线一根
|
||||
|
||||
3、USB-RS485 串口板
|
||||
|
||||
> 此处购买链接仅为推荐,如有问题请直接联系店家
|
||||
|
||||
- 购买链接:[4路RS-485,TYPEC接口 不含USB线](https://item.taobao.com/item.htm?app=chrome&bxsign=scdJP32y4DuiSo5k5D89Yse5PsbQ6EIYXNIPNkzmMi6zdQszLdrZrUy6-Nw96m51cCA5oz67QzXT9StIYyW8C2WWDa9P6CTUC4Imox3bONGK_FgAw8bQ8lYY0rnL7cRpNsG&cpp=1&id=608773837508&price=2.5&shareUniqueId=34323628624&share_crt_v=1&shareurl=true&short_name=h.7YHZDX57ex5G68h&skuId=5692060399621&sourceType=item&sp_tk=QXZFNGZzdXJGeTg%3D&spm=a2159r.13376460.0.0&suid=97525605-306d-4a26-8181-c6a5e5ac1449&tbSocialPopKey=shareItem&tk=AvE4fsurFy8&un=7a6477372f5d73d28011994573a7abfb&un_site=0&ut_sk=1.ZjZmtV%2FpLDkDACz9psyM0ajN_21646297_1765329298678.Copy.1&wxsign=tbwqCWYZys39IqYxa6fkQJ4fSCqNnxJegN9tEYlbjtUm1rAZyDddEbbohCLQnFZUojPMaKxNICvdbp1uAgV6d03jf7_X0hLeyUaHbuddZUTcL_y45R5fClnUqq9IfXXAxNG)
|
||||
|
||||

|
||||
|
||||
## 四、演示软件环境
|
||||
|
||||
1、[Luatools下载调试工具](https://docs.openluat.com/air780epm/luatos/common/download/)
|
||||
|
||||
2、[Air780EPM V2018 版本](https://docs.openluat.com/air780epm/luatos/firmware/version/)(理论上最新版本固件也可以,如果使用最新版本的固件不可以,可以烧录 V2018-1 固件对比验证)
|
||||
|
||||
3、[摩尔信使(MThings)官网](https://www.gulink.cn/)(用于模拟 modbus 主站设备)
|
||||
|
||||
## 五、演示核心步骤
|
||||
|
||||
1、搭建硬件环境
|
||||
|
||||
- 将 USB-RS485 串口板与 Air780EPM 开发板进行连接
|
||||
- 将 USB-RS485 串口板 与 Air780EPM 开发板的 USB 端同时接在电脑上
|
||||
- 参考图见 演示硬件环境
|
||||
|
||||
2、在摩尔信使上配置模拟 RTU 主站设备环境
|
||||
|
||||
- 点击左上角的 “通道管理”按钮,在 “通道管理” 窗口选择对应的串口(USB-RS485 串口板与 Air780EPM 开发板进行 485 通信时的端口),点击对应串口后面的 “配置” 按钮,在 “串口参数配置” 窗口配置串口参数(要求与代码中调用 exmodbus.create 接口时填入的配置参数一致),操作流程图如下:
|
||||
|
||||

|
||||
|
||||
- 点击左上角的 “添加设备”按钮,在 “添加设备” 窗口对通信设备参数进行配置,配置好后点击 “添加” 按钮,左侧栏即为添加后的效果,操作流程图如下:
|
||||
|
||||

|
||||
|
||||
- 点击左侧的第一个主站(我这里显示为 “COM36-001”),点击中上部分的 “新增数据” 按钮,在 “新增数据配置” 窗口将 “数据条数” 、“区块” 、“起始数据地址” 按照下图中所示进行配置,最后点击 “确定” 按钮,此时便成功新增线圈 0-2,操作流程图如下,此时按照刚才操作,依次分别创建离散输入 0-2、保持寄存器 0-2、输入寄存器 0-2
|
||||
|
||||

|
||||
|
||||
- 此时在摩尔信使上的配置操作已经完成,如果需要在摩尔信使上查看报文,那么操作流程图如下:
|
||||
|
||||

|
||||
|
||||
4、打开 Luatools 工具,根据要求烧录本次所需要的内核固件和脚本代码
|
||||
|
||||
5、烧录成功后,自动开机运行
|
||||
|
||||
6、开机运行后 Luatools 工具上记录的日志如下,此时便开始等待主站发送请求
|
||||
|
||||
```
|
||||
[2025-12-29 11:22:47.269][000000000.323] I/user.main RTU_SLAVE 001.000.000
|
||||
[2025-12-29 11:22:47.271][000000000.350] Uart_ChangeBR 1338:uart1, 115200 115203 26000000 3611
|
||||
[2025-12-29 11:22:47.273][000000000.351] I/user.exmodbus 串口 1 初始化成功,波特率 115200
|
||||
[2025-12-29 11:22:47.277][000000000.351] I/user.exmodbus_test rtu_slave 创建成功, 从站 ID 为 1
|
||||
[2025-12-29 11:22:47.280][000000000.351] I/user.exmodbus 已注册从站请求处理回调函数
|
||||
[2025-12-29 11:22:47.289][000000000.351] I/user.从站回调函数已注册,开始监听主站请求...
|
||||
```
|
||||
|
||||
7、如下图所示,在摩尔信使上鼠标右击第一个主站,然后点击 “启动轮询”,此时上位机便会模拟主站设备开始执行轮询请求操作
|
||||
|
||||

|
||||
|
||||
8、如下图所示,如果需要修改轮询的间隔时间或者其他参数,先将滑动条滑到右边,然后鼠标左键双击对应参数即可修改
|
||||
|
||||

|
||||
|
||||
9、开启轮询后 Luatools 工具与摩尔信使上的日志如下:
|
||||
|
||||
```
|
||||
[2025-12-29 11:24:22.254][000000095.742] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:22.258][000000095.742] I/user.exmodbus_test 读取成功,返回数据: 0, 0
|
||||
[2025-12-29 11:24:25.268][000000098.756] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:25.271][000000098.757] I/user.exmodbus_test 读取成功,返回数据: 1, 1
|
||||
[2025-12-29 11:24:28.279][000000101.767] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:28.281][000000101.768] I/user.exmodbus_test 读取成功,返回数据: 201, 202
|
||||
[2025-12-29 11:24:31.269][000000104.759] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:31.272][000000104.760] I/user.exmodbus_test 读取成功,返回数据: 101, 102
|
||||
[2025-12-29 11:24:34.277][000000107.766] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:34.284][000000107.767] I/user.exmodbus_test 读取成功,返回数据: 0, 0
|
||||
[2025-12-29 11:24:37.276][000000110.764] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:37.280][000000110.765] I/user.exmodbus_test 读取成功,返回数据: 1, 1
|
||||
[2025-12-29 11:24:40.297][000000113.785] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:40.309][000000113.785] I/user.exmodbus_test 读取成功,返回数据: 201, 202
|
||||
[2025-12-29 11:24:43.327][000000116.814] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:43.329][000000116.814] I/user.exmodbus_test 读取成功,返回数据: 101, 102
|
||||
[2025-12-29 11:24:46.333][000000119.821] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:24:46.335][000000119.822] I/user.exmodbus_test 读取成功,返回数据: 0, 0
|
||||
```
|
||||
|
||||

|
||||
|
||||
10、如下图所示,如果需要执行写入请求,需要先在执行可写操作的对应区块行的指令处鼠标左键双击填入要写入的数值,然后在鼠标右键双击该数值,最后点击下发写指令
|
||||
|
||||

|
||||
|
||||
11、执行写入请求后 Luatools 工具与摩尔信使上的日志如下:
|
||||
|
||||
```
|
||||
[2025-12-29 11:28:38.214][000000351.702] I/user.exmodbus_test rtu_slave 收到主站请求
|
||||
[2025-12-29 11:28:38.216][000000351.702] I/user.exmodbus_test 写入成功,写入地址: 0 写入数据: 123
|
||||
```
|
||||
|
||||

|
||||
|
||||
12、如下图所示,在摩尔信使上鼠标右击第一个主站,然后点击 “停止轮询”,此时上位机便不会再执行轮询请求操作
|
||||
|
||||

|
||||
@@ -0,0 +1,157 @@
|
||||
--[[
|
||||
@module rtu_slave_manage
|
||||
@summary RTU 从站应用模块
|
||||
@version 1.0
|
||||
@date 2025.12.29
|
||||
@author 马梦阳
|
||||
@usage
|
||||
本功能模块演示的内容为:
|
||||
1、将设备配置为 modbus RTU 从站模式
|
||||
2、等待并且应答主站请求
|
||||
|
||||
注意事项:
|
||||
1、该示例程序需要搭配 exmodbus 扩展库使用
|
||||
2、设备作为 modbus RTU 从站模式时,仅支持接收 modbus RTU 标准格式的请求报文
|
||||
3、进行回应时也需要符合 modbus RTU 标准格式
|
||||
|
||||
本文件没有对外接口,直接在 main.lua 中 require "rtu_slave_manage" 就可以加载运行;
|
||||
]]
|
||||
|
||||
local exmodbus = require("exmodbus")
|
||||
|
||||
-- 根据硬件环境配置控制485接收和发送的使能脚
|
||||
local rs485_dir_gpio = 24 -- 默认值
|
||||
|
||||
if HARDWARE_ENV == "DEV_BOARD_V1.2" then
|
||||
rs485_dir_gpio = 25 -- V1.2开发板使用GPIO25
|
||||
elseif HARDWARE_ENV == "DEV_BOARD_V1.3" then
|
||||
rs485_dir_gpio = 24 -- V1.3开发板使用GPIO24
|
||||
end
|
||||
|
||||
gpio.setup(1, 1) -- Air780EPM RS485 芯片供电引脚
|
||||
gpio.setup(23, 1) -- Air780EPM vref 脚拉高
|
||||
|
||||
-- 创建 RTU 从站配置参数
|
||||
-- 说明:创建 RTU 从站时只需要配置如下参数即可
|
||||
local rtu_slave_config = {
|
||||
-- 串口配置参数
|
||||
mode = exmodbus.RTU_SLAVE, -- 通信模式
|
||||
uart_id = 1, -- UART 端口号
|
||||
baud_rate = 115200, -- 波特率
|
||||
data_bits = 8, -- 数据位
|
||||
stop_bits = 1, -- 停止位
|
||||
parity_bits = uart.None, -- 校验位
|
||||
byte_order = uart.LSB, -- 字节顺序
|
||||
rs485_dir_gpio = rs485_dir_gpio, -- RS485 方向引脚
|
||||
rs485_dir_rx_level = 0, -- RS485 接收方向电平
|
||||
}
|
||||
|
||||
|
||||
-- 当前从站地址(ID 号)
|
||||
local SLAVE_ID = 1
|
||||
|
||||
|
||||
-- 寄存器映射表(按类型组织)
|
||||
local modbus_data = {
|
||||
coils = {}, -- 线圈,可读可写,布尔值 (0/1)
|
||||
inputs = {}, -- 输入状态,只读,布尔值 (0/1)
|
||||
input_registers = {}, -- 输入寄存器,只读,16 位无符号整数
|
||||
holding_registers = {} -- 保持寄存器,可读可写,16 位无符号整数
|
||||
}
|
||||
|
||||
|
||||
-- 初始化一些默认值,便于测试
|
||||
for i = 0, 3 do
|
||||
modbus_data.coils[i] = 0
|
||||
modbus_data.inputs[i] = 1
|
||||
modbus_data.input_registers[i] = 100 + i
|
||||
modbus_data.holding_registers[i] = 200 + i
|
||||
end
|
||||
|
||||
|
||||
-- 创建 RTU 从站实例
|
||||
local rtu_slave = exmodbus.create(rtu_slave_config)
|
||||
|
||||
-- 判断从站是否创建成功
|
||||
if not rtu_slave then
|
||||
log.info("exmodbus_test", "rtu_slave 创建失败")
|
||||
else
|
||||
log.info("exmodbus_test", "rtu_slave 创建成功, 从站 ID 为", SLAVE_ID)
|
||||
end
|
||||
|
||||
|
||||
-- 定义主站请求处理回调函数
|
||||
local function callback(request)
|
||||
log.info("exmodbus_test", "rtu_slave 收到主站请求")
|
||||
|
||||
-- 检查从站 ID 是否匹配
|
||||
if request.slave_id ~= SLAVE_ID then
|
||||
log.info("exmodbus_test", "从站 ID 不匹配,请求从站 ID 为", request.slave_id, ",当前从站 ID 为", SLAVE_ID)
|
||||
return nil
|
||||
end
|
||||
|
||||
-- 根据功能码和寄存器类型,匹配对应的数据表
|
||||
local data_table = nil
|
||||
local is_write = false -- 标记是否为写操作
|
||||
|
||||
-- 检查请求的功能码是否支持
|
||||
if request.func_code == exmodbus.READ_COILS then -- 读线圈
|
||||
data_table = modbus_data.coils
|
||||
elseif request.func_code == exmodbus.READ_DISCRETE_INPUTS then -- 读离散输入
|
||||
data_table = modbus_data.inputs
|
||||
elseif request.func_code == exmodbus.READ_HOLDING_REGISTERS then -- 读保持寄存器
|
||||
data_table = modbus_data.holding_registers
|
||||
elseif request.func_code == exmodbus.READ_INPUT_REGISTERS then -- 读输入寄存器
|
||||
data_table = modbus_data.input_registers
|
||||
elseif request.func_code == exmodbus.WRITE_SINGLE_COIL or request.func_code == exmodbus.WRITE_MULTIPLE_COILS then -- 写单个/多个线圈
|
||||
is_write = true
|
||||
data_table = modbus_data.coils
|
||||
elseif request.func_code == exmodbus.WRITE_SINGLE_HOLDING_REGISTER or request.func_code == exmodbus.WRITE_MULTIPLE_HOLDING_REGISTERS then -- 写单个/多个保持寄存器
|
||||
is_write = true
|
||||
data_table = modbus_data.holding_registers
|
||||
else
|
||||
-- 不支持的功能码
|
||||
log.info("exmodbus_test", "不支持的功能码: ", request.func_code)
|
||||
return exmodbus.ILLEGAL_FUNCTION
|
||||
end
|
||||
|
||||
-- 检查数据地址是否有效
|
||||
local end_addr = request.start_addr + request.reg_count - 1
|
||||
|
||||
-- 假设每种寄存器的最大地址是 3 (即 0 - 3)
|
||||
if request.start_addr < 0 or end_addr > 3 then
|
||||
log.info("exmodbus_test", "数据地址超出范围,起始地址为", request.start_addr, "结束地址为", end_addr)
|
||||
return exmodbus.ILLEGAL_DATA_ADDRESS
|
||||
end
|
||||
|
||||
-- 处理读取操作
|
||||
if not is_write then
|
||||
-- 构造响应数据表
|
||||
local response = {}
|
||||
local response_str = ""
|
||||
for i = 0, request.reg_count - 1 do
|
||||
local addr = request.start_addr + i
|
||||
response[addr] = data_table[addr]
|
||||
response_str = response_str .. (i > 0 and ", " or "") .. response[addr]
|
||||
end
|
||||
log.info("exmodbus_test", "读取成功,返回数据: ", response_str)
|
||||
return response
|
||||
end
|
||||
|
||||
-- 处理写入操作
|
||||
if is_write then
|
||||
-- 执行写入操作
|
||||
for i = 0, request.reg_count - 1 do
|
||||
local addr = request.start_addr + i
|
||||
data_table[addr] = request.data[addr]
|
||||
log.info("exmodbus_test", "写入成功,写入地址: ", addr, "写入数据: ", request.data[addr])
|
||||
end
|
||||
return {} -- 返回空表表示成功
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- 注册主站请求处理回调函数
|
||||
rtu_slave:on(callback)
|
||||
|
||||
log.info("从站回调函数已注册,开始监听主站请求...")
|
||||
Reference in New Issue
Block a user