通过串口读写数据,非常简单,只需要将控制拉到窗口位置即可,就可以在窗口的下方查看到串口控件的图标,点击图标,按下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(); } } }
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(); } } }
最后是窗体的代码
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串口获取数据出错"); } } }
2021-04-02
更新,在后期使用的过程中,有部分电脑的IC刷卡器获取数据时,会分两段进入至应用中
请参考《C# 串口接收1次数据会进入2次串口接收事件serialPort1_DataReceived,第2次进入时串口缓冲区为空》
正常的数据的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; } ... }