| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- --[[
- @module tcp_slave_manage
- @summary TCP 从站应用模块
- @version 1.0
- @date 2025.12.12
- @author 马梦阳
- @usage
- 本功能模块演示的内容为:
- 1、将设备配置为 modbus TCP 从站模式
- 2、等待并且应答主站请求
- 注意事项:
- 1、该示例程序需要搭配 exmodbus 扩展库使用
- 2、设备作为 modbus TCP 从站模式时,仅支持接收 modbus TCP 标准格式的请求报文
- 3、进行回应时也需要符合 modbus TCP 标准格式
- 本文件没有对外接口,直接在 main.lua 中 require "tcp_slave_manage" 就可以加载运行;
- ]]
- local exmodbus = require("exmodbus")
- -- 创建 TCP 从站配置参数
- -- 说明:创建 TCP 从站时只需要配置如下参数即可
- local tcp_slave_config = {
- -- 网络配置参数
- mode = exmodbus.TCP_SLAVE, -- 通信模式:TCP 从站
- adapter = socket.LWIP_ETH, -- 网卡 ID:LwIP 协议栈的以太网卡
- port = 6000, -- 本地端口号:6000(主站:服务器端口;从站:本地端口)
- }
- -- 当前从站地址(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
- -- 创建 TCP 从站实例
- local tcp_slave = exmodbus.create(tcp_slave_config)
- -- 判断从站是否创建成功
- if not tcp_slave then
- log.info("exmodbus_test", "tcp_slave 创建失败")
- else
- log.info("exmodbus_test", "tcp_slave 创建成功, 从站 ID 为", SLAVE_ID)
- end
- -- 定义主站请求处理回调函数
- local function callback(request)
- log.info("exmodbus_test", "tcp_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 = {}
- for i = 0, request.reg_count - 1 do
- local addr = request.start_addr + i
- response[addr] = data_table[addr]
- end
- log.info("exmodbus_test", "读取成功,返回数据: ", table.concat(response, ", "))
- 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
- -- 注册主站请求处理回调函数
- tcp_slave:on(callback)
- log.info("从站回调函数已注册,开始监听主站请求...")
|