打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

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

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

 

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

 

2010.03.27 更新 Help By Wyz. I appreciate it !!!

 

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


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

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

        /// <summary>
        /// 初始化
        /// </summary>
        public PortDataDisplay()
        {
        }

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

        /// <summary>
        /// 开始工作
        /// </summary>
        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();
            }
        }

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

        /// <summary>
        /// 当通知到有数据达到120时处理(读取,与分析)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        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
    {
        /// <summary>
        /// 封装好的串口类
        /// </summary>
        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 = "打开串口";
            }
        }

        /// <summary>
        /// 事件
        /// </summary>
        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();
        }
    }
}

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C#串口介绍以及简单串口通信程序设计实现
java 串口通信
C++串口编程实例
WPF中使用SerialPort实现串口通讯
利用Java实现串口全双工通讯
Android串口通讯SerialPort(使用篇)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服