Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

163 строки
5.3 KiB

  1. #ifndef MODBUS_RTU_SLAVE_H
  2. #define MODBUS_RTU_SLAVE_H
  3. #include "stm32f4xx_hal.h"
  4. #include <stdint.h>
  5. #ifdef __cplusplus
  6. extern "C"
  7. {
  8. #endif
  9. /**
  10. * @brief Modbus 数据模型的最大地址
  11. *
  12. * 任务要求规定线圈和保持寄存器地址范围均为 0~0x270F,
  13. * 因此每种数据共有 10000 项
  14. */
  15. #define MODBUS_MAP_LAST_ADDRESS (0x270FU) // 保持寄存器或线圈地址
  16. #define MODBUS_MAP_ITEM_COUNT (0x2710U) // 保持寄存器或线圈数量
  17. #define MODBUS_SLAVE_DEFAULT_ADDRESS (1U)
  18. #define MODBUS_CONNECTION_TIMEOUT_MS (1000U)
  19. /**
  20. * @brief 与 TouchWin 触摸屏联调使用的演示地址
  21. *
  22. * 可以直接访问以下地址
  23. */
  24. #define HMI_REG_DEVICE_ID (0U)
  25. #define HMI_REG_UPTIME_SECONDS (1U)
  26. #define HMI_REG_RX_FRAME_COUNT (2U)
  27. #define D3 (3U)
  28. #define D4 (4U)
  29. #define D5 (5U)
  30. #define D6 (6U)
  31. #define D7 (7U)
  32. #define HMI_REG_WRITE_TEST (10U)
  33. #define HMI_COIL_WRITE_TEST (0U)
  34. #define MODBUS_RETAINED_D_START (100U)
  35. #define MODBUS_RETAINED_D_END (120U)
  36. #define MODBUS_RETAINED_D_COUNT (21U)
  37. #define MODBUS_BACKUP_MAGIC (0x44313030UL)
  38. /**
  39. * @brief 掉电保持寄存器在Backup SRAM中的存储格式
  40. */
  41. typedef struct
  42. {
  43. uint32_t magic; ///< 掉电保持数据有效标志
  44. uint16_t retainedD[MODBUS_RETAINED_D_COUNT]; ///< D100~D120保持值
  45. } MODBUS_BACKUP_DATA;
  46. /**
  47. * @brief Modbus 从站通信统计信息
  48. */
  49. typedef struct
  50. {
  51. uint32_t rxEventCount; ///< 串口接收事件总数
  52. uint32_t validFrameCount; ///< CRC 和从站地址均有效的帧数
  53. uint32_t txFrameCount; ///< 成功启动 DMA 发送的帧数
  54. uint32_t crcErrorCount; ///< CRC 校验错误帧数
  55. uint32_t ignoredAddressCount; ///< 因从站地址不匹配而忽略的帧数
  56. uint32_t illegalFunctionCount; ///< 非法功能码计数
  57. uint32_t illegalAddressCount; ///< 非法数据地址计数
  58. uint32_t illegalValueCount; ///< 非法数据值计数
  59. uint32_t droppedFrameCount; ///< 接收槽占用或长度错误导致的丢帧数
  60. uint32_t uartErrorCount; ///< HAL 串口错误计数
  61. } MODBUS_SLAVE_STATS;
  62. /**
  63. * @brief 一次Modbus RTU通信的历史记录
  64. */
  65. typedef struct
  66. {
  67. uint32_t tick; ///< 通信发生时的系统时间
  68. uint16_t requestLength; ///< 请求ADU长度
  69. uint16_t responseLength; ///< 响应ADU长度
  70. uint8_t request[256]; ///< 请求ADU数据
  71. uint8_t response[256]; ///< 响应ADU数据
  72. } MODBUS_HISTORY_ITEM;
  73. /** @brief Modbus 从站通信统计数据 */
  74. extern volatile MODBUS_SLAVE_STATS ModbusSlaveStatistics;
  75. /**
  76. * @brief 初始化 Modbus 从站并启动 USART DMA 空闲接收
  77. * @param[in] huart 已由 HAL 初始化完成的串口句柄
  78. * @param[in] slaveAddress 从站地址,有效范围为 1~247
  79. * @retval HAL_OK 初始化成功且 DMA 接收已启动
  80. * @retval HAL_ERROR 输入参数无效
  81. * @retval HAL_BUSY 串口或 DMA 当前忙
  82. */
  83. HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart,
  84. uint8_t slaveAddress);
  85. /**
  86. * @brief 校验并处理一帧待处理请求
  87. *
  88. * 本函数应在 uC/OS-II 任务中周期调用中断只负责接收数据,
  89. * CRC 校验、协议解析和响应发送均在任务上下文中执行
  90. */
  91. void ModbusSlavePoll(void);
  92. /**
  93. * @brief 处理 HAL 串口 DMA 接收事件
  94. * @param[in] huart 产生接收事件的串口句柄
  95. * @param[in] size 本次接收到的字节数
  96. */
  97. void ModbusSlaveOnRxEvent(UART_HandleTypeDef *huart, uint16_t size);
  98. /**
  99. * @brief 处理 HAL 串口 DMA 发送完成事件
  100. * @param[in] huart 完成发送的串口句柄
  101. */
  102. void ModbusSlaveOnTxComplete(UART_HandleTypeDef *huart);
  103. /**
  104. * @brief 处理 HAL 串口错误事件并恢复接收
  105. * @param[in] huart 发生错误的串口句柄
  106. */
  107. void ModbusSlaveOnUartError(UART_HandleTypeDef *huart);
  108. /**
  109. * @brief 写入一个保持寄存器
  110. * @param[in] address 保持寄存器地址
  111. * @param[in] value 待写入的 16 位数据
  112. * @retval 1 写入成功
  113. * @retval 0 保持寄存器地址无效
  114. */
  115. uint8_t ModbusSlaveSetHoldingRegister(uint16_t address, uint16_t value);
  116. /**
  117. * @brief 读取一个保持寄存器
  118. * @param[in] address 保持寄存器地址
  119. * @param[out] value 用于保存读取结果的指针
  120. * @retval 1 读取成功
  121. * @retval 0 保持寄存器地址无效或输出指针为空
  122. */
  123. uint8_t ModbusSlaveGetHoldingRegister(uint16_t address, uint16_t *value);
  124. /**
  125. * @brief 设置一个线圈的状态
  126. * @param[in] address 线圈地址
  127. * @param[in] state 0 表示复位,非 0 表示置位
  128. * @retval 1 设置成功
  129. * @retval 0 线圈地址无效
  130. */
  131. uint8_t ModbusSlaveSetCoil(uint16_t address, uint8_t state);
  132. /**
  133. * @brief 读取一个线圈的状态
  134. * @param[in] address 线圈地址
  135. * @param[out] state 用于保存线圈状态的指针,结果为 0 或 1
  136. * @retval 1 读取成功
  137. * @retval 0 线圈地址无效或输出指针为空
  138. */
  139. uint8_t ModbusSlaveGetCoil(uint16_t address, uint8_t *state);
  140. /**
  141. * @brief 判断指定时间内是否收到过有效请求
  142. * @param[in] timeoutMs 连接超时时间,单位为毫秒
  143. * @retval 1 从站在指定时间内收到过有效请求
  144. * @retval 0 尚未收到有效请求或连接已经超时
  145. */
  146. uint8_t ModbusSlaveIsConnected(uint32_t timeoutMs);
  147. void ModbusRetainedRegistersLoad(void);
  148. void ModbusRetainedRegistersPoll(void);
  149. void HistorySaveToRegisters(void);
  150. #ifdef __cplusplus
  151. }
  152. #endif
  153. #endif /* MODBUS_RTU_SLAVE_H */