Modbus-Ascii详解

news2024/11/16 11:36:06

目录

Modbus-Ascii详解

Modbus-Ascii帧结构

LRC效验

将数据字节转成ASCII

将返回帧转为数据字节

Modbus-Ascii的实现

使用NModbus4实现Modbus-Ascii

实例


Modbus-Ascii详解

Modbus ASCII是一种将二进制数据转换为可打印的ASCII字符的通信协议,‌每个8位数据需要两个ASCII字符表示,‌报文之间通过特定字符分隔。‌这种编码方式使得数据在传输过程中更易于阅读和调试。‌Modbus ASCII协议主要应用于需要串行通信接口进行数据交互的领域,‌如工业自动化、‌楼宇自动化、‌电力系统、‌环境监测等。‌尽管其传输效率相对较低,‌但由于其良好的可读性和容错性,‌在要求数据可读性或通信链路稳定性较好的场合,‌Modbus ASCII仍然是一个不错的选择。‌

Modbus ASCII的消息帧格式包括起始符号、‌节点地址、‌功能码、‌数据字段和LRC校验码,‌以及消息的结束符号。‌具体来说,‌每个8位的字节被拆分为两个ASCII字符进行发送,‌例如,‌十六进制数0xAB会被分解成ASCII字符“A”和“B”进行发送。‌这种编码方式允许在两个字符之间有最长1秒的时间间隔而不引发通信故障,‌采用纵向冗余校验(‌LRC)‌的方法来检验错误。‌

在应用方面,‌Modbus ASCII协议允许直接在终端看到可读字符,‌方便调试和人工解析,‌尤其在需要人工介入或监控的场景中显得尤为重要。‌然而,‌由于其传输效率较低,‌因此在实时性要求较高的场合,‌可能会考虑使用Modbus RTU或其他更快捷的协议。‌此外,‌为了避免与报文中的特殊字符冲突,‌需要对特定字符进行转义处理。‌

Modbus-ASCII是一种基于ASCII码的Modbus通信协议。数据以ASCII字符形式传输,每个字节由两个ASCII字符表示。

Modbus-Ascii帧结构

帧结构:起始符号、设备地址、功能码、数据和LRC校验字段。

LRC效验
/// <summary>
/// 将字节数组,通过lrc算法生成效验码
/// </summary>
/// <param name="date">字节数组</param>
/// <returns>效验</returns>
public static string CalcLRC(byte[] date)
{
    // 1 获取字节数组每一个元素相加的和
    uint sum = (uint)date.Sum(x => x); // 计算每个元素的和

    // 2 把sum进行取反操作,再加1,再和0xff进行与运算,                                          
    uint res =  (~sum +1 )& 0xff;

    return res.ToString("X2");

}
将数据字节转成ASCII
/// <summary>
/// [01,03,00,00,00,01] 转成 ":010300010001FB\r\n"
/// </summary>
/// <param name="date">转换的字节数组</param>
/// <returns>转成ascii字符串</returns>
public static string GeRequestFrame(byte[] date) 
{
    // 1 算1rc效验码
    string jym = CalcLRC(date);

    string requesData = "";

    // 2 遍历字节数组
    foreach(byte b in date)
    {
        requesData += b.ToString("X2");
    }

    // 3 拼接效验码
    string value = ":" + requesData + jym + "\r\n";
    return value;
}
将返回帧转为数据字节
/// <summary>
/// 转成对应的ushort数组[5A,C0]
/// </summary>
/// <param name="s">ASCII字符串</param>
/// <param name="value">寄存器个数 一个时候2字节,2个4字节</param>
/// <param name="startIndex">从哪个位置开始截取</param>
/// <returns></returns>
public static ushort[] StringToUshort(string s,int valueCount ,int startIndex=7)
{
    // 如果寄存器个数*4+开始截取数据的位置>整体字符串长度 证明没有数据部分
    if(valueCount*4+startIndex>s.Length)
    {
        throw new ArgumentException("字符串长度不满足最小的解析要求");
    }

    // 正常的响应帧格式
    // 定义长度为寄存器个数数组
    // :010302 5AC0 5AC0 5AC0 E0
    ushort[] bs = new ushort[valueCount];
    for(int i = 0; i < valueCount; i++)
    {
        string value = s.Substring(startIndex,4);
        startIndex += 4;
        Console.WriteLine(value);
        bs[i] = Convert.ToUInt16(value,16);
    }
    return bs;
}

Modbus-Ascii的实现

namespace Modbus_Ascii
{
    public partial class Form1 : Form
    {
        // 参数1 串口名 , 参数2 波特率 , 参数3 奇偶效验 , 参数4 数据位 , 参数5 停止位
        public SerialPort port = new SerialPort("COM2",9600,Parity.None,8,StopBits.One);
        public Form1()
        {
            InitializeComponent();

            port.Open();
            port.DataReceived += Port_DataReceived;

            // 1 验证CalcLRC方法
            string s = Tools.CalcLRC(new byte[] {01,03,00,00,00,01});
            MessageBox.Show(s);
            // 2 验证把字节转成ASCII请求帧方法
            string s1 = Tools.GeRequestFrame(new byte[] { 01, 03, 00, 00, 00, 01 });
            MessageBox.Show(s1);

            string s2 = Tools.GeRequestFrame(new byte[] {01,03,00,00,00,01});

            // 发送
            port.Write(s2);

        }

        
        /// <summary>
        /// 接收数据事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] bs = new byte[port.ReadBufferSize];
            port.Read(bs, 0, bs.Length);
            string s = Encoding.ASCII.GetString(bs,0,bs.Length);
            Console.WriteLine(s);

            ushort[] data = Tools.StringToUshort(s,1);
            Console.WriteLine(data[0]);
        }

    }


    internal static class Tools
    {
        /// <summary>
        /// 将字节数组,通过lrc算法生成效验码
        /// </summary>
        /// <param name="date">字节数组</param>
        /// <returns>效验</returns>
        public static string CalcLRC(byte[] date)
        {
            // 1 获取字节数组每一个元素相加的和
            uint sum = (uint)date.Sum(x => x); // 计算每个元素的和

            // 2 把sum进行取反操作,再加1,再和0xff进行与运算,                                          
            uint res =  (~sum +1 )& 0xff;

            return res.ToString("X2");

        }

        /// <summary>
        /// [01,03,00,00,00,01] 转成 ":010300010001FB\r\n"
        /// </summary>
        /// <param name="date">转换的字节数组</param>
        /// <returns>转成ascii字符串</returns>
        public static string GeRequestFrame(byte[] date) 
        {
            // 1 算1rc效验码
            string jym = CalcLRC(date);

            string requesData = "";

            // 2 遍历字节数组
            foreach(byte b in date)
            {
                requesData += b.ToString("X2");
            }

            // 3 拼接效验码
            string value = ":" + requesData + jym + "\r\n";
            return value;
        }

        /// <summary>
        /// 转成对应的ushort数组[5A,C0]
        /// </summary>
        /// <param name="s">ASCII字符串</param>
        /// <param name="value">寄存器个数 一个时候2字节,2个4字节</param>
        /// <param name="startIndex">从哪个位置开始截取</param>
        /// <returns></returns>
        public static ushort[] StringToUshort(string s,int valueCount ,int startIndex=7)
        {
            // 如果寄存器个数*4+开始截取数据的位置>整体字符串长度 证明没有数据部分
            if(valueCount*4+startIndex>s.Length)
            {
                throw new ArgumentException("字符串长度不满足最小的解析要求");
            }

            // 正常的响应帧格式
            // 定义长度为寄存器个数数组
            // :010302 5AC0 5AC0 5AC0 E0
            ushort[] bs = new ushort[valueCount];
            for(int i = 0; i < valueCount; i++)
            {
                string value = s.Substring(startIndex,4);
                startIndex += 4;
                Console.WriteLine(value);
                bs[i] = Convert.ToUInt16(value,16);
            }
            return bs;
        }

    }
}

使用NModbus4实现Modbus-Ascii

在C#中使用第三方库NModbus4进行Modbus通信时,首先需要安装该库。可以通过NuGet包管理器来安装。

实例
public partial class Form1 : Form
{
    SerialPort port = new SerialPort("COM2",9600,Parity.None,8,(StopBits)1);
    ModbusSerialMaster master;
    public Form1()
    {
        InitializeComponent();
        port.Open();
        master =  ModbusSerialMaster.CreateAscii(port);
    }

    /// <summary>
    /// 读取
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        // 读取寄存器数据
        ushort[] data = master.ReadHoldingRegisters(2, 0x000, 3);
        MessageBox.Show(data[0] + "-" + data[1] + "-" + data[2]);
    }

    /// <summary>
    /// 写入
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {
        // master.WriteSingleRegister(2,7,6); //写入单个寄存器

        master.WriteMultipleRegisters(2,3,new ushort[] {10,30,4,32,4,56,99});
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1984121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WPF学习(4)- VirtualizingStackPanel (虚拟化元素)+Canvas控件(绝对布局)

VirtualizingStackPanel虚拟化元素 VirtualizingStackPanel 类&#xff08;虚拟化元素&#xff09;和StackPanel 类在用法上几乎差不多。其作用是在水平或垂直的一行中排列并显示内容。它继承于一个叫VirtualizingPanel的抽象类&#xff0c;而这个VirtualizingPanel抽象类继承…

AI基础架构-NVLink 技术详解

AI Infra 基础知识 - NVLink 入门 NVLink&#xff0c;一种专有互连硬件&#xff0c;实现Nvidia GPU与CPU之间的高效、一致数据和控制传输&#xff0c;提升多GPU系统性能。 概述 NVLink 于 2014 年初发布&#xff0c;旨在作为 PCI Express 的替代解决方案&#xff0c;具有更…

Java零基础之多线程篇:线程同步

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

Java13.0标准之重要特性及用法实例(二十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列…

【第三版 系统集成项目管理工程师】第9章 项目管理概论

持续更新。。。。。。。。。。。。。。。 【第三版】第九章 项目管理概论 9.1 PMBOK的发展9.2 项目基本要素9.2.1项目基础 P3041.独特的产品、服务或成果-P3042.临时性工作-P3043.项目驱动变更-P3054.项目创造业务价值-P3055.项目启动背景-P306 9.2.2项目管理 P3069.2.2 项目管…

AQS的ReentrantLock源码

什么是AQS&#xff08;全称AbstractQueuedSynchronizer&#xff09; 代表&#xff1a;重入锁、独占锁/共享锁、公平锁/非公平锁 是JUC包中线程阻塞、阻塞队列、唤醒、尝试获取锁的一个框架 AbstractQueuedSynchronizer是全称&#xff0c;是一个模板模式&#xff0c;一些线程…

深入理解Java的内存管理机制

文章目录 1. 程序计数器 (Program Counter Register)2. Java虚拟机栈 (Java Virtual Machine Stack)3. 本地方法栈 (Native Method Stack)4. 堆 (Heap)a. 年轻代 (Young Generation)b. 老年代 (Old Generation) 5. 方法区 (Method Area)6. 运行时常量池 (Runtime Constant Pool…

magic-api相关应用与配置

目录 项目启动 工具&#xff1a;IDEA 运行项目 关于配置 项目启动 工具&#xff1a;IDEA 新建——》项目——》导入——》运行 运行项目 http://localhost:9999/magic/web/index.htmlhttp://localhost:9999/magic/web/index.html 关于配置 配置多数据源 在线配置多数据…

git版本控制的底层实现

目录 前言 核心概念串讲 底层存储形式探测 本地仓库的详细解析 提交与分支的深入解析 几个问题的深入探讨 前言 Git的重要性 Git是一个开源的版本控制工具&#xff0c;广泛用于编程开发领域。它极大地提高了研发团队的开发协作效率。对于开发者来说&#xff0c;Git是一个…

32-《蝴蝶兰》

蝴蝶兰 蝴蝶兰&#xff08;学名&#xff1a;Phalaenopsis aphrodite Rchb. F.&#xff09;为兰科蝴蝶兰属&#xff0c;原产于亚热带雨林地区&#xff0c;为附生性兰花。蝴蝶兰白色粗大的气根露在叶片周围&#xff0c;除了具有吸收空气中养分的作用外&#xff0c;还有生长和光合…

java之WIFI模块实现文件传输(开源)

AndroidManifest这里要获取到权限,所以要导入: <uses-permission android:name"android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name"android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name"…

22 - grace数据处理 - 补充 - 泄露误差改正 - Slepian局部谱分析法(二) - Slepian谱分析程序包初始化

22 - grace数据处理 - 补充 - 泄露误差改正 - Slepian局部谱分析法 - Slepian谱分析程序包初始化 0 引言1 slepian程序包配置过程1.1 获取环境配置安装包1.2 执行demo测试是否配置成功2 结语0 引言 上篇提到进行slepian谱分析可以使用美国普林斯顿大学Frederik Simons教授提供的…

Google Chrome 应用商店插件离线导出导入方法(亲测有效)

Google Chrome 浏览器插件&#xff08;也称为扩展程序&#xff09;是一种可以增强浏览器功能的小型软件程序。这些插件可以让用户在浏览器中添加新的功能、定制化界面、自动化任务等。以下是一些常见的 Google Chrome 浏览器插件功能&#xff1a; 功能增强&#xff1a;插件可以…

使用 Pytorch 从头开始​​构建 Transformer

目录 一、说明 二、输入嵌入 2.1 __init__()方法目的 2.2 super() 三、PositionalEncoding 类 四、位置编码的工作原理 4.1 总体过程 4.2 数学公式 五、LayerNormalization 类 5.1 过程描述 5.2 例子 六、FeedForwardBlock 类 6.1 总体描述 6.2 数学公式 七、MultiHeadAttentio…

全球清真食品配料市场规划预测:未来六年CAGR为3.4%

随着全球穆斯林人口的增长和消费能力的提升&#xff0c;清真食品配料作为符合伊斯兰教义的食品添加剂和成分&#xff0c;正逐渐受到更多消费者的青睐。本文旨在通过深度分析清真食品配料行业的各个维度&#xff0c;揭示行业发展趋势和潜在机会。 【市场趋势的演变】 1. 市场规…

AI 生成搞笑段子

段子在我们生活中扮演着极为重要的角色&#xff0c;它不仅能够带给我们欢乐和娱乐&#xff0c;还能够促进交流和拉近人与人之间的距离。通过幽默诙谐的段子&#xff0c;我们可以轻松地化解尴尬和紧张的气氛&#xff0c;让沉闷的场合变得活泼有趣。 而段子手生成器&#xff0c;则…

Flink-DataWorks第一部分:DataWorks(第57天)

系列文章目录 1.1 什么是DataWorks 1.2 功能特性 1.2.1 数据集成&#xff1a;全领域数据汇聚 1.2.3 数据建模&#xff1a;智能数据建模 1.2.4 数据分析&#xff1a;即时快速分析 1.2.5 数据质量&#xff1a;全流程的质量监控 1.2.6 数据地图&#xff1a;统一管理&#xff0c;跟…

数据跨境流动需要注意什么?怎么实现安全合规的跨境传输?

2024年3月22日&#xff0c;《促进和规范数据跨境流动规定》&#xff08;以下简称《数据跨境规定》&#xff09;正式公布并施行。数据跨境流通涉及到隐私保护、安全性和法律合规等多个方面的重要考虑因素。 具体来说&#xff0c;需要注意以下几点&#xff1a; 1、隐私保护&…

农场游戏中的时间管理实例

一、准备工作 在Unity中创建承载日期和时间的文本 二、设置游戏的时间戳 using System.Collections; using System.Collections.Generic; using UnityEngine; //标识这个类可以被序列化 [System.Serializable] public class GameTimestamp {// 游戏时间戳的成员变量public in…

【第三版 系统集成项目管理工程师】第10章 启动过程组

持续更新。。。。。。。。。。。。。。。 【第三版】第十章 启动过程组 10.1 制定项目章程10.1.1 主要输入1.立项管理文件-P3562.协议-P35710.1.2 主要输出1.项目章程-P3572.假设日志-P358练习10.2 识别干系人10.2.1 主要输入1.项目管理计划-P3602.项目文件-P36010.2.2 主要工…