diff --git a/Core/Src/main.c b/Core/Src/main.c index 2690525..80c3e63 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -24,6 +24,7 @@ /* USER CODE BEGIN Includes */ #include "ucos_ii.h" #include "modbus_rtu_slave.h" +#include "stdio.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -110,6 +111,9 @@ static void AppTaskStart(void *p_arg) 6, (uint16_t)ModbusSlaveStatistics.illegalValueCount); +HistorySaveToRegisters(); + + @@ -122,6 +126,7 @@ static void AppTaskStart(void *p_arg) */ ModbusSlavePoll(); ModbusRetainedRegistersPoll(); + // printf("123"); OSTimeDly(1U); } } diff --git a/Document/my_document/Modbus异常码实例.md b/Document/my_document/Modbus异常码实例.md new file mode 100644 index 0000000..b82555a --- /dev/null +++ b/Document/my_document/Modbus异常码实例.md @@ -0,0 +1,81 @@ +# Modbus异常码实例 + +## 非法功能码 + +- 请求:`01 02 00 00 00 01 B9 CA` +- 请求帧长度:8字节 +- 返回帧:`01 82 01 81 60` +- 返回帧长度:5字节 +- 解释:从站未实现功能码`0x02`,返回功能码`0x82`和异常码`0x01`,表示非法功能。 + +## 03功能码读取非法地址 + +- 请求:`01 03 27 10 00 01 8F 7B` +- 请求帧长度:8字节 +- 返回帧:`01 83 02 C0 F1` +- 返回帧长度:5字节 +- 解释:起始地址`0x2710`等于10000,超出标准保持寄存器有效地址`0~9999`,返回异常码`0x02`,表示非法数据地址。 + +## 03功能码读取数量为0 + +- 请求:`01 03 00 00 00 00 45 CA` +- 请求帧长度:8字节 +- 返回帧:`01 83 03 01 31` +- 返回帧长度:5字节 +- 解释:读取寄存器数量为0,不符合功能码要求,返回异常码`0x03`,表示非法数据值。 + +## 05功能码写入非法线圈值 + +- 请求:`01 05 00 00 12 34 C0 BD` +- 请求帧长度:8字节 +- 返回帧:`01 85 03 02 91` +- 返回帧长度:5字节 +- 解释:05功能码只允许使用`FF 00`表示ON或`00 00`表示OFF,写入值`12 34`非法,返回异常码`0x03`。 + +## 06功能码写入非法地址 + +- 请求:`01 06 27 10 00 01 43 7B` +- 请求帧长度:8字节 +- 返回帧:`01 86 02 C3 A1` +- 返回帧长度:5字节 +- 解释:写入地址`0x2710`等于10000,超出标准保持寄存器有效地址`0~9999`,返回异常码`0x02`。 + +## 0F功能码字节数错误 + +- 请求:`01 0F 00 00 00 09 01 01 6E 95` +- 请求帧长度:10字节 +- 返回帧:`01 8F 03 04 31` +- 返回帧长度:5字节 +- 解释:请求写入9个线圈时应携带2个数据字节,但帧中的字节数字段为1,返回异常码`0x03`。 + +## 10功能码写入数量为0 + +- 请求:`01 10 00 00 00 00 00 09 50` +- 请求帧长度:9字节 +- 返回帧:`01 90 03 0C 01` +- 返回帧长度:5字节 +- 解释:写入寄存器数量为0,不符合功能码要求,返回异常码`0x03`。 + +## 48功能码读取非法大地址 + +- 请求:`01 48 01 11 6F 00 01 CD 69` +- 请求帧长度:9字节 +- 返回帧:`01 C8 02 F6 01` +- 返回帧长度:5字节 +- 解释:起始地址`0x01116F`等于69999,超出扩展保持寄存器有效地址`0~69998`,返回异常码`0x02`。 + +## 48功能码读取数量为0 + +- 请求:`01 48 00 00 00 00 00 04 48` +- 请求帧长度:9字节 +- 返回帧:`01 C8 03 37 C1` +- 返回帧长度:5字节 +- 解释:读取寄存器数量为0,不符合功能码要求,返回异常码`0x03`。 + +## 从站地址不匹配 + +- 请求:`02 03 00 00 00 01 84 39` +- 请求帧长度:8字节 +- 返回帧:无 +- 返回帧长度:0字节 +- 解释:当前从站地址为`0x01`,请求帧的目标从站地址为`0x02`,因此当前从站直接忽略该帧,不返回正常响应或异常响应。 diff --git a/Modbus/Inc/modbus_rtu_slave.h b/Modbus/Inc/modbus_rtu_slave.h index 04fb106..017e171 100644 --- a/Modbus/Inc/modbus_rtu_slave.h +++ b/Modbus/Inc/modbus_rtu_slave.h @@ -71,6 +71,17 @@ typedef struct uint32_t uartErrorCount; ///< HAL 串口错误计数。 } MODBUS_SLAVE_STATS; +typedef struct +{ + uint32_t tick; + + uint16_t requestLength; + uint16_t responseLength; + + uint8_t request[256]; + uint8_t response[256]; +} MODBUS_HISTORY_ITEM; + /** @brief Modbus 从站通信统计数据。 */ extern volatile MODBUS_SLAVE_STATS ModbusSlaveStatistics; @@ -82,8 +93,8 @@ extern volatile MODBUS_SLAVE_STATS ModbusSlaveStatistics; * @retval HAL_ERROR 输入参数无效。 * @retval HAL_BUSY 串口或 DMA 当前忙。 */ -HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart, - uint8_t slaveAddress); +HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart, uint8_t slaveAddress); + /** * @brief 校验并处理一帧待处理请求。 @@ -149,6 +160,13 @@ uint8_t ModbusSlaveGetCoil(uint16_t address, uint8_t *state); uint8_t ModbusSlaveIsConnected(uint32_t timeoutMs); void ModbusRetainedRegistersLoad(void); void ModbusRetainedRegistersPoll(void); +void HistorySaveToRegisters(void); +static void ModbusHistorySave( + uint32_t tick, + const uint8_t *request, + uint16_t requestLength, + const uint8_t *response, + uint16_t responseLength); #ifdef __cplusplus } #endif diff --git a/Modbus/Src/modbus_rtu_slave.c b/Modbus/Src/modbus_rtu_slave.c index e9cc5f6..6b5528c 100644 --- a/Modbus/Src/modbus_rtu_slave.c +++ b/Modbus/Src/modbus_rtu_slave.c @@ -1,5 +1,5 @@ #include "modbus_rtu_slave.h" - +#include "ucos_ii.h" #include #define MODBUS_RTU_ADU_SIZE_MAX (256U)//Modbus RTU 最大 ADU 长度,单位为字节 @@ -24,6 +24,8 @@ static UART_HandleTypeDef *ModbusUart; static uint8_t ModbusSlaveAddress; +static MODBUS_HISTORY_ITEM ModbusHistory[16]; +static uint16_t ModbusHistoryWriteIndex; /** * DMA 缓冲区只由 DMA 写入;帧缓冲区在接收回调中完成一次快照, * 随后由任务解析,避免 DMA 重启后覆盖尚未处理的数据 @@ -752,7 +754,12 @@ void ModbusSlavePoll(void) responseLength = ModbusProcessRequest(ModbusRxFrame, ModbusRxFrameLength); - + ModbusHistorySave(OSTimeGet() / 1000,ModbusRxFrame, + ModbusRxFrameLength, + ModbusTxFrame, + responseLength); + + if (responseLength > 0U) { @@ -941,3 +948,72 @@ void ModbusRetainedRegistersPoll(void) } +static void ModbusHistorySave( + uint32_t tick, + const uint8_t *request, + uint16_t requestLength, + const uint8_t *response, + uint16_t responseLength) +{ + MODBUS_HISTORY_ITEM *item; + + if(requestLength > 256U) + { + requestLength = 256U; + } + + if(responseLength > 256U) + { + responseLength = 256U; + } + + item = &ModbusHistory[ModbusHistoryWriteIndex]; + + item->tick = tick; + item->requestLength = requestLength; + item->responseLength = responseLength; + + (void)memcpy( + item->request, + request, + requestLength); + + if(responseLength > 0U) + { + (void)memcpy( + item->response, + response, + responseLength); + } + + ModbusHistoryWriteIndex++; + + if(ModbusHistoryWriteIndex >= 16U) + { + ModbusHistoryWriteIndex = 0U; + } +} +void HistorySaveToRegisters(void) +{ + // (void)memcpy( + // &ModbusHoldingRegisters[1000], + // ModbusHistory, + // sizeof(ModbusHistory)); + + uint16_t index; + + if(ModbusHistoryWriteIndex == 0U) + { + index = 15U; + } + else + { + index = ModbusHistoryWriteIndex - 1U; + } + + (void)memcpy( + &ModbusHoldingRegisters[ + 1000U + index * 260U], + &ModbusHistory[index], + sizeof(ModbusHistory[index])); +} \ No newline at end of file diff --git a/Touchwin/工程11.txp b/Touchwin/工程11.txp index ba65d7c..16ea9fa 100644 Binary files a/Touchwin/工程11.txp and b/Touchwin/工程11.txp differ