Modbus-ASCII 协议 + LRC校验

一、Modbus 全部功能码 必考对照表(完整版)

考试必背:区分线圈、离散输入、保持寄存器、输入寄存器读写权限

  • 01 功能码 :读取线圈状态(可读可写),存储 开关量 0/1

  • 02 功能码:读取离散输入状态(只读),传感器开关信号

  • 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 计算三步流程(背诵)

  1. 对所有有效参与校验字节累加求和

  2. 总和 按8位取反 + 1(补码运算)

  3. 0xFF 与运算,强制截断保留8位,得到LRC校验码

3.2 LRC 核心代码(可直接默写)

cs 复制代码
/// <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\n

4.2 完整组帧代码

cs 复制代码
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读取寄存器 业务代码(ASCII)

5.1 读取请求帧组装

cs 复制代码
// 固定格式:从机地址01 + 功能码03 + 起始地址0000 + 读取长度0004
string s2 = GetRequestFrame(new byte[] { 01, 03, 00, 00, 00, 04 });
port.Write(s2);

5.2 响应帧数据解析算法

ASCII返回为字符串,每4个字符代表1个寄存器数值

cs 复制代码
/// <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字节,再算LRC

6.2 写入核心代码

cs 复制代码
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专属)

cs 复制代码
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-RTU Modbus-ASCII
传输格式 二进制字节流 字符串
校验方式 CRC16(0xFFFF,0xA001) LRC纵向校验
帧头帧尾 无标识,靠间隔 帧头: : 帧尾:\r\n
效率 高,工业主流 低,可读性强

九、LRC与CRC核心区别

  • CRC16:16位校验、多项式异或、RTU使用

  • LRC:8位累加取反、算法简单、ASCII使用

十、完整初始化代码

cs 复制代码
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]}");
    }
}
相关推荐
发光小北8 小时前
西门子 PLC 串口转网口模块现场应用有哪些问题?
网络协议
开心就多写,一点就开心9 小时前
导演视听语言与分镜系统笔记(一):景别系统、机位视点与时空连贯性设计
笔记·aigc·镜头·电影
疯狂打码的少年11 小时前
【计算机网络】IPv6基础(特点、表示法、与IPv4对比)
网络·笔记·计算机网络
楚Y6同学11 小时前
QT上位机开发-UDP通信-模拟下位机数据联调的方法
网络协议·udp·联调方法
泡泡鱼(敲代码中)13 小时前
MySQL基础学习笔记:从数据模型到DDL全掌握
开发语言·数据库·笔记·学习·mysql
唐青枫13 小时前
别只会看日志:C#.NET SOS 调试扩展从 Dump 到内存泄漏排查
c#·.net
江湖人称菠萝包13 小时前
【Windows】《深入浅出Windows API程序设计:核心编程篇》笔记-Chapter4-进程
windows·笔记
今儿敲了吗15 小时前
03停用词过滤
笔记·python
秦哈哈16 小时前
【Hello Agents】学习笔记(二)
笔记·学习·microsoft
风早爽太17 小时前
Flutter 开发笔记:share_plus 分享插件
笔记·flutter