tcp_slave_manage.lua 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. --[[
  2. @module tcp_slave_manage
  3. @summary TCP 从站应用模块
  4. @version 1.0
  5. @date 2025.12.12
  6. @author 马梦阳
  7. @usage
  8. 本功能模块演示的内容为:
  9. 1、将设备配置为 modbus TCP 从站模式
  10. 2、等待并且应答主站请求
  11. 注意事项:
  12. 1、该示例程序需要搭配 exmodbus 扩展库使用
  13. 2、设备作为 modbus TCP 从站模式时,仅支持接收 modbus TCP 标准格式的请求报文
  14. 3、进行回应时也需要符合 modbus TCP 标准格式
  15. 本文件没有对外接口,直接在 main.lua 中 require "tcp_slave_manage" 就可以加载运行;
  16. ]]
  17. local exmodbus = require("exmodbus")
  18. -- 创建 TCP 从站配置参数
  19. -- 说明:创建 TCP 从站时只需要配置如下参数即可
  20. local tcp_slave_config = {
  21. -- 网络配置参数
  22. mode = exmodbus.TCP_SLAVE, -- 通信模式:TCP 从站
  23. adapter = socket.LWIP_ETH, -- 网卡 ID:LwIP 协议栈的以太网卡
  24. port = 6000, -- 本地端口号:6000(主站:服务器端口;从站:本地端口)
  25. }
  26. -- 当前从站地址(ID 号)
  27. local SLAVE_ID = 1
  28. -- 寄存器映射表(按类型组织)
  29. local modbus_data = {
  30. coils = {}, -- 线圈,可读可写,布尔值 (0/1)
  31. inputs = {}, -- 输入状态,只读,布尔值 (0/1)
  32. input_registers = {}, -- 输入寄存器,只读,16 位无符号整数
  33. holding_registers = {} -- 保持寄存器,可读可写,16 位无符号整数
  34. }
  35. -- 初始化一些默认值,便于测试
  36. for i = 0, 3 do
  37. modbus_data.coils[i] = 0
  38. modbus_data.inputs[i] = 1
  39. modbus_data.input_registers[i] = 100 + i
  40. modbus_data.holding_registers[i] = 200 + i
  41. end
  42. -- 创建 TCP 从站实例
  43. local tcp_slave = exmodbus.create(tcp_slave_config)
  44. -- 判断从站是否创建成功
  45. if not tcp_slave then
  46. log.info("exmodbus_test", "tcp_slave 创建失败")
  47. else
  48. log.info("exmodbus_test", "tcp_slave 创建成功, 从站 ID 为", SLAVE_ID)
  49. end
  50. -- 定义主站请求处理回调函数
  51. local function callback(request)
  52. log.info("exmodbus_test", "tcp_slave 收到主站请求")
  53. -- 检查从站 ID 是否匹配
  54. if request.slave_id ~= SLAVE_ID then
  55. log.info("exmodbus_test", "从站 ID 不匹配,请求从站 ID 为", request.slave_id, ",当前从站 ID 为", SLAVE_ID)
  56. return nil
  57. end
  58. -- 根据功能码和寄存器类型,匹配对应的数据表
  59. local data_table = nil
  60. local is_write = false -- 标记是否为写操作
  61. -- 检查请求的功能码是否支持
  62. if request.func_code == exmodbus.READ_COILS then -- 读线圈
  63. data_table = modbus_data.coils
  64. elseif request.func_code == exmodbus.READ_DISCRETE_INPUTS then -- 读离散输入
  65. data_table = modbus_data.inputs
  66. elseif request.func_code == exmodbus.READ_HOLDING_REGISTERS then -- 读保持寄存器
  67. data_table = modbus_data.holding_registers
  68. elseif request.func_code == exmodbus.READ_INPUT_REGISTERS then -- 读输入寄存器
  69. data_table = modbus_data.input_registers
  70. elseif request.func_code == exmodbus.WRITE_SINGLE_COIL or request.func_code == exmodbus.WRITE_MULTIPLE_COILS then -- 写单个/多个线圈
  71. is_write = true
  72. data_table = modbus_data.coils
  73. elseif request.func_code == exmodbus.WRITE_SINGLE_HOLDING_REGISTER or request.func_code == exmodbus.WRITE_MULTIPLE_HOLDING_REGISTERS then -- 写单个/多个保持寄存器
  74. is_write = true
  75. data_table = modbus_data.holding_registers
  76. else
  77. -- 不支持的功能码
  78. log.info("exmodbus_test", "不支持的功能码: ", request.func_code)
  79. return exmodbus.ILLEGAL_FUNCTION
  80. end
  81. -- 检查数据地址是否有效
  82. local end_addr = request.start_addr + request.reg_count - 1
  83. -- 假设每种寄存器的最大地址是 3 (即 0 - 3)
  84. if request.start_addr < 0 or end_addr > 3 then
  85. log.info("exmodbus_test", "数据地址超出范围,起始地址为", request.start_addr, "结束地址为", end_addr)
  86. return exmodbus.ILLEGAL_DATA_ADDRESS
  87. end
  88. -- 处理读取操作
  89. if not is_write then
  90. -- 构造响应数据表
  91. local response = {}
  92. for i = 0, request.reg_count - 1 do
  93. local addr = request.start_addr + i
  94. response[addr] = data_table[addr]
  95. end
  96. log.info("exmodbus_test", "读取成功,返回数据: ", table.concat(response, ", "))
  97. return response
  98. end
  99. -- 处理写入操作
  100. if is_write then
  101. -- 执行写入操作
  102. for i = 0, request.reg_count - 1 do
  103. local addr = request.start_addr + i
  104. data_table[addr] = request.data[addr]
  105. log.info("exmodbus_test", "写入成功,写入地址: ", addr, "写入数据: ", request.data[addr])
  106. end
  107. return {} -- 返回空表表示成功
  108. end
  109. end
  110. -- 注册主站请求处理回调函数
  111. tcp_slave:on(callback)
  112. log.info("从站回调函数已注册,开始监听主站请求...")