各位乡亲父老,欢迎大家来捧场!江湖卖艺,生活不易!技艺交流(投稿、打广告、链接交换),请搓这里

  C#中如何安全的关闭串口

2019/11/8 17:46:27管理员 1902
- N +
C#中如果涉及到多线程,特别是大量的数据处理和界面更新时,如果简单强制的关闭串口,很可能会造成串口死掉,我1年来一直有个想法,今天终于真正找到了原因和解决的办法。

串口无法关闭的原因是:要关闭串口的时候,有其它线程还在读取数据或者更新界面。
关键是:在准备关闭串口的时候,看看是否在接收和处理数据,如果是就等它处理完为止;在事件处理的最前面,判断如果是准备关闭串口的bool类型值,就不再进入数据接收和处理。

using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Timers;


namespace PortTesting
{
        ///         /// 定义了一个委托类型
        ///
        public delegate void WhenGetNew();

        ///         /// 串口封装类,Help By Wyz
        ///
        public class PortDataDisplay
        {
                ///                 /// 系统串口类
                ///
                public SerialPort serialPort = new SerialPort("COM1", 19200);
                ///                 /// 解析得到数据后触发事件
                ///
                public event WhenGetNew whenGetNew;
                ///                 /// 处理线程
                ///
                private SerialDataReceivedEventHandler threadCallHandler;
                ///                 /// 对外的数据类型定义
                ///
                public string dataSrc = "";
                ///                 /// 准备关闭串口=true
                ///
                private bool m_IsTryToClosePort = false;
                ///                 /// true表示正在接收数据
                ///
                private bool m_IsReceiving = false;
              

                ///                 /// 初始化
                ///
                public PortDataDisplay()
                {
                }

                ///                 /// 有参数的构造函数
                ///
                /// 串口号,如"COM1"                /// 波特率,如19200                public PortDataDisplay(string PortName, int BaudRate)
                {
                        serialPort = new SerialPort(PortName, BaudRate);
                }

                ///                 /// 开始工作
                ///
                public void ConnectDeveice()
                {
                        //0.注册事件
                        serialPort.DataReceived -= OnSerialPortDataCome;
                        serialPort.DataReceived += OnSerialPortDataCome;
                        //1.再设置一下串口参数
                        if (this.serialPort.IsOpen == false)
                        {
                                this.serialPort.ReadBufferSize = 1000;
                                this.serialPort.ReceivedBytesThreshold = 1;//数据达到120的时候才就要触发事件,不行!!应该是数据来就触发
                                //2.打开串口开始工作
                                m_IsTryToClosePort = false;
                                this.serialPort.Open();
                        }
                }

                ///                 /// 结束工作
                ///
                public void DisconnectDeveice() // 关键和核心!!!
                {
                        m_IsTryToClosePort = true;
                        while (m_IsReceiving)
                        {
                                System.Windows.Forms.Application.DoEvents();
                        }
                        serialPort.Close();
                }

                ///                 /// 当通知到有数据达到120时处理(读取,与分析)
                ///
                ///                 ///                 private void OnSerialPortDataCome(object sender, SerialDataReceivedEventArgs e)
                {
                        if (m_IsTryToClosePort) // 关键!!!
                        {
                                return;
                        }

                        m_IsReceiving = true; // 关键!!!

                        try
                        {
                                if (threadCallHandler == null)
                                {
                                        threadCallHandler = new SerialDataReceivedEventHandler(OnSerialPortDataCome);
                                }

                                //read
                                dataSrc = serialPort.ReadExisting();//读出缓冲区所有数据
                                if (dataSrc != "" && this.whenGetNew != null)
                                {
                                        this.whenGetNew();
                                }
                        }
                        finally // 放在finally里面比较好。
                        {
                                m_IsReceiving = false; // 关键!!!
                        }
                }
        }
}





使用的时候:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace PortTesting
{
        public partial class FrmMain : Form
        {
                ///                 /// 封装好的串口类
                ///
                private PortDataDisplay m_portDispl = new PortDataDisplay("COM1", 19200);

                public FrmMain()
                {
                        InitializeComponent();
                }

                private void btnOpen_Click(object sender, EventArgs e)
                {
                        if (btnOpen.Text == "打开串口")
                        {
                                m_portDispl.whenGetNew -= portDispl_whenGetNew;
                                m_portDispl.whenGetNew += new WhenGetNew(portDispl_whenGetNew);
                                m_portDispl.ConnectDeveice();
                                btnOpen.Text = "关闭串口";
                        }
                        else if (btnOpen.Text == "关闭串口")
                        {
                                m_portDispl.DisconnectDeveice();
                                btnOpen.Text = "打开串口";
                        }
                }

                ///                 /// 事件
                ///
                private void portDispl_whenGetNew()
                {
                        WhenGetNew ehan = delegate
                        {
                                txtDisplay.AppendText(m_portDispl.dataSrc);
                        };

                        try
                        {
                                if (InvokeRequired)
                                {
                                        this.Invoke(ehan);
                                }
                        }
                        catch
                        {
                        }
                }


                private void btnClear_Click(object sender, EventArgs e)
                {
                        txtDisplay.Clear();
                }
        }
}
0人赞 分享 二维码 赏一个
选择分享方式
移步手机端
文章手机二维码

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
选择打赏方式
微信赞助

打赏