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]}");
    }
}
相关推荐
金立基包装胶水1 小时前
纸袋封口热封胶不粘是什么原因?
大数据·笔记·其他
chnyi6_ya1 小时前
论文阅读笔记 | From Priors to Perception: Grounding Video-LLMs in Physical Reality
论文阅读·笔记
自己的九又四分之三站台1 小时前
C# 接入 RasterLite2:从原生 DLL 加载到 Coverage、Section、Tile 验证
开发语言·c#·地理信息
左钦杨1 小时前
如何剩下一笔SSL(https)证书的钱?
网络协议·https·ssl
好名字都被猪取了-2 小时前
# C# 全栈开发资源包(.NET8/.NET10)
c#
2501_915918412 小时前
Rust 程序抓包解密,rustls 不认系统证书的几种办法
开发语言·后端·网络协议·ios·adb·https·rust
M78佐菲2 小时前
Linux学习笔记:目录IO与帧缓冲
linux·笔记·学习·算法
喜欢吃燃面2 小时前
网络协议与通信原理深度解析
网络·网络协议
hongmai6668882 小时前
把玩ESP8684-WROOM-04C-H4X:一颗耐高温的RISC-V小钢炮
笔记·单片机·嵌入式硬件·物联网·risc-v