精华内容
下载资源
问答
  • C#读写串口数据Demo

    2018-07-07 10:38:22
    C#实现读写串口数据。用于自动化界面和板卡、PLC等通讯
  • C#读取串口数据封装, RS485、232 MODBUS通讯协议,亲测可用
  • C#读取串口数据画图

    2018-11-12 15:50:43
    同学在用FPGA做读卡器,上位机准备用labview做,因为不熟悉所以让我用C#做个备份,备不时之需。 菜鸟级别就跑去给人家帮忙,越帮越忙。他的要求是自定义串口属性,...2、读取串口数据存储到txt中 3、在winform中画图
  • C#通过串口读取和发送数据,简单的串口读取发送数据例子,简单易懂,适合初学者,欢迎下载
  • 简单明了的利用SerialPort类读取和发送串口数据
  • visual studio 2012 c# wpf 开发串口收发数据demo,仅供学习测试使用,已测,可正常收发数据
  • C#读取串口数据

    2015-05-21 16:42:33
    C#读取串口数据:打开端口、监听端口并获取数据、关闭端口
  • C#接收串口数据

    2016-12-29 13:01:51
    基于C# winform,建立监听线程,读取串口数据
  • 串口通信,电子称数据读取。程序详细易懂,可以扩展到其他应用。 串口通信,电子称数据读取。程序详细易懂,可以扩展到其他应用。
  • C# SerialPort连接串口,读写串口数据

    千次阅读 2020-09-23 09:07:55
    C# SerialPort连接串口,读写串口数据 一、起始 最近在公司做上位机,上位机要求是能够读取一款支持串口通信的传感器并且把传感器的数据用图表显示出来,且上位机能对传感器发送指令,需求有涉及到串口通信和绘制图表...

    C# SerialPort连接串口,读写串口数据

    一、起始

    最近在公司做上位机,上位机要求是能够读取一款支持串口通信的传感器并且把传感器的数据用图表显示出来,且上位机能对传感器发送指令,需求有涉及到串口通信和绘制图表。

    那么首先要解决的问题就是能够让电脑上的程序进行串口通信,有串口通信的编程语言有很多,C++,C#,JAVA,Python等语言都是支持串口通信的。我选择了使用C#,因为上位机主要是在Windows操作系统上运行,而C#对于winodws桌面应用的开发支持是比较方便的,功能也比较强大,尤其是WPF程序,做出来的UI页面比较好看

    那么本篇内容就介绍c#程序怎么实现串口通信

    二、工具准备

    开发工具:Visual Studio 2019 Community
    开发工具下载:免费的 IDE 和开发人员工具 | Visual Studio Community
    维特智能姿态角度传感器JY901模块1
    USB-TLL模块
    1、杜邦线*1
    在这里插入图片描述

    三、新建项目

    1.新建项目,选择WPF应用程序,你可能会发现两个 WPF 桌面模板,一个用于 .NET Framework,另一个用于 .NET Core。 .NET Core 模板在 Visual Studio 2019 16.3 及更高版本中可用。 你可以在本教程中使用任何一个,但建议使用 .NET Core 进行新的开发。
    在这里插入图片描述
    2.在下一屏幕中指定“项目名称”和选择“项目路径”,然后点击“创建”
    在这里插入图片描述

    四、添加串口通信引用

    1.右击项目解决方案“管理NuGet程序包”,搜索“Ports”关键字,添加System.IO.Ports引用。System.IO.Ports包是.Net 2.0以来集成的免费的串口通信包,
    在这里插入图片描述

    五、建立串口通信工具类

    创建SerialPortUtils工具类,为了后面能够方便的操作串口我们先实现一个串口操作的工具类,串口通信中用到最多的操作就是“搜索串口”,”打开/关闭串口“,”接收数据“,“发送数据”,我们可以先实现以上操作的方法。
    在这里插入图片描述

    搜索串口实现,搜索串口可以直接调用SerialPort类的GetPortNames方法,该方法会返回一个串口名称的string数组。
    在这里插入图片描述

    打开关闭串口实现,这里传入“串口名称”和“波特率”参数打开串口,如果有需要其他参数可以修改方法参数。打开串口后把ReceiveData做为接收事件的委托。
    在这里插入图片描述

    接收串口数据的委托方法实现,sender对象为串口对象,接收数据后直接向控制台打印数据
    在这里插入图片描述
    发送数据实现,检查串口是否打开,然后向串口发送数据并且打印到控制台,这样一个简单的串口通信工具类就实现了
    在这里插入图片描述

    六、SerialPortUtils工具类完整代码

    public class SerialPortUtils
        {
    
            public static string[] GetPortNames() {
                return SerialPort.GetPortNames();
            }
    
    
            public static SerialPort SerialPort = null; 
            public static SerialPort OpenClosePort(string comName,int baud)
            {
                //串口未打开
                if (SerialPort == null|| !SerialPort.IsOpen)
                {
                    SerialPort = new SerialPort();
                    //串口名称
                    SerialPort.PortName = comName;
                    //波特率
                    SerialPort.BaudRate = baud;
                    //数据位
                    SerialPort.DataBits = 8;
                    //停止位
                    SerialPort.StopBits = StopBits.One;
                    //校验位
                    SerialPort.Parity = Parity.None;
                    //打开串口
                    SerialPort.Open();
                    //串口数据接收事件实现
                    SerialPort.DataReceived += new SerialDataReceivedEventHandler(ReceiveData);
    
                    return SerialPort;
                }
                //串口已经打开
                else 
                {
                    SerialPort.Close();
                    return SerialPort;
                }
            }
    
            public static void ReceiveData(object sender, SerialDataReceivedEventArgs e) {
                SerialPort _SerialPort = (SerialPort)sender;
    
                int _bytesToRead = _SerialPort.BytesToRead;
                byte[] recvData = new byte[_bytesToRead];
    
                _SerialPort.Read(recvData, 0, _bytesToRead);
    
                //向控制台打印数据
                Debug.WriteLine("收到数据:"+ recvData);
            }
    
            public static bool SendData(byte[] data)
            {
                if (SerialPort != null && SerialPort.IsOpen)
                {
                    SerialPort.Write(data, 0, data.Length);
                    Debug.WriteLine("发送数据:" + data);
                    return true;
                }
                else {
                    return false;
                }
            }
    
        }
    

    七、工具类收发数据演示

    JY901连接我的电脑是COM3

    测试方法,在MainWindow创建testSerialPortUtils方法,testSerialPortUtils方法先搜索一遍串口,打印所有串口的名称;然后打开COM3,向COM3发送一条指令

    调试输出结果

    COM3
    发送数据:System.Byte[]
    收到数据:System.Byte[]
    收到数据:System.Byte[]
    收到数据:System.Byte[]
    收到数据:System.Byte[]
    收到数据:System.Byte[]
    

    调试后发现输出的数据是一个Byte数组,是的在串口开发中收到的数据都是byte形式的,在串口开发过程中经常会遇到byte数据和二进制、十进制、十六进制的数据。下一篇“C#十六进制、十进制、二进制、字符串数据互转”将详细介绍串口开发中用到的数据装换
    八、结语

    再为大家介绍一个优秀的C#开源串口助手项目

    码云OSDA开源串口助手项目地址:Leven/OSDA

    感谢阅读本篇“C# SerialPort连接串口,读取串口数据”,本篇到此结束,下一篇“C#十六进制、十进制、二进制、字符串数据互转”

    展开全文
  • C#串口通信时丢失数据的一种解决方法,刘凯,周云耀,C # 串行类( SerialPort )为串口通信提供了简便方法,且具有功能强大、通信快速、实时性好等特点。但在实际应用中,在串口高波特率大信
  • C# 串口数据采集小DEMO

    2015-06-29 11:57:47
    C# 串口数据采集小DEMO
  • 使用C#编写的串口数据读取,并且将读取到的数据模拟键盘数据到光标所在位置。同时可以设置软件开机自动启动启动。
  • 在工业嘈杂的生产环境中,可能发生各种意外...c#读写串口缓冲区,发送比较简单。 接收包格式:起始头+标志位+数据位+结束尾,先收到缓冲区里暂存,然后从缓冲区里检查起始位、结束尾。无效串口数据丢弃,有效数据处理。
  • 本源码在VS2013平台上,使用C#编程,实现了多串口通信的数据接收处理,实用性强,代码简洁,内置使用说明
  • c# 读取串口写入数据库

    热门讨论 2013-08-26 12:35:08
    c#编写的winform程序,读取串口数据,并写入本地的sqlite数据库,同时写入SQLServer网络数据库,这个过程都是多线程的。
  • C#基于SerialPort类串口通讯程序,可以接受数据并实时绘制数据图。很好的例子。
  • C#串口读取数字温湿度传感器数据,数据库保存历史数据,并虚线显示读取的温湿度信息,数据库保存历史数据,并虚线显示读取的温湿度信息,
  • C#中SerialPort类中DataReceived事件GUI实时处理方法 MSDN:从 SerialPort 对象接收数据时,将在辅助线程上引发 DataReceived 事件。由于此事件在辅助线程而非主线程上引发,因此尝试修改主线程中的一些元素(如 UI ...
  • C#串口接收数据保存到数据库
  • C#串口读取

    2021-09-03 08:41:43
    串口SerialPort类using System.IO.Ports;SerialPort常用属性SerialPort的主要方法串口使用串口使用需要一些相关设置:打开和关闭串口DataReceived using System.IO.Ports; 此类位于System.IO.Ports命名空间下。用于...

    using System.IO.Ports;

    此类位于System.IO.Ports命名空间下。用于控制串行端口文件资源,此类提供同步I/O和事件驱动的I/O、对管脚和中断状态的访问以及对串行驱动程序的访问。

    SerialPort常用属性

    • BaudRate 获取或设置串行波特率
    • BreakState 获取或设置中断信号状态
    • BytesToRead 获取接收缓冲区中数据的字节数
    • BytesToWrite 获取发送缓冲区中数据的自己数
    • DataBits 获取或设置每个字节的标准数据位长度(默认为8)
    • DtrEnable 获取或设置一个值,该值指示Null字节在端口和接收缓冲区之间传输时是否被忽略
    • Encoding 获取或设置传输前后的文本转换的字节编码
    • IsOpen 获取一个值,该值指示SerialPort对象的打开或关闭状态
    • NewLine 获取或设置用于解释ReadLine和WriteLine方法调用结束的值
    • Parity 获取或设置奇偶校验检查协议
    • PortName 获取或设置通信端口,包括但不限于所有可用的COM端口
    • ReadBufferSize 获取或设置SerialPort输入缓冲区的大小
    • ReadTimeOut 获取或设置读取操作未完成时发生超时之前的毫秒数
    • ReceivedBytesThreshold 获取或设置DataReceived事件发生前内部输入缓冲区中的字节数
    • RtsEnable 获取或设置一个值,该值指示在串行通信中是否启用请求发送RTS信号
    • StopBits 获取或设置每个字节的标准停止位数
    • WriteBufferSize 获取或设置串行端口输出缓冲区的大小
    • WriteTimeout 获取或设置写入操作未完成时发生超时之前的毫秒数

    SerialPort的主要方法

    • Close 关闭端口连接,将IsOpen属性设置成为false,并释放内部Stream对象
    • Dispose 释放SerialPort对象使用的非托管资源
    • GetPortNames 获取当前计算机的串行端口名称数组
    • Open 打开一个新的串行端口连接
    • Read 从SerialPort输入缓冲区中读取
    • ReadByte 从SerialPort输入缓冲区中同步读取一个字节
    • ReadChar 从SerialPort输入缓冲区中同步读取一个字符
    • ReadExisting 在编码的基础上,读取SerialPort对象的流和输入缓冲区中所有立即可用的字节
    • ReadLine 一直读取到输入缓冲区中的NewLine值
    • ReadTo 一直读取到输入缓冲区中指定value的字符串
    • Write 将数据写入到串行端口输出缓冲区
    • WriteLine 将指定的字符串和NewLine值写入到输出缓冲区
    • DataReceived 表示将处理SerialPort对象的数据接收事件的方法
    • ErrorReceived 表示处理Serialport对象的错误事件的方法

    串口使用

    串口使用需要一些相关设置:

    .PortName 串口名称,COM1, COM2等。
    .BaudRate 波特率,也就是串口通讯的速度,进行串口通讯的双方其波特率需要相同,如果用PC连接其他非PC系统,一般地,波特率由非PC系统决定。
    .Parity 奇偶校验。可以选取枚举Parity中的值
    .DataBits 数据位
    .StopBits 停止位,可以选取枚举StopBits中的值
    .Handshake 握手方式,也就是数据流控制方式,可以选取枚举Handshake中的值

    打开和关闭串口

    在创建一个SerialPort 对象,设置串口属性后,可以通过 Open()方法打开串口。数据读写完成后,可以通过Close()方法关闭串口。
    根据经验,对于有些系统,在打开串口后,还需要将RtsEnable设置为True,这样才能读写数据,否则不能正常读写数据。

    DataReceived

    SerialPort 提供了DataReceived事件。当有数据进入时,该事件被触发。该事件的触发由操作系统决定,当有数据到达时,该事件在辅助线程中被触发。辅助线程的优先级比较低,因此并不能确保每个字节的数据到达时,该事件都被触发。

    使用过程中问题:

    DataReceived 和 自己写线程监听

    项目中遇到的是不调用DataReceived而是自己写线程监听事件;

    一个简单的串口解析模板:

    using Assets.Scripts.Configuration;
    using Assets.Scripts.EntityModel;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO.Ports;
    using System.Threading;
    using UnityEngine;
    
    /// <summary>
    /// 转盘监听,
    /// 传输结果,监听线程,
    /// </summary>
    public static class ConnectTurntable
    {
        //监听串口线程
        static Thread dataReceiveThread_1, dataReceiveThread_2;
    
    
    
       static SerialPort serialPort = new SerialPort();
    
        public static void StartSerialPortListen()
        {
            //设定
            serialPort.PortName = "COM1";
            serialPort.BaudRate = 1000;
            serialPort.ReadTimeout = 500;
            serialPort.WriteTimeout = 500;
            serialPort.DataReceived += null;
    
            //不使用DataReceived,自己写线程监听
            //开启线程监听串口
            try
            {
            	//串口数据解析方法(忽视第二个参数,根据自己的解析方式自己写,这里放一个公司的串口解析)
                dataReceiveThread_1 = new Thread(() => DataReceiveFunction(serialPort, xuanzhuan));
                if (dataReceiveThread_1 != null && dataReceiveThread_1.IsAlive)
                {
                    dataReceiveThread_1.Abort();
                }
                dataReceiveThread_1.Start();
            }
            catch (Exception ex)
            {
                Debug.LogError("监听事件打开失败!ex=" + ex.Message);
            }
        }
        
        
    
        
    
        #region 串口数据解析
        static void DataReceiveFunction(SerialPort serialPort, SensorResult sensorResult)
        {
            try
            {
                /** **/
                byte[] RxBuffer = new byte[1000];
                UInt16 usRxLength = 0;
    
                int bytes = 0;
                int flag0 = 0xFF;
                int flag1 = 0xAA;
                int index = 0;//用于记录此时的数据次序
                while (true)
                {
                    if (serialPort != null && serialPort.IsOpen)
                    {
                        try
                        {
                            byte[] byteTemp = new byte[1000];
    
                            try
                            {
                                UInt16 usLength = 0;
                                try
                                {
                                    usLength = (UInt16)serialPort.Read(RxBuffer, usRxLength, 700);
                                }
                                catch (Exception err)
                                {
                                    //MessageBox.Show(err.Message);
                                    //return;
                                    Debug.LogError("spSerialPort.Read!! ex=" + err.Message);
                                }
                                usRxLength += usLength;
                                while (usRxLength >= 11)
                                {
                                    //UpdateData Update = new UpdateData(DecodeData);
                                    RxBuffer.CopyTo(byteTemp, 0);
                                    if (!((byteTemp[0] == 0x55) & ((byteTemp[1] & 0x50) == 0x50)))
                                    {
                                        for (int i = 1; i < usRxLength; i++) RxBuffer[i - 1] = RxBuffer[i];
                                        usRxLength--;
                                        continue;
                                    }
                                    if (((byteTemp[0] + byteTemp[1] + byteTemp[2] + byteTemp[3] + byteTemp[4] + byteTemp[5] + byteTemp[6] + byteTemp[7] + byteTemp[8] + byteTemp[9]) & 0xff) == byteTemp[10])
                                    {
                                        Thread t = new Thread(() => XuanzhuanReceiveData(byteTemp, sensorResult));
                                        t.Start();
                                    }
                                    for (int i = 11; i < usRxLength; i++) RxBuffer[i - 11] = RxBuffer[i];
                                    usRxLength -= 11;
                                }
    
                                Thread.Sleep(10);
                            }
                            finally
                            {
    
                            }
                        }
                        catch (Exception ex)
                        {
                            // Debug.Log(ex.Message);
                        }
                    }
                    Thread.Sleep(100);
                }
            }
            catch (Exception ex)
            {
    
                //log.Error("DataReceiveFunction!! ex=" + ex.Message);
            }
        }
    
    
    
    
       
    
        private static void XuanzhuanReceiveData(byte[] RxBuffer, SensorResult sensorResult)
        {
            try
            {
                DecodeData(ref sensorResult, RxBuffer);
            }
            catch (Exception ex)
            {
                Debug.LogError(" ComReceiveData ex={0}" + ex.Message);
            }
        }
        /// <summary>
        /// 输入数据解析出来到sr里
        /// </summary>
        /// <param name="sr"></param>
        /// <param name="byteTemp"></param>
        private static void DecodeData(ref SensorResult sr, byte[] byteTemp)
        {
            DateTime TimeStart = DateTime.Now;
            short sRightPack = 0;
            short[] ChipTime = new short[7];
            double Temperature;
            double Pressure, Altitude, GroundVelocity, GPSYaw, GPSHeight;
            long Longitude, Latitude;
            double[] LastTime = new double[10];
    
    
    
            float[] Data = new float[4];
            double TimeElapse = (DateTime.Now - TimeStart).TotalMilliseconds / 1000;
    
            Data[0] = BitConverter.ToInt16(byteTemp, 2);
            Data[1] = BitConverter.ToInt16(byteTemp, 4);
            Data[2] = BitConverter.ToInt16(byteTemp, 6);
            Data[3] = BitConverter.ToInt16(byteTemp, 8);
            sRightPack++;
            switch (byteTemp[1])
            {
                case 0x52:
                    //Data[3] = Data[3] / 32768 * double.Parse(textBox9.Text) + double.Parse(textBox8.Text);
                    Temperature = Data[3] / 100.0;
                    Data[0] = Data[0] / 32768.0f * 2000;
                    Data[1] = Data[1] / 32768.0f * 2000;
                    Data[2] = Data[2] / 32768.0f * 2000;
                    sr.WX = Data[0];
                    sr.WY = Data[1];
                    sr.WZ = Data[2];
                    sr.WO = Data[3];
                    if ((TimeElapse - LastTime[2]) < 0.1) return;
                    LastTime[2] = TimeElapse;
                    break;
           
                case 0x55:
                    sr.D0 = Data[0];
                    sr.D1 = Data[1];
                    sr.D2 = Data[2];
                    sr.D3 = Data[3];
                    break;
          
                default:
                    break;
            }
        }
    
    
    
       
    
        #endregion
    
    
    
    
    }
    
    

    问题:

    if (((use11byte[0] + use11byte[1] + use11byte[2] + use11byte[3] + use11byte[4] + use11byte[5] + use11byte[6] + use11byte[7] + use11byte[8] + use11byte[9]) & 0xff) == use11byte[10])
    

    校验:前几个的和,& 0xff, 取最后8位 和校验位校验

    BitConverter.ToInt16(byteTemp, 2);使用,
    取byte[] 中 第2个byte和他的下一个(即第三个),然后组合成 【第三个 第二个】16位数。注意颠倒

    展开全文
  • RS232协议,用于读取下位机,可通信仪表。代码内含托利多仪表返回协议
  • 文章目录原方案代码基本思路串口通信基本原理采集数据流程问题重构问题复盘重构过程ReadTo函数多线程代码 原方案 欢迎大家访问我的个人网站 www.joezhouman.com 查看原文 首先说明一下,我对串口通信的理解不深,...

    原方案

    欢迎大家访问我的个人网站 www.joezhouman.com 查看原文
    首先说明一下,我对串口通信的理解不深,所有关于这方面的说明会有很多纰漏,有时会词不达意,各位图一乐就好。

    代码

    private char _start; // 起始位标志
    private char _end;   // 结束位标志
    private string recvstr;         // 用于存储一组数据的全局变量
    
    public void sendMsg(){
        Thread thread;
        thread = new Thread(() =>//新开线程,执行接收数据操作
        {
            while (enablescan)//如果标识为true
            {
                Thread.Sleep(1);
                try
                {
                    serialPort1.WriteLine(":READ?");
                    Thread.Sleep(AppCfg.devicepara.Scan_interval);
                }
                catch (Exception ex){;}
            }
        });
        thread.Start();//启动线程
        thread.IsBackground = true;
    }
    
    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                string str = serialPort1.ReadExisting();
                if (str.IndexOf(_start) != -1)//当前数据存在起始位
                {
                    str = str.Substring(str.IndexOf(_start), str.Length - str.IndexOf(_start);//截取起始位到字符串末尾
                }
                if(str.IndexOf(_end==-1)//当前数据不存在结束位
                    recvstr += str;
                else{//当前数据存在起始位
                    str = str.Substring(0, str.IndexOf(_end);
                    recvstr = recvstr + str;
                    DoSomething(recvstr)//对一组串口数据进行其他处理
                    recvstr = "";//清空数据
                }
                
            }
    

    基本思路

    串口通信基本原理

    说先说明一下采集仪发送数据的方式。一组数据一般由一个起始位标识开始,由一个结束位标识结束,中间为实际数据字符。
    我们以S表示起始位,E表示结束位,D表示有效数据,那么一组数据是这样的

    SDDDDDDDDDDDDDDE

    而且,一组数据一般不是一次完整发送过来的,而是分段发送, 如:

    SDDD
    DDDD
    DDDD
    DDDE

    发送过来的数据会放在串口通信的缓存区里。

    采集数据流程

    1. 开始采集, enablescanfalse 变为 true
    2. 开启新线程,若检测到enablescantrue,则每个一段时间向采集仪发送采集信号
    3. 采集仪向串口发送数据,将数据放入缓冲区
    4. 串口接收到数据后触发serialPort_DataRecived事件,取走当前缓冲区的所有数据,进行处理(详细处理的方式见代码)
    5. 数据处理完后,退出serialPort_DataRecived函数,等待事件的下一次触发
    6. 停止采集,enablescantrue 变为 false
    7. 发送数据的线程检测到enablescanfalse,结束工作,销毁线程。

    问题

    在实际使用中,接受到的数据经常会缺失一部分,DoSomething时经常会抛出异常,造成了很大的困扰。

    最开始的思路是用try...catch捕获异常,丢掉有问题的数据,但有时不赶巧,一组正常的数据都没有,而且这一问题出现的频率不低。
    痛定思痛,决定重构这一祖传代码,真是前人拉屎总不冲,后人难忍终清洁

    重构

    问题复盘

    我们首先复盘一下问题发生的过程
    正常的过程应该是这样的

    采集仪动作接收事件当前缓存区strrecvstr
    开始待命中nullnullnull
    发送数据触发事件SDDDSDDDSDDD
    发送数据-处理中-DDDDSDDDSDDD
    -发送间隔-处理完成DDDDSDDDSDDD
    发送数据触发事件DDDDDDDEDDDDDDDESDDDDDDDDDDE
    开始休息处理完成nullnullnull

    产生错误时:

    采集仪动作接收事件当前缓存区strrecvstr
    开始待命中nullnullnull
    发送数据触发事件SDDDSDDDSDDD
    发送数据-处理中-DDDDSDDDSDDD
    发送数据-处理中-DDDDDDDESDDDSDDD
    -待机-处理完成DDDDDDDESDDDSDDD
    -待机--待命中-DDDDDDDESDDDSDDD
    发送数据触发事件DDDDDDDESDDDSDDDSDDDSDDD

    看,原本应该接收到SDDDDDDDDDDESDDD...,现在真正这组收到的是SDDDSDDD...,部分数据丢失。

    对源代码进行修改太麻烦,故而选择直接重构该部分功能。

    重构过程

    ReadTo函数

    首先想到的是,难到不能读到一组完整的数据再进行处理吗?

    其实是可以的。C#内置了ReadTo方法 查看MSDN

    一直读到结束位标识后,再这一组数据放到指定的参数中,底层肯定有一些细节,总而言之,可以保证每次读到一组完整的数据。

    其用法为

        string endStr = ((char)13).ToString
        string targetStr = SerialPort.ReadTo("endStr");
    

    多线程

    ReadTo解决了数据读取的问题,然而当该方法在读取数据时,整个一直在等待,等读取成功后,再执行之后的操作,在这个等待过程中,
    其他任何的触发事件都无法完成,呈现出的效果就是软件“卡住了”。

    未解决这一问题,我们可以采用多线程的方法。一个线程专门负责读取数据,一个线程处理数据。
    为了几个线程之间的通信,我们设计一个
    读到的数据不断放入中,另一个线程不断从中提取数据。除此之外,我们还要保证先放入池中的数据先被处理。

    根据以上特点,我们自然而然的想到了一种先入先出的数据结构–队列


    说句题外话,老有人说小学时的问题一个池子,一边注水,一边放水这种问题很傻,没有现实意义。。。其实现实中处处都有。
    不一定是真实的,也可以是抽象的


    话不多说,上代码。

    代码

    private char _start; // 起始位标志
    private char _end ;   // 结束位标志
    private private Queue<string> _serialPortData; // 数据池
    
    ///<summary>
    ///向测试仪发送读取信号及接受测试仪发回数据的线程。根据之前所说ReadTo的性质,正好保证读完一组数据后,再发送指令让测试仪测试下一组数据
    ///<summary>
    public void ReadDataThread() {
        _enableScan = true;
        Thread thread = new Thread(() => //新开线程,执行接收数据操作
        {
             while (_enableScan) //如果标识为true
            {
                Thread.Sleep(1);
                try {
                    serialPort1.WriteLine(":READ?");
                    Thread.Sleep(10);
                    if (serialPort1.BytesToRead != 0) _serialPortData.Enqueue(serialPort1.ReadTo(_end));//将读到的数据放入池中
                    Thread.Sleep(100);
                }
                catch (Exception ex) {//其他的改进
                    HandleException(ex);//加上异常处理,是系统更稳健
                    Log.Error(ex);//打logger,记录异常原因,为修改bug提供依据
                }
            }
        });
        thread.Start(); //启动线程
        thread.IsBackground = true;//线程在后台运行
    }
    
    public void SolveDataThread(){
        Thread thread = new Thread(() => //新开线程,执行接收数据操作
        {
            while (_enableScan) //如果标识为true
            {
                if (_serialPortData.Count == 0)continue; 
                try{
                    string str = _serialPortData.Dequeue();//从池中读取数据
                    DoSomething(str);
                    thread.Sleep(100);
                }
                catch (Exception ex) {//其他的改进
                    HandleException(ex);//加上异常处理,是系统更稳健
                    Log.Error(ex);//打logger,记录异常原因,为修改bug提供依据
                }
            }
    }
    
    
    

    信息说明都在代码注释里。

    展开全文
  • 使用方法详见我的博客:https://blog.csdn.net/HorseRoll/article/details/83587484
  • C#编写的串口数据接收保存

    热门讨论 2014-12-08 15:19:50
    本压缩文件是一个完整的C#编写的串口采集软件,可以实时接收串口数据并显示在文本框内,以Excel表格的形式实时记录储存数据,含有全部代码和界面设计等,也可直接使用.本人采用的是vs2010,若有下载后不能使用的请给我...
  • c#(winform)通过串口读取并解析数据

    千次阅读 多人点赞 2020-02-03 09:38:42
    在开发过程中,有时会遇到通过串口读取地磅等数据,但是在真实的环境测试也不方便,这时使用虚拟串口工具就显得非常方便了,虚拟出两个串口,一个模拟发送数据,一个模拟接收数据。 虚拟串口工具:Configure ...

    1、工具选择

    在开发过程中,有时会遇到通过串口读取地磅等数据,但是在真实的环境测试也不方便,这时使用虚拟串口工具就显得非常方便了,虚拟出两个串口,一个模拟发送数据,一个模拟接收数据。

    虚拟串口工具:Configure Virtual Serial Port Driver 

    串口调试工具:Serial Port Utility

    2、程序编写

    2.1 winform 中使用串口就需要在左侧工具箱里拖入一个serialPort,如下图所示

                                                    

    2.2 初始化串口

    public SerialPort serialPort;
    private bool Listening = false;//是否没有执行完invoke相关操作   
    private bool Closing = false;//是否正在关闭串口,执行Application.DoEvents,并阻止再次invoke   
    #region 初始化串口
            private void InitPort()
            {
                try
                {
                    serialPort1.PortName = "COM1";
                    serialPort1.BaudRate = 4800;
                    serialPort1.DataBits = 8;
                    serialPort1.Parity = Parity.None;
                    serialPort1.StopBits = StopBits.One;
                    serialPort1.WriteTimeout = 3000;
                    serialPort1.ReadTimeout = 3000;
                    serialPort1.ReceivedBytesThreshold = 1;
                    serialPort1.DtrEnable = true;
                    serialPort1.RtsEnable = true;
                    updateText = new UpdateTextEventHandler(UpdateTextBox);  //实例化委托对象
                    serialPort1.Handshake = Handshake.RequestToSend;
                    serialPort1.Open();
                    //MessageBox.Show("开始");
                    button3.Text = "关闭串口";
                    serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            #endregion

    2.3 串口获取数据

    我解析这个吊钩秤是通过称一直向外发送数据,程序解析数据,通过截取字符串,获取两个空白之间的数据并显示在文本框上

    #region  串口获取数据
            public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
                try
                {
                    Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。
                    Thread.Sleep(600);
    
                    string SDateTemp = "";
                    int len = serialPort1.BytesToRead;
    
                    Byte[] readBuffer = new Byte[len];
                    serialPort1.Read(readBuffer, 0, len);
    
                    SDateTemp = Encoding.Default.GetString(readBuffer);
                    //MessageBox.Show(SDateTemp);
    
    
                    int L = SDateTemp.IndexOf(" ");
                    int length = SDateTemp.Length;
                    string str1 = SDateTemp.Substring(L, length - L).Trim();
    
                    int L2 = str1.IndexOf(" ");
                    int length2 = str1.Length;
                    str2 = str1.Substring(0, L2).Trim();
    
                    if (!string.IsNullOrEmpty(str2))
                    {
                        this.BeginInvoke(new UpdateTextEventHandler(UpdateTextBox), new string[] { str2 });
                        //SDateTemp = GetValue(SDateTemp, "@G002", "kg").Trim(); //多少kg
                    }
    
                    //this.Invoke(new UpdateTextEventHandler(UpdateTextBox), new string[] { SDateTemp });
                    
                }
                finally
                {
                    Listening = false;//我用完了,ui可以关闭串口了。   
                }
            }
            #endregion

    2.4 到文本框进行显示

    private void UpdateTextBox(string text)
            {
                if (!string.IsNullOrEmpty(text))
                {
                    textBox6.Text = text;
                }
            }

    3、正则解析

    如果串口发送的数据时规范的并且可以用正则解析的话,可以使用下边的方法。

    #region 获得字符串中开始和结束字符串之间的值
            /// <summary>
            /// 获得字符串中开始和结束字符串之间的值
            /// </summary>
            /// <param name="str">字符串</param>
            /// <param name="A">开始</param>
            /// <param name="B">结束</param>
            /// <returns></returns> 
    public static string GetValue(string str, string A, string B)
            {
                Regex rg = new Regex("(?<=(" + A + "))[.\\s\\S]*?(?=(" + B + "))", RegexOptions.Multiline | RegexOptions.Singleline);
                //Regex rg = new Regex("(?<=(" + A + "))[.\\d]*?(?=(" + B + "))", RegexOptions.Multiline | RegexOptions.Singleline);
    
                return rg.Match(str).Value;
            }
            #endregion

    如果采用了上边GetValue方法的话,在serialPort1_DataReceived 方法中,带注释的两行就需要取消注释使用。

    展开全文
  • 本文主要介绍两种获取串口列表的方法,比较简单,方便大家使用,另外分享了一个已封装的API,需要的朋友可以参考下。
  • C#串口数据读取程序,解决串口读取不完整小问题。 出现问题:串口数据读取不完整 在对串口设备进行数据读取的过程中,遇到数据读取不完整的情况,例:完整的数据由506个字节,但每次串口读取的数据数量是随机的,506...
  • VS2010C#工程,接收单片机系统串口传输的4字节温度数据并显示,附带数据库查询指令参考 (本科生时期项目,没有数据表,谨慎下载)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,407
精华内容 2,562
关键字:

c#读取串口数据

c# 订阅