十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Modbus-ASCII 协议 + LRC校验

Modbus-ASCII 协议 + LRC校验 一、Modbus 全部功能码 必考对照表完整版考试必背区分线圈、离散输入、保持寄存器、输入寄存器读写权限01 功能码读取线圈状态可读可写存储开关量 0/102 功能码读取离散输入状态只读传感器开关信号03 功能码读取保持寄存器可读可写存储数值、温度、压力04 功能码读取输入寄存器只读下位机采集数据上传06 功能码写入单个保持寄存器16 功能码写入多个保持寄存器重点区别 线圈是位存储0/1状态8个状态占1字节 寄存器是字存储数值1个寄存器2字节二、Modbus-RTU 与 Modbus-ASCII 核心区别简答题满分2.1 Modbus-RTU二进制模式传输格式纯字节流二进制校验方式CRC16帧首尾无特殊标记靠时间间隔判定帧结束效率高、工业最常用2.2 Modbus-ASCII字符串模式传输格式ASCII字符串校验方式LRC纵向冗余校验帧头冒号 :帧尾\r\n 回车换行可读性强、效率低2.3 帧格式对比RTU帧从机地址 功能码 起始地址 长度 CRC纯8字节二进制ASCII帧: 地址功能码数据字符串 LRC校验 \r\n示例:010300000004E0\r\n三、LRC 校验算法原理 逐行代码必考手写3.1 LRC 计算三步流程背诵对所有有效参与校验字节累加求和总和按8位取反 1补码运算和0xFF 与运算强制截断保留8位得到LRC校验码3.2 LRC 核心代码可直接默写/// summary /// LRC纵向冗余校验Modbus-ASCII专用 /// /summary public static string CalcLRC(byte[] data) { //1.所有字节累加求和 uint sum (uint)data.Sum(x x); //2.8位取反1 3.截断8位 uint res (~sum 1) 0xff; //返回两位十六进制大写 return res.ToString(X2); }四、ASCII 请求帧组装原理与代码4.1 组帧规则所有字节转两位16进制字符串拼接LRC校验码头部加:尾部加\r\n4.2 完整组帧代码public static string GetRequestFrame(byte[] data) { //计算LRC校验 string lrc CalcLRC(data); //字节数组转十六进制字符串 string requestData ; foreach (byte b in data) { requestData b.ToString(X2); } //拼接ASCII标准帧格式 return : requestData lrc \r\n; }五、03读取寄存器 业务代码ASCII5.1 读取请求帧组装// 固定格式从机地址01 功能码03 起始地址0000 读取长度0004 string s2 GetRequestFrame(new byte[] { 01, 03, 00, 00, 00, 04 }); port.Write(s2);5.2 响应帧数据解析算法ASCII返回为字符串每4个字符代表1个寄存器数值/// summary /// ASCII字符串批量解析为寄存器数值 /// /summary public static ushort[] StringToUshort(string s, int valueCount, int startIndex 7) { //长度校验 if (valueCount * 4 startIndex s.Length) { throw new ArgumentException(响应字符串个数不够); } ushort[] bs new ushort[valueCount]; for (int i 0; i valueCount; i) { //截取4位16进制字符串 string value s.Substring(startIndex, 4); startIndex 4; //转为数值 bs[i] Convert.ToUInt16(value); } return bs; }六、06写入单个寄存器 完整代码考试重点6.1 写入帧结构从机地址(1) 功能码06(1) 写入地址(2) 写入数据(2) 共6字节再算LRC6.2 写入核心代码private void button1_Click(object sender, EventArgs e) { byte add 0x01; //从机地址 byte func 0x06; //写入功能码 ushort addres 0x0010; //写入寄存器地址 ushort value 0x1234; //写入数值 //拆分高低字节 byte[] bs { add, func, (byte)(addres 8), //地址高位 (byte)(addres 0xff), //地址低位 (byte)(value 8), //数据高位 (byte)(value 0xff) //数据低位 }; //生成ASCII帧并发送 string s GetRequestFrame(bs); port.Write(s); }七、串口接收事件代码ASCII专属private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { int readLength port.BytesToRead; byte[] bs new byte[readLength]; port.Read(bs, 0, readLength); //ASCII转字符串去除首尾换行回车 string s Encoding.ASCII.GetString(bs).Trim(\r, \n); Console.WriteLine(s); //判断是否为03读取响应帧 if (s.Contains(03)) { //解析4个寄存器数据 ushort[] us StringToUshort(s, 4); Console.WriteLine(${us[0]}:{us[1]}:{us[2]}:{us[3]}); } }八、RTU与ASCII 终极考点总结必背对比项Modbus-RTUModbus-ASCII传输格式二进制字节流字符串校验方式CRC16(0xFFFF,0xA001)LRC纵向校验帧头帧尾无标识靠间隔帧头: : 帧尾:\r\n效率高工业主流低可读性强九、LRC与CRC核心区别CRC1616位校验、多项式异或、RTU使用LRC8位累加取反、算法简单、ASCII使用十、完整初始化代码private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { int readLength port.BytesToRead; byte[] bs new byte[readLength]; port.Read(bs, 0, readLength); //ASCII转字符串去除首尾换行回车 string s Encoding.ASCII.GetString(bs).Trim(\r, \n); Console.WriteLine(s); //判断是否为03读取响应帧 if (s.Contains(03)) { //解析4个寄存器数据 ushort[] us StringToUshort(s, 4); Console.WriteLine(${us[0]}:{us[1]}:{us[2]}:{us[3]}); } }
返回列表