C#操作串口通信协议Modbus的常用方法介绍

一、读线圈状态

        /// <summary>
        /// 读线圈状态测试
        /// </summary>
        static void Test_0x01()
        {
            ushort startAddr = 0;
            ushort readLen = 10;

            var a = BitConverter.GetBytes(readLen);

            // 请求
            // byte[] 需要指定长度;不支持Linq
            List<byte> command = new List<byte>();
            command.Add(0x01);// 1号从站
            command.Add(0x01);// 功能码:读线圈状态
            // 起始地址
            command.Add(BitConverter.GetBytes(startAddr)[1]);//
            command.Add(BitConverter.GetBytes(startAddr)[0]);
            // 读取数量
            command.Add(BitConverter.GetBytes(readLen)[1]);
            command.Add(BitConverter.GetBytes(readLen)[0]);

            // CRC
            command = CRC16(command);

            // 报文组装完成
            // 发送-》SerialPort
            SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            // 打开串口
            serialPort.Open();

            serialPort.Write(command.ToArray(), 0, command.Count);

            // 进行响应报文的接收和解析
            byte[] respBytes = new byte[serialPort.BytesToRead];
            serialPort.Read(respBytes, 0, respBytes.Length);

            // respBytes -> 01 01 02 00 00 B9 FC
            // 检查一个校验位
            List<byte> respList = new List<byte>(respBytes);
            respList.RemoveRange(0, 3);//截去:从站地址  功能码  字节计数
            respList.RemoveRange(respList.Count - 2, 2);//截去:校验位

            respList.Reverse();
            var respStrList = respList.Select(r => Convert.ToString(r, 2)).ToList();
            var values = string.Join("", respStrList).ToList();
            values.Reverse();
            values.ForEach(c => Console.WriteLine(Convert.ToBoolean(int.Parse(c.ToString()))));

        }

二、读保持寄存器

        /// <summary>
        /// 读保持型寄存器
        /// </summary>
        static void Test_0x03()
        {
            ushort startAddr = 0;
            ushort readLen = 10;

            // 请求
            // byte[] 需要指定长度;不支持Linq
            List<byte> command = new List<byte>();
            command.Add(0x01);// 1号从站
            command.Add(0x03);// 功能码:读保持型寄存器
            // 起始地址
            command.Add(BitConverter.GetBytes(startAddr)[1]);
            command.Add(BitConverter.GetBytes(startAddr)[0]);
            // 读取数量
            command.Add(BitConverter.GetBytes(readLen)[1]);
            command.Add(BitConverter.GetBytes(readLen)[0]);

            // CRC
            command = CRC16(command);

            // 报文组装完成
            // 发送-》SerialPort
            SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            // 打开串口
            serialPort.Open();

            serialPort.Write(command.ToArray(), 0, command.Count);

            // 进行响应报文的接收和解析
            byte[] respBytes = new byte[serialPort.BytesToRead];
            serialPort.Read(respBytes, 0, respBytes.Length);

            // respBytes -> 01 01 02 00 00 B9 FC
            // 检查一个校验位
            List<byte> respList = new List<byte>(respBytes);
            respList.RemoveRange(0, 3);//截去:从站地址  功能码  字节计数
            respList.RemoveRange(respList.Count - 2, 2);//截去:校验位

            // 拿到实际的数据部分,进行数据解析
            // 明确一点:读的是无符号单精度
            //byte[] data = new byte[2];
            //for (int i = 0; i < readLen; i++)
            //{
            //    // 字节序问题    小端   大端
            //    data[0] = respList[i * 2 + 1];
            //    data[1] = respList[i * 2];
            //    // 根据此两个字节转换成想要的实际数字
            //    var value = BitConverter.ToUInt16(data, 0);
            //    Console.WriteLine(value);
            //}

            // 明确一点:读的是Float
            byte[] data = new byte[4];
            for (int i = 0; i < readLen / 2; i++)
            {
                // 字节序问题    小端   大端
                data[0] = respList[i * 4 + 3];
                data[1] = respList[i * 4 + 2];
                data[2] = respList[i * 4 + 1];
                data[3] = respList[i * 4];
                // 根据此两个字节转换成想要的实际数字
                var value = BitConverter.ToSingle(data, 0);
                Console.WriteLine(value);
            }
        }

三、写多个保持寄存器

        /// <summary>
        /// 写多个保持型寄存器
        /// </summary>
        static void Test_0x10()
        {
            ushort startAddr = 2;
            ushort writeLen = 4;
            float[] values = new float[] { 123.45f, 14.3f };

            // 请求
            // byte[] 需要指定长度;不支持Linq
            List<byte> command = new List<byte>();
            command.Add(0x01);// 1号从站
            command.Add(0x10);// 功能码:写多个保持型寄存器
            // 写入地址
            command.Add(BitConverter.GetBytes(startAddr)[1]);
            command.Add(BitConverter.GetBytes(startAddr)[0]);
            // 写入数量
            command.Add(BitConverter.GetBytes(writeLen)[1]);
            command.Add(BitConverter.GetBytes(writeLen)[0]);

            // 获取数值的byte[]
            List<byte> valueBytes = new List<byte>();
            for (int i = 0; i < values.Length; i++)
            {
                List<byte> temp = new List<byte>(BitConverter.GetBytes(values[i]));
                temp.Reverse();// 调整字节序
                valueBytes.AddRange(temp);
            }

            // 字节数
            command.Add((byte)valueBytes.Count);
            command.AddRange(valueBytes);

            // CRC
            command = CRC16(command);

            // 报文组装完成
            // 发送-》SerialPort
            SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            // 打开串口
            serialPort.Open();

            serialPort.Write(command.ToArray(), 0, command.Count);
        }

四、CRC校验

        static List<byte> CRC16(List<byte> value, ushort poly = 0xA001, ushort crcInit = 0xFFFF)
        {
            if (value == null || !value.Any())
                throw new ArgumentException("");

            //运算
            ushort crc = crcInit;
            for (int i = 0; i < value.Count; i++)
            {
                crc = (ushort)(crc ^ (value[i]));
                for (int j = 0; j < 8; j++)
                {
                    crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ poly) : (ushort)(crc >> 1);
                }
            }
            byte hi = (byte)((crc & 0xFF00) >> 8);  //高位置
            byte lo = (byte)(crc & 0x00FF);         //低位置

            List<byte> buffer = new List<byte>();
            //添加校验原始值
            buffer.AddRange(value);
            //添加校验位值
            buffer.Add(lo);
            buffer.Add(hi);

            //加上原始校验值返回
            return buffer;
        }

到此这篇关于C#操作串口通信协议协议Modbus的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • c# 实现简单的串口通讯

    本文提供一个用C#实现串口通讯实例,亲自编写,亲测可用! 开发环境: VS2008+.net FrameWork3.5(实际上2.0应该也可以) 第一步 创建一个WinForm窗体,拉入一些界面元素 重点就是,图中用红框标出的,工具箱--组件--SerialPort,做.net串口通讯,这是必备控件 第二步 设置SerialPort控件属性 用C#向串口发送数据没什么特别的,就是调用SerialPort的Write方法往串口写数据就行 但是从串口那里接收数据的方式就比较特别了 首先,需要在代码里

  • C#基于SerialPort类实现串口通讯详解

    本文实例为大家分享了C#基于SerialPort类实现串口通讯的具体代码,供大家参考,具体内容如下 最终效果 窗体设置: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; usi

  • C#串口通讯概念及简单的实现方法

    前言 最近在研究串口通讯,其中有几个比较重要的概念,RS-232这种适配于上位机和PC端进行连接,RS-232只限于PC串口和设备间点对点的通信.它很简单的就可以进行连接,由于串口通讯是异步的,也就是说你可以同时向两端或者更多进行数据发送,它们之间的传输数据类型是byte,串口通信最重要的参数是波特率.数据位.停止位和奇偶校验.对于两个进行通信的端口,这些参数必须匹配. 听大佬说的几个关于串口通讯的术语,啥?啥,这是啥? 就让我这个"小白"给你说说:第一个波特率,这个东西在不同领域都有

  • C#实现简单串口通讯实例

    本文实例为大家分享了C#实现简单串口通讯的具体代码,供大家参考,具体内容如下 参数设置界面代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO.P

  • C#基于WinForm实现串口通讯

    串口通讯是一种计算机常用的数据传输方式. 程序运行如下: 首先,检查计算机的串口,并获取所有串口信息. private void CheckPort()//检查串口是否可用         {             myLog(2, "检测串口开始!");  //log记录函数             comboBox1.Items.Clear();//清除控件中的当前值                      string[] a = SerialPort.GetPortName

  • C#操作串口通信协议Modbus的常用方法介绍

    一.读线圈状态 /// <summary> /// 读线圈状态测试 /// </summary> static void Test_0x01() { ushort startAddr = 0; ushort readLen = 10; var a = BitConverter.GetBytes(readLen); // 请求 // byte[] 需要指定长度:不支持Linq List<byte> command = new List<byte>(); com

  • jQuery layui常用方法介绍

    layer简介: layer是一款近年来备受青睐的web弹层组件,她具备全方位的解决方案,致力于服务各水平段的开发人员,您的页面会轻松地拥有丰富友好的操作体验. layer(全称:jQuery-plugin-layer),一个可以让你想到即可做到的web弹窗(层)解决方案(js组件),作者贤心(菜鸟级前端攻城师).layer侧重于用户灵活的自定义,为不同人的使用习惯提供动力.其意义在于,可以让您的页面拥有更丰富与便捷的操作体验,而这,您只需在调用时简单地配置相关参数,即可轻松实现. 与同类弹出层

  • 基于StringUtils工具类的常用方法介绍(必看篇)

    前言:工作中看到项目组里的大牛写代码大量的用到了StringUtils工具类来做字符串的操作,便学习整理了一下,方便查阅. isEmpty(String str) 是否为空,空格字符为false isNotEmpty(String str) 是否为非空,空格字符为true isBlank(String str) 是否为空,空格字符为true isNotBlank(String str) 是否为非空,空格字符为false trim(String str)去除字符串两端的控制符,空字符串.null

  • 详解python中GPU版本的opencv常用方法介绍

    引言 本篇是以python的视角介绍相关的函数还有自我使用中的一些问题,本想在这篇之前总结一下opencv编译的全过程,但遇到了太多坑,暂时不太想回看做过的笔记,所以这里主要总结python下GPU版本的opencv. 主要函数说明 threshold():二值化,但要指定设定阈值 blendLinear():两幅图片的线形混合 calcHist() createBoxFilter ():创建一个规范化的2D框过滤器 canny边缘检测 createGaussianFilter():创建一个Ga

  • Python中安装库的常用方法介绍

    目录 方法一:需要在网络条件下安装 方法二:离线安装 方法三:换源安装 总结 方法一:需要在网络条件下安装 win+R进入运行框输入命令cmd 点击确定进入 普通下载:pip install 模块名字 例如:输入 pip install pygame pip install numpy pip install xlwt xlwt代表需要安装所需包和库等 列出安装版本:pip list 和pip freeze 卸载模块: pip uninstall xlwt Y--确定卸载,n--否 指定版本下载

  • php操作xml入门之xml基本介绍及xml标签元素

    本文实例讲述了php操作xml入门之xml基本介绍及xml标签元素.分享给大家供大家参考.具体分析如下: 以xml实例来讲解: 复制代码 代码如下: <?xml version="1.0" encoding="utf-8" standalone="no" ?> <class>  <student>   <name>小乔</name>   <sex>女</sex>

  • Python操作串口的方法

    本文实例讲述了Python操作串口的方法.分享给大家供大家参考.具体如下: 首先需确保安装了serial模块,如果没安装的话就安装一下python-pyserial. 一个Python实现的串口Echo import serial import sys try: ser = serial.Serial('/dev/ttyUSB0', 9600) except Exception, e: print 'open serial failed.' exit(1) print 'A Serial Ech

  • 浅析node Async异步处理模块用例分析及常用方法介绍

    最近在研究nodejs,令我感受比较深的是--熟悉js代码的地球人都知道,js的加载顺序很重要!很重要!!那么问题来了,在编写node的时候,会在后台去请求很多接口(我们公司是与java后台交接数据的),接口就会有个回调,这么多回调怎么办呢--每个回调回来的加载顺序怎么去处理是个问题--总不可能去嵌套--嵌套--这样吧,那会显的多麻烦!!这么大的一个问题怎么没有处理方法呢,那是不可能的--对吧! Async异步处理模块! 以下是小sam的理解: 安装很简单,就跟普通的安装模块一样就行了 这样就安

  • 使用python3实现操作串口详解

    通过引用serial模块包,来操作串口. 1.查看串口名称 在Linux和Windows中,串口的名字规则不太一样. 需要事先查看. Linux下的查看串口命令 root@D2:~# ls -l /dev/ttyS* crw-rw---- 1 root dialout 4, 64 Dec 26 06:53 /dev/ttyS0 crw-rw---- 1 root dialout 4, 65 Dec 26 06:41 /dev/ttyS1 crw--w---- 1 root tty     4,

  • javascript数组操作总结和属性、方法介绍

    一.数组的操作 1.数组的创建 复制代码 代码如下: var arrayObj = new Array(); //创建一个数组var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限,是长度var arrayObj = new Array([element0[, element1[, ...[, elementN]]]]);//创建一个数组并赋值 要说明的是,虽然第二种方法创建数组指定了长度,但实际上所有情况下数组都是变长的,也就是说即使指定了

随机推荐