Quellcode durchsuchen

更新了测试报告

deepseek
ywh vor 1 Monat
Ursprung
Commit
3b0ea45b7b
5 geänderte Dateien mit 250 neuen und 109 gelöschten Zeilen
  1. +141
    -0
      Document/my_document/Modbus RTU最大长度ADU测试.md
  2. BIN
      Document/my_document/测试报告.docx
  3. +48
    -48
      Modbus/Inc/modbus_rtu_slave.h
  4. +61
    -61
      Modbus/Src/modbus_rtu_slave.c
  5. BIN
      Touchwin/工程11.txp

+ 141
- 0
Document/my_document/Modbus RTU最大长度ADU测试.md Datei anzeigen

@@ -0,0 +1,141 @@
# Modbus RTU最大长度ADU测试

串口助手请选择HEX发送。下列报文已经完整展开,可以直接复制。

测试条件:

- 从站地址为`0x01`
- 先执行0x0F写线圈,再执行0x01读线圈
- 先执行0x10写保持寄存器,再执行0x03读保持寄存器
- 0x10和0x03使用D6000起始地址,避免覆盖掉电保持区和通信历史区
- 文档中的全零读取响应以相关线圈和保持寄存器初始值均为0为前提
- 0x0F一次最多写1968个线圈,不能单次清零全部2000个待读线圈;测试0x01前还应确认线圈1968~1999为0
- 0x10一次最多写123个寄存器,不能单次清零全部125个待读寄存器;测试0x03前还应确认D6123~D6124为0

## 0x0F写入1968个线圈

含义:

- `01`:从站地址
- `0F`:写多个线圈功能码
- `00 00`:起始线圈地址0
- `07 B0`:写入数量1968
- `F6`:后续线圈数据长度246字节
- 连续246个`00`:将线圈0~1967全部写为OFF
- `A6 FE`:CRC低字节、CRC高字节
- 测试目的:用255字节合法请求帧检查DMA接收缓冲区边界和最大线圈写入数量

请求帧长度:255字节

请求帧:

```text
01 0F 00 00 07 B0 F6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A6 FE
```

预期响应帧长度:8字节

预期响应帧:

```text
01 0F 00 00 07 B0 56 4F
```

## 0x01读取2000个线圈

含义:

- `01`:从站地址
- `01`:读线圈功能码
- `00 00`:起始线圈地址0
- `07 D0`:读取数量2000
- `3F A6`:CRC低字节、CRC高字节
- 响应中的`FA`表示后续包含250字节线圈状态,因为`2000 ÷ 8 = 250`
- 响应中的250个`00`表示线圈0~1999全部为OFF
- `F5 AF`:全零响应对应的CRC低字节、CRC高字节
- 测试目的:检查最大线圈读取数量以及255字节响应帧的DMA发送

请求帧长度:8字节

请求帧:

```text
01 01 00 00 07 D0 3F A6
```

预期响应帧长度:255字节

预期响应帧:

```text
01 01 FA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F5 AF
```

## 0x10写入123个保持寄存器

含义:

- `01`:从站地址
- `10`:写多个保持寄存器功能码
- `17 70`:起始地址6000,即D6000
- `00 7B`:写入数量123
- `F6`:后续寄存器数据长度246字节
- 连续246个`00`:将D6000~D6122全部写为0
- `76 06`:CRC低字节、CRC高字节
- 正常响应回显起始地址`17 70`和写入数量`00 7B`
- 测试目的:用255字节合法请求帧检查DMA接收缓冲区边界和最大寄存器写入数量

请求帧长度:255字节

请求帧:

```text
01 10 17 70 00 7B F6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 06
```

预期响应帧长度:8字节

预期响应帧:

```text
01 10 17 70 00 7B 84 45
```

## 0x03读取125个保持寄存器

含义:

- `01`:从站地址
- `03`:读保持寄存器功能码
- `17 70`:起始地址6000,即D6000
- `00 7D`:读取数量125
- `81 84`:CRC低字节、CRC高字节
- 响应中的`FA`表示后续包含250字节寄存器数据,因为`125 × 2 = 250`
- 响应中的250个`00`表示D6000~D6124全部为0
- `08 E8`:全零响应对应的CRC低字节、CRC高字节
- 测试目的:检查最大保持寄存器读取数量以及255字节响应帧的DMA发送

请求帧长度:8字节

请求帧:

```text
01 03 17 70 00 7D 81 84
```

预期响应帧长度:255字节

预期响应帧:

```text
01 03 FA 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 E8
```

## 检查项

- 0x0F和0x10请求的`ModbusRxFrameLength`应为255
- 0x01和0x03正常响应的`responseLength`应为255
- `droppedFrameCount`不应增加
- `uartErrorCount`不应增加
- 不应发生HardFault、DMA越界或接收停止
- 完成255字节帧后,下一帧仍应正常通信

BIN
Document/my_document/测试报告.docx Datei anzeigen


+ 48
- 48
Modbus/Inc/modbus_rtu_slave.h Datei anzeigen

@@ -9,10 +9,10 @@ extern "C"
#endif

/**
* @brief Modbus 数据模型的最大地址
* @brief Modbus 数据模型的最大地址
*
* 任务要求规定线圈和保持寄存器地址范围均为 0~0x270F,
* 因此每种数据共有 10000 项
* 因此每种数据共有 10000 项
*/
#define MODBUS_MAP_LAST_ADDRESS (0x270FU)//保持寄存器或线圈地址
#define MODBUS_MAP_ITEM_COUNT (0x2710U)//保持寄存器或线圈数量
@@ -24,9 +24,9 @@ extern "C"
#define MODBUS_CONNECTION_TIMEOUT_MS (1000U)

/**
* @brief 与 TouchWin 触摸屏联调使用的演示地址
* @brief 与 TouchWin 触摸屏联调使用的演示地址
*
* 可以直接访问以下地址
* 可以直接访问以下地址
*/
#define HMI_REG_DEVICE_ID (0U)
#define HMI_REG_UPTIME_SECONDS (1U)
@@ -55,20 +55,20 @@ static volatile MODBUS_BACKUP_DATA *backupData =(volatile MODBUS_BACKUP_DATA *)B


/**
* @brief Modbus 从站通信统计信息
* @brief Modbus 从站通信统计信息
*/
typedef struct
{
uint32_t rxEventCount; ///< 串口接收事件总数
uint32_t validFrameCount; ///< CRC 和从站地址均有效的帧数
uint32_t txFrameCount; ///< 成功启动 DMA 发送的帧数
uint32_t crcErrorCount; ///< CRC 校验错误帧数
uint32_t ignoredAddressCount; ///< 因从站地址不匹配而忽略的帧数
uint32_t illegalFunctionCount; ///< 非法功能码计数
uint32_t illegalAddressCount; ///< 非法数据地址计数
uint32_t illegalValueCount; ///< 非法数据值计数
uint32_t droppedFrameCount; ///< 接收槽占用或长度错误导致的丢帧数
uint32_t uartErrorCount; ///< HAL 串口错误计数
uint32_t rxEventCount; ///< 串口接收事件总数
uint32_t validFrameCount; ///< CRC 和从站地址均有效的帧数
uint32_t txFrameCount; ///< 成功启动 DMA 发送的帧数
uint32_t crcErrorCount; ///< CRC 校验错误帧数
uint32_t ignoredAddressCount; ///< 因从站地址不匹配而忽略的帧数
uint32_t illegalFunctionCount; ///< 非法功能码计数
uint32_t illegalAddressCount; ///< 非法数据地址计数
uint32_t illegalValueCount; ///< 非法数据值计数
uint32_t droppedFrameCount; ///< 接收槽占用或长度错误导致的丢帧数
uint32_t uartErrorCount; ///< HAL 串口错误计数
} MODBUS_SLAVE_STATS;

typedef struct
@@ -82,80 +82,80 @@ typedef struct
uint8_t response[256];
} MODBUS_HISTORY_ITEM;

/** @brief Modbus 从站通信统计数据 */
/** @brief Modbus 从站通信统计数据 */
extern volatile MODBUS_SLAVE_STATS ModbusSlaveStatistics;

/**
* @brief 初始化 Modbus 从站并启动 USART DMA 空闲接收
* @param[in] huart 已由 HAL 初始化完成的串口句柄
* @param[in] slaveAddress 从站地址,有效范围为 1~247
* @retval HAL_OK 初始化成功且 DMA 接收已启动
* @retval HAL_ERROR 输入参数无效
* @retval HAL_BUSY 串口或 DMA 当前忙
* @brief 初始化 Modbus 从站并启动 USART DMA 空闲接收
* @param[in] huart 已由 HAL 初始化完成的串口句柄
* @param[in] slaveAddress 从站地址,有效范围为 1~247
* @retval HAL_OK 初始化成功且 DMA 接收已启动
* @retval HAL_ERROR 输入参数无效
* @retval HAL_BUSY 串口或 DMA 当前忙
*/
HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart, uint8_t slaveAddress);

/**
* @brief 校验并处理一帧待处理请求
* @brief 校验并处理一帧待处理请求
*
* 本函数应在 uC/OS-II 任务中周期调用中断只负责接收数据,
* CRC 校验、协议解析和响应发送均在任务上下文中执行
* 本函数应在 uC/OS-II 任务中周期调用中断只负责接收数据,
* CRC 校验、协议解析和响应发送均在任务上下文中执行
*/
void ModbusSlavePoll(void);

/**
* @brief 处理 HAL 串口 DMA 接收事件
* @param[in] huart 产生接收事件的串口句柄
* @param[in] size 本次接收到的字节数
* @brief 处理 HAL 串口 DMA 接收事件
* @param[in] huart 产生接收事件的串口句柄
* @param[in] size 本次接收到的字节数
*/
void ModbusSlaveOnRxEvent(UART_HandleTypeDef *huart, uint16_t size);

/**
* @brief 处理 HAL 串口 DMA 发送完成事件
* @param[in] huart 完成发送的串口句柄
* @brief 处理 HAL 串口 DMA 发送完成事件
* @param[in] huart 完成发送的串口句柄
*/
void ModbusSlaveOnTxComplete(UART_HandleTypeDef *huart);

/**
* @brief 处理 HAL 串口错误事件并恢复接收
* @param[in] huart 发生错误的串口句柄
* @brief 处理 HAL 串口错误事件并恢复接收
* @param[in] huart 发生错误的串口句柄
*/
void ModbusSlaveOnUartError(UART_HandleTypeDef *huart);

/**
* @brief 写入一个保持寄存器
* @param[in] address 保持寄存器地址
* @param[in] value 待写入的 16 位数据
* @brief 写入一个保持寄存器
* @param[in] address 保持寄存器地址
* @param[in] value 待写入的 16 位数据
*/
uint8_t ModbusSlaveSetHoldingRegister(uint16_t address, uint16_t value);

/**
* @brief 读取一个保持寄存器
* @param[in] address 保持寄存器地址
* @param[out] value 用于保存读取结果的指针
* @brief 读取一个保持寄存器
* @param[in] address 保持寄存器地址
* @param[out] value 用于保存读取结果的指针
*/
uint8_t ModbusSlaveGetHoldingRegister(uint16_t address, uint16_t *value);

/**
* @brief 设置一个线圈的状态
* @param[in] address 线圈地址
* @param[in] state 0 表示复位,非 0 表示置位
* @brief 设置一个线圈的状态
* @param[in] address 线圈地址
* @param[in] state 0 表示复位,非 0 表示置位
*/
uint8_t ModbusSlaveSetCoil(uint16_t address, uint8_t state);

/**
* @brief 读取一个线圈的状态
* @param[in] address 线圈地址
* @param[out] state 用于保存线圈状态的指针,结果为 0 或 1
* @brief 读取一个线圈的状态
* @param[in] address 线圈地址
* @param[out] state 用于保存线圈状态的指针,结果为 0 或 1
*/
uint8_t ModbusSlaveGetCoil(uint16_t address, uint8_t *state);

/**
* @brief 判断指定时间内是否收到过有效请求
* @param[in] timeoutMs 连接超时时间,单位为毫秒
* @retval 1 从站在指定时间内收到过有效请求
* @retval 0 尚未收到有效请求或连接已经超时
* @brief 判断指定时间内是否收到过有效请求
* @param[in] timeoutMs 连接超时时间,单位为毫秒
* @retval 1 从站在指定时间内收到过有效请求
* @retval 0 尚未收到有效请求或连接已经超时
*/
uint8_t ModbusSlaveIsConnected(uint32_t timeoutMs);
void ModbusRetainedRegistersLoad(void);


+ 61
- 61
Modbus/Src/modbus_rtu_slave.c Datei anzeigen

@@ -110,9 +110,9 @@ static uint32_t ModbusGetU24Be(const uint8_t *data)
}

/**
* @brief 检查连续数据地址范围是否合法
* @param[in] start 起始地址
* @param[in] quantity 数据项数量
* @brief 检查连续数据地址范围是否合法
* @param[in] start 起始地址
* @param[in] quantity 数据项数量
*/
static uint8_t ModbusAddressRangeIsValid(uint16_t start, uint16_t quantity)
{
@@ -126,9 +126,9 @@ static uint8_t ModbusAddressRangeIsValid(uint16_t start, uint16_t quantity)
}

/**
* @brief 读取已经确认地址合法的线圈
* @param[in] address 线圈地址
* @return 线圈状态,取值为 0 或 1
* @brief 读取已经确认地址合法的线圈
* @param[in] address 线圈地址
* @return 线圈状态,取值为 0 或 1
*/
static uint8_t ModbusCoilGetUnchecked(uint16_t address)
{
@@ -138,9 +138,9 @@ static uint8_t ModbusCoilGetUnchecked(uint16_t address)
}

/**
* @brief 设置已经确认地址合法的线圈
* @param[in] address 线圈地址
* @param[in] state 0 表示复位,非 0 表示置位
* @brief 设置已经确认地址合法的线圈
* @param[in] address 线圈地址
* @param[in] state 0 表示复位,非 0 表示置位
*/
static void ModbusCoilSetUnchecked(uint16_t address, uint8_t state)
{
@@ -157,10 +157,10 @@ static void ModbusCoilSetUnchecked(uint16_t address, uint8_t state)
}

/**
* @brief 启动 USART DMA 空闲接收
* @retval HAL_OK DMA 接收启动成功
* @retval HAL_BUSY 串口未配置或发送尚未结束
* @return 其他 HAL 状态表示 DMA 接收启动失败
* @brief 启动 USART DMA 空闲接收
* @retval HAL_OK DMA 接收启动成功
* @retval HAL_BUSY 串口未配置或发送尚未结束
* @return 其他 HAL 状态表示 DMA 接收启动失败
*/
static HAL_StatusTypeDef ModbusStartReceive(void)
{
@@ -178,8 +178,8 @@ static HAL_StatusTypeDef ModbusStartReceive(void)
if ((status == HAL_OK) && (ModbusUart->hdmarx != NULL))
{
/*
* 普通 Modbus 帧只应在 IDLE 或缓冲区满时交给应用
* 关闭 DMA 半传输中断,避免长帧在一半位置被误认为完整帧
* 普通 Modbus 帧只应在 IDLE 或缓冲区满时交给应用
* 关闭 DMA 半传输中断,避免长帧在一半位置被误认为完整帧
*/
__HAL_DMA_DISABLE_IT(ModbusUart->hdmarx, DMA_IT_HT);
}
@@ -190,24 +190,24 @@ static HAL_StatusTypeDef ModbusStartReceive(void)


/**
* @brief 在 RTU 帧末尾追加 CRC 低字节和高字节
* @param[in,out] frame 待追加 CRC 的帧缓冲区
* @param[in] payloadLength 不包含 CRC 的有效载荷长度
* @brief 在 RTU 帧末尾追加 CRC 低字节和高字节
* @param[in,out] frame 待追加 CRC 的帧缓冲区
* @param[in] payloadLength 不包含 CRC 的有效载荷长度
*/
static void ModbusAppendCrc(uint8_t *frame, uint16_t payloadLength)
{
uint16_t crc = ModbusCrc16(frame, payloadLength);

/* Modbus RTU 在线路上传输 CRC 低字节在前、高字节在后 */
/* Modbus RTU 在线路上传输 CRC 低字节在前、高字节在后 */
frame[payloadLength] = (uint8_t)(crc & 0x00FFU);
frame[payloadLength + 1U] = (uint8_t)(crc >> 8U);
}

/**
* @brief 构造 Modbus 异常响应
* @param[in] function 请求功能码
* @param[in] exception 异常码
* @return 异常响应 ADU 长度
* @brief 构造 Modbus 异常响应
* @param[in] function 请求功能码
* @param[in] exception 异常码
* @return 异常响应 ADU 长度
*/
static uint16_t ModbusBuildException(uint8_t function, uint8_t exception)
{
@@ -338,11 +338,11 @@ static uint16_t ModbusProcessReadHolding(const uint8_t *request,uint16_t request
}

/**
* @brief 处理写单个保持寄存器功能码 0x06
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
* @brief 处理写单个保持寄存器功能码 0x06
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
*/
static uint16_t ModbusProcessWriteSingleRegister(
const uint8_t *request,
@@ -376,18 +376,18 @@ static uint16_t ModbusProcessWriteSingleRegister(
return 0U;
}

/* 0x06 的正常响应必须原样回显请求的前 6 个字节 */
/* 0x06 的正常响应必须原样回显请求的前 6 个字节 */
(void)memcpy(ModbusTxFrame, request, 6U);
ModbusAppendCrc(ModbusTxFrame, 6U);
return 8U;
}

/**
* @brief 处理写单个线圈功能码 0x05
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
* @brief 处理写单个线圈功能码 0x05
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
*/
static uint16_t ModbusProcessWriteSingleCoil(
const uint8_t *request,
@@ -409,7 +409,7 @@ static uint16_t ModbusProcessWriteSingleCoil(

/*
* 0x05 只接受 0xFF00(线圈置位)和 0x0000(线圈复位);
* 其他数值属于非法数据值
* 其他数值属于非法数据值
*/
if ((value != MODBUS_COIL_VALUE_ON)
&& (value != MODBUS_COIL_VALUE_OFF))
@@ -435,18 +435,18 @@ static uint16_t ModbusProcessWriteSingleCoil(
return 0U;
}

/* 0x05 正常应答原样回显请求的前 6 个字节,再追加 CRC */
/* 0x05 正常应答原样回显请求的前 6 个字节,再追加 CRC */
(void)memcpy(ModbusTxFrame, request, 6U);
ModbusAppendCrc(ModbusTxFrame, 6U);
return 8U;
}

/**
* @brief 处理写多个线圈功能码 0x0F
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
* @brief 处理写多个线圈功能码 0x0F
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
*/
static uint16_t ModbusProcessWriteMultipleCoils(
const uint8_t *request,
@@ -511,11 +511,11 @@ static uint16_t ModbusProcessWriteMultipleCoils(
}

/**
* @brief 处理写多个保持寄存器功能码 0x10
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
* @brief 处理写多个保持寄存器功能码 0x10
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @param[in] isBroadcast 非 0 表示当前请求为广播
* @return 单播响应长度;广播或无法响应时返回 0
*/
static uint16_t ModbusProcessWriteMultipleRegisters(
const uint8_t *request,
@@ -590,7 +590,7 @@ static uint16_t ModbusProcessReadBigHolding(
uint16_t index;
uint16_t value;

/* 请求帧:站号1 + 功能码1 + 地址3 + 数量2 + CRC2 */
/* 请求帧:站号1 + 功能码1 + 地址3 + 数量2 + CRC2 */
if (requestLength != 9U)
{
ModbusSlaveStatistics.illegalValueCount++;
@@ -600,11 +600,11 @@ static uint16_t ModbusProcessReadBigHolding(
MODBUS_EX_ILLEGAL_VALUE);
}

/* 提取24位起始地址和16位寄存器数量 */
/* 提取24位起始地址和16位寄存器数量 */
start = ModbusGetU24Be(&request[2]);
quantity = ModbusGetU16Be(&request[5]);

/* 一次最多读取125个寄存器 */
/* 一次最多读取125个寄存器 */
if ((quantity == 0U) ||
(quantity > MODBUS_READ_REGS_MAX))
{
@@ -617,7 +617,7 @@ static uint16_t ModbusProcessReadBigHolding(

/*
* 普通SRAM有40000个寄存器,CCMRAM有29999个寄存器,
* 总地址范围为0~69998
* 总地址范围为0~69998
*/
if ((start >= 69999UL) || ((uint32_t)quantity > (69999UL - start)))
@@ -629,7 +629,7 @@ static uint16_t ModbusProcessReadBigHolding(
}

/* 组成正常响应帧头 */
/* 组成正常响应帧头 */
ModbusTxFrame[0] = ModbusSlaveAddress;
ModbusTxFrame[1] = 0x48U;
ModbusTxFrame[2] = (uint8_t)(quantity * 2U);
@@ -640,7 +640,7 @@ static uint16_t ModbusProcessReadBigHolding(

/*
* 地址0~39999位于普通SRAM;
* 地址40000~69998位于CCMRAM
* 地址40000~69998位于CCMRAM
*/
if (currentAddress < 40000UL)
{
@@ -652,22 +652,22 @@ static uint16_t ModbusProcessReadBigHolding(
}

/* 每个寄存器按照高字节、低字节装入响应帧 */
/* 每个寄存器按照高字节、低字节装入响应帧 */
ModbusTxFrame[3U + index * 2U] = (uint8_t)(value >> 8U);
ModbusTxFrame[4U + index * 2U] = (uint8_t)(value & 0x00FFU);
}
/* 添加CRC */
/* 添加CRC */
ModbusAppendCrc( ModbusTxFrame, (uint16_t)(3U + quantity * 2U));
return (uint16_t)(5U + quantity * 2U);
}

/**
* @brief 校验并分发一帧 Modbus RTU 请求
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @return 待发送响应长度;无需响应时返回 0
* @brief 校验并分发一帧 Modbus RTU 请求
* @param[in] request RTU 请求帧
* @param[in] requestLength 请求帧长度
* @return 待发送响应长度;无需响应时返回 0
*/
static uint16_t ModbusProcessRequest(const uint8_t *request,uint16_t requestLength)
{
@@ -706,7 +706,7 @@ static uint16_t ModbusProcessRequest(const uint8_t *request,uint16_t requestLeng
switch (request[1])
{
case 0X01U://读线圈
// 广播请求不允许读取,从站不作响应
// 广播请求不允许读取,从站不作响应
return (isBroadcast != 0U) ? 0U :
ModbusProcessReadCoils(request, requestLength);

@@ -798,7 +798,7 @@ void ModbusSlavePoll(void)
}

/*
* 当前帧;处理完成后再释放帧槽
* 当前帧;处理完成后再释放帧槽
*/
ModbusRxFrameReady = 0U;
}
@@ -936,7 +936,7 @@ void ModbusRetainedRegistersLoad(void)

/*
* 数据初始化完成后最后写magic,避免初始化中途断电
* 却把不完整数据标记成有效
* 却把不完整数据标记成有效
*/
backupData->magic = MODBUS_BACKUP_MAGIC;
}


BIN
Touchwin/工程11.txp Datei anzeigen


Laden…
Abbrechen
Speichern