通过modbustcp获取三菱FX3U M0-M29寄存器的状态,但是有数据传入就崩溃退出,帮忙看下是哪里的原因:
事件 客户1.收到数据(源对象 为 客户,数据值 为 字节型[])
变量 位号 为 整数型
变量 字节号 为 整数型
变量 字节值 为 整数型
变量 buf 为 字节型[]={0,0,0,0}
' 先取出Modbus返回的4个数据字节
buf[0] = 数据值[9]
buf[1] = 数据值[10]
buf[2] = 数据值[11]
buf[3] = 数据值[12]
变量循环(i = 0,29,1)
字节号 = i / 8
位号 = i % 8
字节值 = 到整数(buf[字节号])
M状态[i] = 假
如果(位号 == 0 且 (字节值%2)>=1)
M状态[i] = 真
否则 如果(位号 == 1 且 (字节值%4)>=2)
M状态[i] = 真
否则 如果(位号 == 2 且 (字节值%8)>=4)
M状态[i] = 真
否则 如果(位号 == 3 且 (字节值%16)>=8)
M状态[i] = 真
否则 如果(位号 == 4 且 (字节值%32)>=16)
M状态[i] = 真
否则 如果(位号 == 5 且 (字节值%64)>=32)
M状态[i] = 真
否则 如果(位号 == 6 且 (字节值%128)>=64)
M状态[i] = 真
否则 如果(位号 == 7 且 (字节值%256)>=128)
M状态[i] = 真
结束 如果
结束循环
结束 事件
修正版代码:
事件 客户1.收到数据(源对象 为 客户,数据值 为 字节型[])
变量 位号 为 整数型
变量 字节号 为 整数型
变量 字节值 为 整数型
变量 buf 为 字节型[]={0,0,0,0}
' 安全判断,防止数据太短崩溃
如果 (取字节集长度(数据值) < 11)
返回
结束 如果
' 正确取4个字节(从第8字节开始)
buf[0] = 数据值[7]
buf[1] = 数据值[8]
buf[2] = 数据值[9]
buf[3] = 数据值[10]
' 循环读取 M0 ~ M29(共30位)
变量循环(i = 0,29,1)
字节号 = i / 8
位号 = i % 8
字节值 = 到整数(buf[字节号])
M状态[i] = 假
如果(位号 == 0 且 (字节值 % 2)>=1)
M状态[i] = 真
否则 如果(位号 == 1 且 (字节值 % 4)>=2)
M状态[i] = 真
否则 如果(位号 == 2 且 (字节值 % 8)>=4)
M状态[i] = 真
否则 如果(位号 == 3 且 (字节值 % 16)>=8)
M状态[i] = 真
否则 如果(位号 == 4 且 (字节值 % 32)>=16)
M状态[i] = 真
否则 如果(位号 == 5 且 (字节值 % 64)>=32)
M状态[i] = 真
否则 如果(位号 == 6 且 (字节值 % 128)>=64)
M状态[i] = 真
否则 如果(位号 == 7 且 (字节值 % 256)>=128)
M状态[i] = 真
结束 如果
结束循环
结束 事件
你读取 M0~M29,一共 30 个位
需要的字节数 = 30 / 8 = 3.75 → 4字节你写的是:
buf[0] = 数据值[9]
buf[1] = 数据值[10]
buf[2] = 数据值[11]
buf[3] = 数据值[12]
Modbus TCP 响应报文格式不是这样的!
正常 Modbus TCP 读线圈(读 M)响应:
你硬写死取 9、10、11、12,一旦返回数据长度不够,直接数组越界崩溃!
你用 %2、%4、%8... 这种写法完全没必要,而且逻辑不标准,容易算错。
设备返回错误码时,你直接取数据,必崩溃。
事件 客户1.收到数据(源对象 为 客户,数据值 为 字节型[])
变量 位号 为 整数型
变量 字节号 为 整数型
变量 字节值 为 整数型
变量 数据长度 为 整数型
' 安全判断:防止数据太短直接崩溃
如果 (取字节集长度(数据值) < 8)
' 数据不完整,直接退出,不崩溃
返回
结束 如果
' Modbus TCP 标准解析:第7字节 = 后续数据长度(读M/线圈返回的字节数)
数据长度 = 到整数(数据值[6])
如果 (数据长度 < 4)
' 不够4字节,退出 返回
结束 如果
' 正确取4个字节(从第8字节开始)
变量 buf 为 字节型[] = {0,0,0,0}
buf[0] = 数据值[7]
buf[1] = 数据值[8]
buf[2] = 数据值[9]
buf[3] = 数据值[10]
' 循环读取 M0 ~ M29(共30位)
变量循环(i = 0, 29, 1)
字节号 = i / 8 ' 整除
位号 = i % 8
字节值 = 到整数(buf[字节号])
' 标准位判断:1<<位号 = 对应位的掩码
如果 ((字节值 & (1 << 位号)) != 0)
M状态[i] = 真
否则
M状态[i] = 假
结束 如果
结束循环
结束 事件你写的:
buf[0] = 数据值[9]
buf[1] = 数据值[10]
buf[2] = 数据值[11]
buf[3] = 数据值[12]
如果返回报文只有 10 个字节,你访问 数据值[12] 直接数组越界崩溃。
代码完全匹配三菱 FX3U Modbus TCP 地址规则。