param_field.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. --[[
  2. @module param_field
  3. @summary RTU 主站应用模块(字段参数方式)
  4. @version 1.0
  5. @date 2025.12.12
  6. @author 马梦阳
  7. @usage
  8. 本功能模块演示的内容为:
  9. 1、将设备配置为 modbus RTU 主站模式
  10. 2、与从站 1 和 从站 2 进行通信
  11. 1. 对从站 1 进行 2 秒一次的读取保持寄存器 0-1 操作
  12. 2. 对从站 2 进行 4 秒一次的写入保持寄存器 0-1 操作
  13. 可通过修改字段参数 force_multiple 为 true 来强制使用写多个功能码(写多个线圈功能码:0x0F;写多个寄存器功能码:0x10)
  14. 注意事项:
  15. 1、该示例程序需要搭配 exmodbus 扩展库使用
  16. 2、本功能模块只适合使用标准 modbus RTU 请求报文格式的用户
  17. 3、如果你使用的是非标准 modbus RTU 请求报文格式,请参考 raw_frame 功能模块
  18. 本文件没有对外接口,直接在 main.lua 中 require "param_field" 就可以加载运行;
  19. ]]
  20. local exmodbus = require("exmodbus")
  21. gpio.setup(16, 1) -- Air8000 开发板 RS485 芯片供电引脚
  22. local rs485_dir_gpio = 17 -- Air8000 开发板 RS485 方向引脚
  23. -- 创建 RTU 主站配置参数;
  24. -- 说明:创建 RTU 主站时只需要配置如下参数即可;
  25. local create_config = {
  26. -- 串口配置参数;
  27. mode = exmodbus.RTU_MASTER, -- 通信模式
  28. uart_id = 1, -- UART 端口号
  29. baud_rate = 115200, -- 波特率
  30. data_bits = 8, -- 数据位
  31. stop_bits = 1, -- 停止位
  32. parity_bits = uart.None, -- 校验位
  33. byte_order = uart.LSB, -- 字节顺序
  34. rs485_dir_gpio = rs485_dir_gpio, -- RS485 方向引脚
  35. rs485_dir_rx_level = 0, -- RS485 接收方向电平
  36. }
  37. -- 初始化从站 1 数据结构
  38. -- 用于记录从站 1 保持寄存器 0-1 的值;
  39. local slave1_data = {}
  40. -- 读取从站 1 保持寄存器 0-1 的值时,配置读命令的字段参数;
  41. local read_config = {
  42. slave_id = 1, -- 从站地址 1
  43. reg_type = exmodbus.HOLDING_REGISTER, -- 寄存器类型:保持寄存器
  44. start_addr = 0x0000, -- 起始地址 0
  45. reg_count = 0x0002, -- 读取 2 个寄存器
  46. timeout = 1000 -- 超时时间 1000 ms
  47. }
  48. -- 初始化从站 2 数据结构;
  49. local slave2_data = {
  50. data1 = 123,
  51. data2 = 456
  52. }
  53. -- 定义从站 2 保持寄存器的起始地址;
  54. local start_addr = 0x0000
  55. -- 写入从站 2 保持寄存器 0-1 的值时,配置写命令的字段参数;
  56. local write_config = {
  57. slave_id = 2, -- 从站地址 2
  58. reg_type = exmodbus.HOLDING_REGISTER, -- 寄存器类型:保持寄存器
  59. start_addr = start_addr, -- 起始地址 0
  60. reg_count = 0x0002, -- 写入 2 个寄存器
  61. data = {
  62. [start_addr] = slave2_data.data1, -- 第一个寄存器值
  63. [start_addr + 1] = slave2_data.data2, -- 第二个寄存器值
  64. }, -- 写入寄存器值
  65. force_multiple = true, -- 强制使用写多个功能码
  66. -- 设置为 true 时,写单个或多个线圈时强制功能码为 0x0F,写单个或多个保持寄存器时强制功能码为 0x10
  67. -- 设置为 false 时,写单个线圈时功能码为 0x05,写单个保持寄存器时功能码为 0x06,写多个线圈时功能码为 0x0F,写多个保持寄存器时功能码为 0x10
  68. timeout = 1000 -- 超时时间 1000 ms
  69. }
  70. -- 创建 RTU 主站实例
  71. local rtu_master = exmodbus.create(create_config)
  72. -- 判断主站是否创建成功并记录日志
  73. if not rtu_master then
  74. log.info("exmodbus_test", "rtu_master 创建失败")
  75. else
  76. log.info("exmodbus_test", "rtu_master 创建成功")
  77. end
  78. -- 读取从站 1 保持寄存器数据的函数
  79. local function read_slave1_holding_registers()
  80. log.info("exmodbus_test", "开始读取从站 1 保持寄存器 0-1 的值")
  81. -- 执行读取操作
  82. local read_result = rtu_master:read(read_config)
  83. -- 根据返回状态处理结果
  84. if read_result.status == exmodbus.STATUS_SUCCESS then
  85. slave1_data.data1 = read_result.data[read_config.start_addr]
  86. slave1_data.data2 = read_result.data[read_config.start_addr + 1]
  87. log.info("exmodbus_test", "成功读取到从站 1 保持寄存器 0-1 的值,寄存器 0 数值为", slave1_data.data1, ",寄存器 1 数值为", slave1_data.data2)
  88. elseif read_result.status == exmodbus.STATUS_DATA_INVALID then
  89. log.info("exmodbus_test", "收到从站 1 的响应数据但数据损坏/校验失败")
  90. elseif read_result.status == exmodbus.STATUS_EXCEPTION then
  91. log.info("exmodbus_test", "收到从站 1 的 modbus 标准异常响应,异常码为", read_result.execption_code)
  92. elseif read_result.status == exmodbus.STATUS_TIMEOUT then
  93. log.info("exmodbus_test", "未收到从站 1 的响应(超时)")
  94. end
  95. end
  96. -- 写入从站 2 保持寄存器数据的函数
  97. local function write_slave2_holding_registers()
  98. log.info("exmodbus_test", "开始写入从站 2 保持寄存器 0-1 的值,寄存器 0 数值为", slave2_data.data1, ",寄存器 1 数值为", slave2_data.data2)
  99. -- 执行写入操作
  100. local write_result = rtu_master:write(write_config)
  101. -- 根据返回状态处理结果
  102. if write_result.status == exmodbus.STATUS_SUCCESS then
  103. log.info("exmodbus_test", "成功写入从站 2 保持寄存器 0-1 的值")
  104. elseif write_result.status == exmodbus.STATUS_DATA_INVALID then
  105. log.info("exmodbus_test", "收到从站 2 的响应数据但数据损坏/校验失败")
  106. elseif write_result.status == exmodbus.STATUS_EXCEPTION then
  107. log.info("exmodbus_test", "收到从站 2 的 modbus 标准异常响应,异常码为", write_result.execption_code)
  108. elseif write_result.status == exmodbus.STATUS_TIMEOUT then
  109. log.info("exmodbus_test", "未收到从站 2 的响应(超时)")
  110. end
  111. end
  112. -- 定时任务函数:每 2 秒调用一次读取函数,每 4 秒调用一次写入函数
  113. local function task()
  114. local count = 0 -- 计数器
  115. while true do
  116. if rtu_master then
  117. -- 每 2 秒调用一次读取函数
  118. read_slave1_holding_registers()
  119. if count == 0 then
  120. -- 每 4 秒调用一次写入函数
  121. write_slave2_holding_registers()
  122. end
  123. count = (count + 1) % 2
  124. else
  125. log.info("exmodbus_test", "rtu_master 未创建,无法执行 read_slave1_holding_registers()")
  126. end
  127. sys.wait(2000)
  128. end
  129. end
  130. -- 初始化任务
  131. sys.taskInit(task)