Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 

9.3 KiB

TouchWin 自组 Modbus RTU 附加功能

1. 功能定义

标准功能码仍为 0x010x030x050x060x0F0x10。线圈和保持寄存器地址范围均为 0x0000..0x270F

以下三个功能码是本训练项目的私有扩展,不属于 Modbus 国标,只能由本项目 TouchWin 与 PLC 配套使用:

功能码 用途 请求数据 限制
0x41 读取 0x00010000 32 位地址、16 位数量 地址固定为 0x10000,数量固定为 1
0x42 写入 0x00010000 32 位地址、16 位写入值 地址固定为 0x10000,正常响应回显地址和值
0x43 读取奇数地址的寄存器 16 位起始基准地址、16 位数量 数量为 1..123 中的奇数

0x43 按地址 +2 跳读,只返回奇数地址的值。起始基准地址会自动向上取奇数:基准地址为 0、数量为 123 时,读取地址 1, 3, 5, ..., 245;基准地址为 10 时,读取 11, 13, 15, ...。数量表示返回值个数,仍必须是奇数。

2. TouchWin 地址

PSW319 为状态码,PSW320 为实际接收长度。附加画面使用:

用途 PSW
0x41 读取结果 PSW350
0x42 写入值 PSW351
0x43 起始基准地址、数量 PSW370PSW371
0x43 结果 PSW372..PSW494,共 123 个 WORD

PSW371 只能输入奇数,最大 123PSW370 = 0 时,PSW372 对应 PLC 的 D1PSW373 对应 D3,依次类推;PSW370 = 10 时,结果依次对应 D11D13D15。若要在一个画面显示全部批量读取结果,需要 123 个数值显示组件,依次绑定 PSW372PSW494。用于演示时,可以只放前 8 或前 16 个显示组件,全部 123 个结果仍会写入 PSW。

状态码:0 成功;1 输入错误;2 发送失败;3 接收失败;4 CRC 错误;5 应答错误;0x8000 以上表示异常应答,低字节为异常码。

3. 公共定义

#define MODBUS_SLAVE_ADDRESS                    (1)
#define MODBUS_FUNCTION_READ_EXTENDED_REGISTER  (0x41)
#define MODBUS_FUNCTION_WRITE_EXTENDED_REGISTER (0x42)
#define MODBUS_FUNCTION_READ_ODD_COUNT_REGS     (0x43)
#define MODBUS_ODD_COUNT_MAX                    (123)
#define MODBUS_MIN_RESPONSE_LENGTH               (5)
#define MODBUS_ADDRESS_MAX                       (0x270F)

#define PSW_STATUS                               (319)
#define PSW_RECEIVE_LENGTH                       (320)
#define PSW_EXTENDED_RESULT                      (350)
#define PSW_EXTENDED_WRITE_VALUE                 (351)
#define PSW_ODD_START_ADDRESS                    (370)
#define PSW_ODD_COUNT                            (371)
#define PSW_ODD_RESULTS                          (372)

以下示例使用已有的 ModbusAppendCrcModbusSendReceiveModbusCheckResponse 公共函数。

TouchWin 粘贴规则:以上公共定义和公共函数写入“公共函数”页。以下四段代码写入“函数功能块”中新建的功能函数编辑区,只粘贴代码块内部内容,不要写 void 函数名(void),也不要写最外层的 {}。功能函数名称必须是合法 C 标识符,不能使用 0x410x420x43 作为函数名。

请依次新建并命名为:ReadExtendedRegisterWriteExtendedRegisterClearExtendedResultReadOddCountRegisters。其中 0x410x420x43 只用于 request[1] 中的 Modbus 功能码。

4. ReadExtendedRegister0x41 读取 0x10000

地址和数量固定,不在画面输入:

WORD receiveLength;
WORD status;
BYTE request[10];
BYTE response[7];

request[0] = MODBUS_SLAVE_ADDRESS;
request[1] = MODBUS_FUNCTION_READ_EXTENDED_REGISTER;
request[2] = 0x00;
request[3] = 0x01;
request[4] = 0x00;
request[5] = 0x00;
request[6] = 0x00;
request[7] = 0x01;
ModbusAppendCrc(request, 8);

receiveLength = 0;
status = ModbusSendReceive(request, 10, response, 7, &receiveLength);
if (status == MODBUS_STATUS_OK)
{
    status = ModbusCheckResponse(response, receiveLength,
                                 MODBUS_FUNCTION_READ_EXTENDED_REGISTER);
}
if ((status == MODBUS_STATUS_OK) &&
    ((receiveLength != 7) || (response[2] != 2)))
{
    status = MODBUS_STATUS_RESPONSE_ERROR;
}
if (status == MODBUS_STATUS_OK)
{
    PSW[PSW_EXTENDED_RESULT] = ((WORD)response[3] << 8) | response[4];
}
PSW[PSW_STATUS] = status;
PSW[PSW_RECEIVE_LENGTH] = receiveLength;

5. WriteExtendedRegister0x42 写入 0x10000

写入值从 PSW351 取得。请求和正常响应均为 10 字节,正常响应回显 32 位地址与 16 位写入值:

WORD receiveLength;
WORD status;
WORD writeValue;
BYTE request[10];
BYTE response[10];

writeValue = PSW[PSW_EXTENDED_WRITE_VALUE];
request[0] = MODBUS_SLAVE_ADDRESS;
request[1] = MODBUS_FUNCTION_WRITE_EXTENDED_REGISTER;
request[2] = 0x00;
request[3] = 0x01;
request[4] = 0x00;
request[5] = 0x00;
request[6] = (BYTE)(writeValue >> 8);
request[7] = (BYTE)writeValue;
ModbusAppendCrc(request, 8);

receiveLength = 0;
status = ModbusSendReceive(request, 10, response, 10, &receiveLength);
if (status == MODBUS_STATUS_OK)
{
    status = ModbusCheckResponse(response, receiveLength,
                                 MODBUS_FUNCTION_WRITE_EXTENDED_REGISTER);
}
if ((status == MODBUS_STATUS_OK) &&
    ((receiveLength != 10) || (response[2] != request[2]) ||
     (response[3] != request[3]) || (response[4] != request[4]) ||
     (response[5] != request[5]) || (response[6] != request[6]) ||
     (response[7] != request[7])))
{
    status = MODBUS_STATUS_RESPONSE_ERROR;
}
PSW[PSW_STATUS] = status;
PSW[PSW_RECEIVE_LENGTH] = receiveLength;

PLC 收到并成功处理 0x42 后,会将 0x10000 的最新值保存到 RTC 备份区。

6. ClearExtendedResult:清除读取显示

清除按钮绑定以下函数。该函数只将触摸屏上的读取结果清零,不发送通信帧,不修改 PLC 的 0x10000,也不触发掉电保存:

PSW[PSW_EXTENDED_RESULT] = 0;

用于验证掉电保持时,操作顺序为:使用 0x42 写入非零值,调用清除函数,PLC 断电再上电,最后使用 0x41 读取;若读回原写入值,则掉电保持生效。

7. ReadOddCountRegisters0x43 读取奇数地址寄存器

起始基准地址可以是任意合法地址,PLC 会从第一个不小于该值的奇数地址开始,每次地址加 2。数量必须为奇数且不超过 123。响应容量为 251 字节,满足 123 个 WORD 的数据:

WORD startAddress;
WORD firstOddAddress;
WORD registerCount;
WORD registerOffset;
WORD receiveLength;
WORD expectedLength;
WORD status;
BYTE request[8];
BYTE response[251];

startAddress = PSW[PSW_ODD_START_ADDRESS];
firstOddAddress = (WORD)(startAddress | 0x0001);
registerCount = PSW[PSW_ODD_COUNT];
receiveLength = 0;
status = MODBUS_STATUS_INPUT_ERROR;

if ((registerCount != 0) && (registerCount <= MODBUS_ODD_COUNT_MAX) &&
    ((registerCount & 1) != 0) &&
    (firstOddAddress <= MODBUS_ADDRESS_MAX) &&
    (registerCount <= (((MODBUS_ADDRESS_MAX - firstOddAddress) / 2) + 1)))
{
    request[0] = MODBUS_SLAVE_ADDRESS;
    request[1] = MODBUS_FUNCTION_READ_ODD_COUNT_REGS;
    request[2] = (BYTE)(startAddress >> 8);
    request[3] = (BYTE)startAddress;
    request[4] = (BYTE)(registerCount >> 8);
    request[5] = (BYTE)registerCount;
    ModbusAppendCrc(request, 6);

    expectedLength = MODBUS_MIN_RESPONSE_LENGTH + (registerCount * 2);
    status = ModbusSendReceive(request, 8, response, expectedLength,
                               &receiveLength);
    if (status == MODBUS_STATUS_OK)
    {
        status = ModbusCheckResponse(response, receiveLength,
                                     MODBUS_FUNCTION_READ_ODD_COUNT_REGS);
    }
    if ((status == MODBUS_STATUS_OK) &&
        ((receiveLength != expectedLength) ||
         (response[2] != (BYTE)(registerCount * 2))))
    {
        status = MODBUS_STATUS_RESPONSE_ERROR;
    }
    if (status == MODBUS_STATUS_OK)
    {
        for (registerOffset = 0; registerOffset < registerCount;
             registerOffset++)
        {
            PSW[PSW_ODD_RESULTS + registerOffset] =
                ((WORD)response[3 + (registerOffset * 2)] << 8) |
                response[4 + (registerOffset * 2)];
        }
    }
}
PSW[PSW_STATUS] = status;
PSW[PSW_RECEIVE_LENGTH] = receiveLength;

示例请求:起始基准地址 0、数量 123 的请求数据为 00 00 00 7B,响应数据字节数为 246,返回地址为 1, 3, 5, ..., 245。若数量为 122124,PLC 返回异常码 03;若最后一个奇数地址越过 0x270F,返回异常码 02

8. RTC 断电保持

不设置保存或恢复按钮。仅私有写操作 0x42 成功后,PLC 自动将固定寄存器 0x10000 写入 RTC 备份寄存器;启动时校验通过则自动恢复。保持寄存器 0..31 和线圈 0..15 均不保存、不恢复,也不会被 RTC 旧值覆盖。

STM32F407 的 RTC 备份区只有 20 个 32 位寄存器,不能保存完整的 10000 个寄存器和线圈。实际掉电保持还要求 PLC 板的 VBAT 电池已经接入;没有 VBAT 时,RTC 备份数据也会丢失。

9. 联调帧

读取 0x10000:01 41 00 01 00 00 00 01 2C C3
写入 0x10000:01 42 00 01 00 00 <value_hi> <value_lo> CRC_L CRC_H
读取 1, 3, ..., 245:01 43 00 00 00 7B CRC_L CRC_H

0x43 每次按钮操作只发送一帧,最多处理 123 个奇数地址寄存器。