c# winform读取及发送串口信号

时间:2024-03-05 12:26:55

请参考C#的API文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.io.ports.serialport?redirectedfrom=MSDN&view=netframework-4.5

 

通过串口读写数据,非常简单,只需要将控制拉到窗口位置即可,就可以在窗口的下方查看到串口控件的图标,点击图标,按下F4即可查看该串品的详细属性

也可以通过在代码中创建一个串口类,并在代码中直接操作串口收发数据

其中包括比较基础的端口名称、波特率、数据位、停止位、检验位等五个参数

也有只需要指定端口名称即可,其他参数保持默认

 

知识点:向串口发送数据并获取数据
只需要将serialPort加入至窗口中,并且指定其中的端口名及波特率,指定串口数据回应事件即可(DataReceived事件) 

然后在窗口加载事件中,将serialPort打开即可

1,直接使用serialPort.writeLine方法即可将数据发送至端口

2,已为serialPort指定了数据回应事件,当有数据从串口中返回,事件即会响应

 

 


 

示例项目

系统启动三个后台线程,

一个线程对应到更新当前时间

一个线程定时发送AA1086至串口7,并从串口7获得返回的数据

一个线程定时获取串口1的数据(修改为不需要后台线程)

 

示例代码

两个基础类,线程及定时,存放在Common文件夹中

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Threading;

namespace MES_MonitoringClient.Common
{
    /// <summary>
    /// 多线程任务
    /// </summary>
    public class ThreadHandler
    {
        //
        Thread _TThread = null;

        //默认后台运行
        private const bool default_isBackground = true;

        //默认不自动运行
        private const bool default_autoRun = false;




        public ThreadHandler(System.Threading.ThreadStart startFunction) : this(startFunction, default_isBackground, default_autoRun)
        { }

        public ThreadHandler(System.Threading.ThreadStart startFunction, bool isBackground) : this(startFunction, isBackground, default_autoRun)
        { }        

        /// <summary>
        /// 创建线程
        /// </summary>
        /// <param name="startFunction">运行方法</param>
        /// <param name="isBackground">是否后台运行</param>
        /// <param name="autoRun">是否自动运行</param>
        public ThreadHandler(System.Threading.ThreadStart startFunction, bool isBackground, bool autoRun)
        {
            _TThread = new Thread(startFunction);

            //是否后台运行
            _TThread.IsBackground = isBackground;

            //自动运行线程
            if (autoRun)
            {
                _TThread.Start();
            }
        }




        /// <summary>
        /// 开始线程
        /// </summary>
        public void ThreadStart()
        {
            _TThread.Start();
        }

        /// <summary>
        /// 查看线程执行状态
        /// </summary>
        /// <returns></returns>
        public bool ThreadIsAlive()
        {
            return _TThread.IsAlive;
        }

        /// <summary>
        /// 查看线程
        /// 前后台执行
        /// </summary>
        /// <returns></returns>
        public string ThreadState()
        {
            return _TThread.ThreadState.ToString();
        }

        /// <summary>
        /// 当前线程唯一托管标识符
        /// </summary>
        /// <returns></returns>
        public int ThreadManagedThreadId()
        {
            return _TThread.ManagedThreadId;
        }

        /// <summary>
        /// 等待线程结束
        /// </summary>
        public void ThreadJoin()
        {
            _TThread.Join();
        }
    }
}
ThreadHandler
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;



namespace MES_MonitoringClient.Common
{
    /// <summary>
    /// 定时器帮助类
    /// 创建定时器=》开始执行任务
    /// </summary>
    public class TimmerHandler
    {
        //定时器
        System.Timers.Timer _TTimer = null;

        //定时器默认执行一次
        private const bool default_autoReset = false;

        //定时器默认一秒执行一次
        private const int default_interval = 1000;

        //定时器创建后即刻运行
        private const bool default_autoRun = false;



        public TimmerHandler(System.Timers.ElapsedEventHandler elapseEvent) : this(default_interval, elapseEvent, default_autoRun)
        { }

        public TimmerHandler(System.Timers.ElapsedEventHandler elapseEvent, bool autoRun) : this(default_interval, elapseEvent, autoRun)
        { }

        public TimmerHandler(int interval, System.Timers.ElapsedEventHandler elapseEvent, bool autoRun) : this(interval, default_autoReset, elapseEvent, autoRun)
        { }

        /// <summary>
        /// 创建定时器
        /// </summary>
        /// <param name="interval">间隔时间(ms)</param>
        /// <param name="autoReset">是否重复执行</param>
        /// <param name="elapseEvent">定时事件</param>
        /// <param name="autoRun">是否自动运行</param>
        public TimmerHandler(int interval, bool autoReset, System.Timers.ElapsedEventHandler elapseEvent, bool autoRun)
        {
            _TTimer = new System.Timers.Timer();

            //时间间隔            
            _TTimer.Interval = interval;

            //是否重复执行
            _TTimer.AutoReset = autoReset;

            //定时器处理事件
            _TTimer.Elapsed += elapseEvent;

            //定时器自动运行
            if (autoRun)
            {
                _TTimer.Start();
            }
        }




        /// <summary>
        /// 定时器是否可用
        /// </summary>
        /// <returns></returns>
        public bool GetTimmerEnable()
        {
            return _TTimer.Enabled;
        }

        /// <summary>
        /// 开始定时器任务
        /// </summary>
        public void StartTimmer()
        {
            _TTimer.Start();
        }

        /// <summary>
        /// 关闭定时器任务
        /// </summary>
        public void StopTimmer()
        {
            _TTimer.Stop();
        }

        /// <summary>
        /// 删除定时器
        /// </summary>
        public void RemoveTimmer()
        {
            _TTimer.Stop();
            _TTimer.Dispose();
        }
    }
}
TimmerHandler

 

最后是窗体的代码

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;
using System.Windows.Forms;

using System.Threading;
using System.Diagnostics;

namespace MES_MonitoringClient
{
    public partial class frmMain : Form
    {

        /*---------------------------------------------------------------------------------------*/
        //发送信号数量
        static int sendDataCount = 0;
        //接收信号数量
        static int receviedDataCount = 0;
        //发送信号错误数量
        static int sendDataErrorCount = 0;
        //接收信号错误数量
        static int receviedDataErrorCount = 0;

        //向串口7发送的默认信号
        static string mc_DefaultSignal = "AA1086";

        //必须的串口端口
        static string[] mc_DefaultRequiredSerialPortName = new string[] { "COM1", "COM7" };

        //三个后台线程
        static Common.ThreadHandler DateTimeThreadHandler = null;
        static Common.ThreadHandler SerialPort1ThreadHandler = null;
        static Common.ThreadHandler SerialPort7ThreadHandler = null;


        /*---------------------------------------------------------------------------------------*/
        //后台线程变量
        Thread timerThread = null;

        //定时器变量
        System.Timers.Timer TTimer;


        /*主窗口方法*/
        /*---------------------------------------------------------------------------------------*/

        public frmMain()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 主窗口加载事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmMain_Load(object sender, EventArgs e)
        {
            try
            {
                var sw = Stopwatch.StartNew();
                //检测端口


                //打开端口
                serialPort7.Open();
                serialPort1.Open();

                //开始后台进程
                DateTimeThreadHandler = new Common.ThreadHandler(new ThreadStart(DateTimeTimer), true, true);
                //SerialPort1ThreadHandler = new Common.ThreadHandler(new ThreadStart(GetRFIDDataTimer), true, true);
                SerialPort7ThreadHandler = new Common.ThreadHandler(new ThreadStart(SendDataToSerialPortTimer), true, true);

                label2.Text = DateTimeThreadHandler.ThreadState();

                //MessageBox.Show("初始化共使用" + sw.ElapsedMilliseconds.ToString() + "毫秒");
                
                sw.Stop();
            }
            catch (Exception ex)
            {
                ShowErrorMessage(ex.Message, "系统初始化");
            }
        }

        /// <summary>
        /// 主窗口关闭中事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            DateTimeThreadHandler.ThreadJoin();
            //SerialPort1ThreadHandler.ThreadJoin();
            SerialPort7ThreadHandler.ThreadJoin();


            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
            }
            if (serialPort7.IsOpen)
            {
                serialPort7.Close();
            }
        }

        /*定时器方法*/
        /*---------------------------------------------------------------------------------------*/

        /// <summary>
        /// 显示时间定时器
        /// </summary>
        private void DateTimeTimer()
        {            
            Common.TimmerHandler TTimerClass = new Common.TimmerHandler(1000, true, (o, a) => {
                SetDateTime();
            }, true);
        }

        /// <summary>
        /// 获取串口1RFID定时器
        /// </summary>
        private void GetRFIDDataTimer()
        {
            Common.TimmerHandler TTimerClass = new Common.TimmerHandler(1000, true, (o, a) => {
                GetRFIDData(mc_DefaultSignal);
            }, true);
        }

        /// <summary>
        /// 发送AA1086至串口7定时器
        /// </summary>
        private void SendDataToSerialPortTimer()
        {
            Common.TimmerHandler TTimerClass = new Common.TimmerHandler(1000, true, (o, a) => {
                SendDataToSerialPort(mc_DefaultSignal);
            }, true);
        }

        /*定时器委托*/
        /*---------------------------------------------------------------------------------------*/

        /// <summary>
        /// 声明显示当前时间委托
        /// </summary>
        private delegate void SetDateTimeDelegate();
        private void SetDateTime()
        {
            if (this.InvokeRequired)
            {
                try
                {
                    this.Invoke(new SetDateTimeDelegate(SetDateTime));
                }
                catch (Exception ex)
                {
                    //响铃并显示异常给用户
                    System.Media.SystemSounds.Beep.Play();
                }
            }
            else
            {
                try
                {
                    label1.Text = string.Format("当前时间:" + DateTime.Now);
                }
                catch (Exception ex)
                {
                    //响铃并显示异常给用户
                    System.Media.SystemSounds.Beep.Play();
                }
            }
        }

        /// <summary>
        /// 声明发送数据至串口委托
        /// </summary>
        /// <param name="defaultSignal"></param>
        private delegate void SendDataToSerialPortDelegate(string defaultSignal);
        private void SendDataToSerialPort(string defaultSignal)
        {
            if (this.InvokeRequired)
            {
                SendDataToSerialPortDelegate sendDataToSerialPortDelegate = SendDataToSerialPort;
                try
                {
                    this.Invoke(sendDataToSerialPortDelegate, new object[] { defaultSignal });
                }
                catch (Exception ex)
                {
                    //响铃并显示异常给用户
                    System.Media.SystemSounds.Beep.Play();
                }
            }
            else
            {
                try
                {
                    if (serialPort7.IsOpen)
                    {
                        serialPort7.WriteLine(defaultSignal);
                        sendDataCount += 1;
                        //lab_SendDataCount.Text = "发送成功:" + sendDataCount;
                    }
                }
                catch (Exception ex)
                {
                    sendDataErrorCount += 1;
                    //lab_SendDataErrorCount.Text = "发送错误:" + sendDataErrorCount;

                    //响铃并显示异常给用户
                    System.Media.SystemSounds.Beep.Play();
                }
            }
        }

        /// <summary>
        /// 声明获取RFID串口委托
        /// </summary>
        /// <param name="defaultSignal"></param>
        private delegate void GetRFIDDataDelegate(string defaultSignal);
        private void GetRFIDData(string defaultSignal)
        {
            if (this.InvokeRequired)
            {
                GetRFIDDataDelegate getRFIDDataDelegate = GetRFIDData;
                try
                {
                    this.Invoke(getRFIDDataDelegate, new object[] { defaultSignal });
                }
                catch (Exception ex)
                {
                    //响铃并显示异常给用户
                    System.Media.SystemSounds.Beep.Play();
                }
            }
            else
            {
                try
                {
                    if (serialPort7.IsOpen)
                    {
                        serialPort7.WriteLine(defaultSignal);
                        sendDataCount += 1;
                        //lab_SendDataCount.Text = "发送成功:" + sendDataCount;
                    }
                }
                catch (Exception ex)
                {
                    sendDataErrorCount += 1;
                    //lab_SendDataErrorCount.Text = "发送错误:" + sendDataErrorCount;

                    //响铃并显示异常给用户
                    System.Media.SystemSounds.Beep.Play();
                }
            }
        }

        /*窗口公共方法*/
        /*---------------------------------------------------------------------------------------*/

        /// <summary>
        /// 显示系统错误信息
        /// </summary>
        /// <param name="errorTitle">错误标题</param>
        /// <param name="errorMessage">错误</param>
        private void ShowErrorMessage(string errorTitle,string errorMessage)
        {
            MessageBox.Show(errorMessage, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /*获取串口数据事件*/
        /*---------------------------------------------------------------------------------------*/

        /// <summary>
        /// 串口7获取数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPort7_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                System.IO.Ports.SerialPort COM = (System.IO.Ports.SerialPort)sender;
                //因为要访问UI资源,所以需要使用invoke方式同步ui
                this.Invoke((EventHandler)(delegate
                {
                    receviedDataCount += 1;
                    //lab_ReceviedDataCount.Text = "接收成功:" + receviedDataCount;

                    richTextBox1.AppendText(COM.ReadLine() + "\r");
                }
                   )
                );
            }
            catch (Exception ex)
            {
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
            }
        }       

        /// <summary>
        /// 串口1获取数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                System.IO.Ports.SerialPort COM = (System.IO.Ports.SerialPort)sender;
                //因为要访问UI资源,所以需要使用invoke方式同步ui
                this.Invoke((EventHandler)(delegate
                {
                    richTextBox2.AppendText(COM.ReadLine() + "\r");
                }
                   )
                );
            }
            catch (Exception ex)
            {
                ShowErrorMessage("serialPort1_DataReceived", "RFID串口获取数据时出错");
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
            }
        }

        private void serialPort1_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
        {
            ShowErrorMessage("serialPort1_ErrorReceived", "RFID串口获取数据出错");
        }
    }
}
frmMain

 

 

2021-04-02

更新,在后期使用的过程中,有部分电脑的IC刷卡器获取数据时,会分两段进入至应用中

请参考《C# 串口接收1次数据会进入2次串口接收事件serialPort1_DataReceived,第2次进入时串口缓冲区为空

微软官方的地址:https://docs.microsoft.com/zh-cn/dotnet/api/system.io.ports.serialport.datareceived?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0

 正常的数据的EventType为Chars类型,结束符的EventType为Eof,这里,只需要加入类型判断即可

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    //接收到EOF则直接退出
    if (e.EventType == System.IO.Ports.SerialData.Eof)
    {
        return;    
    }
    
    ...
}