Visual Stdio 2005中,对于串口操作Framework提供了一个很好的类接口-SerialPort,在这当中,串口数据的读取与写入有较大的不同。由于串口不知道数据何时到达,因此有两种方法可以实现串口数据的读取。
1.用线程实时读串口
2.用事件触发方式实现。
但由于线程实时读串口的效率不是十分高效,因此比较好的方法是事件触发的方式。在SerialPort类中有DataReceived事件,当串口的读缓存有数据到达时则触发DataReceived事件,其中SerialPort.ReceivedBytesThreshold属性决定了当串口读缓存中数据多少个时才触发DataReceived事件,默认为1。
此外,SerialPort.DataReceived事件运行比较特殊,其运行在辅线程,不能与主线程中的显示数据控件直接进行数据传输,必须用间接的方式实现。
一.创建WIndow项目,设计界面
二,编写实现代码
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- using System.IO.Ports;
- using System.Threading;
- using Microsoft.Win32;
- namespace ComMonitor
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- private SerialPort Sp = new SerialPort();
- public delegate void HandleInterfaceUpdataDelegate(string text); //委托,此为重点
- private HandleInterfaceUpdataDelegate interfaceUpdataHandle;
- private bool qiii = false;
- private void btENT_Click(object sender, EventArgs e)
- {
- if ((cmID.Text.Trim() != "") && (cmRate.Text != ""))
- {
- interfaceUpdataHandle = new HandleInterfaceUpdataDelegate(UpdateTextBox);//实例化委托对象
- Sp.PortName = cmID.Text.Trim();
- Sp.BaudRate = Convert.ToInt32(cmRate.Text.Trim());
- Sp.Parity = Parity.None;
- Sp.StopBits = StopBits.One;
- Sp.DataReceived += new SerialDataReceivedEventHandler(Sp_DataReceived);
- Sp.ReceivedBytesThreshold = 1;
- try
- {
- Sp.Open();
- ATCommand3("AT+CLIP=1\r", "OK");
- btPause.Enabled = true;
- btENT.Enabled = false;
- }
- catch
- {
- MessageBox.Show("端口" + cmID.Text.Trim() + "打开失败!");
- }
- }
- else
- {
- MessageBox.Show("请输入正确的端口号和波特率!");
- cmID.Focus();
- }
- }
- private void btPause_Click(object sender, EventArgs e)
- {
- Sp.Close();
- btENT.Enabled = true;
- btPause.Enabled = false;
- }
- private void Form1_FormClosing(object sender, FormClosingEventArgs e)
- {
- Sp.Close();
- }
- private void Form1_Load(object sender, EventArgs e)
- {
- GetComList();
- btPause.Enabled = false;
- }
- public void Sp_DataReceived(object sender,System.IO.Ports.SerialDataReceivedEventArgs e)
- {
- string strTemp = "";
- double iSecond = 0.5;
- DateTime dtOld = System.DateTime.Now;
- DateTime dtNow = System.DateTime.Now;
- TimeSpan dtInter;
- dtInter = dtNow - dtOld;
- int i = Sp.BytesToRead;
- if (i > 0)
- {
- try
- {
- strTemp = Sp.ReadExisting();
- }
- catch
- { }
- if (strTemp.ToLower().IndexOf("\r") < 0)
- {
- i = 0;
- }
- else
- {
- this.Invoke(interfaceUpdataHandle, strTemp);
- }
- }
- while (dtInter.TotalSeconds < iSecond && i <= 0)
- {
- dtNow = System.DateTime.Now;
- dtInter = dtNow - dtOld;
- i = Sp.BytesToRead;
- if (i > 0)
- {
- try
- {
- strTemp += Sp.ReadExisting();
- }
- catch
- { }
- if (strTemp.ToLower().IndexOf("\r") < 0)
- {
- i = 0;
- }
- else
- {
- this.Invoke(interfaceUpdataHandle, strTemp);
- }
- }
- }
- // do null
- }
- private void UpdateTextBox(string text)
- {
- tbData.Text = text;
- }
- /// <summary>
- /// 执行AT指令并返回 成功失败
- /// </summary>
- /// <param name="ATCmd">AT指令</param>
- /// <param name="StCmd">AT指令标准结束标识</param>
- /// <returns></returns>
- private void ATCommand3(string ATCmd, string StCmd)
- {
- string response = "";
- response = ATCommand(ATCmd, StCmd);
- }
- /// <summary>
- /// 执行AT指令并返回结果字符
- /// </summary>
- /// <param name="ATCmd">AT指令</param>
- /// <param name="StCmd">AT指令标准结束标识</param>
- /// <returns></returns>
- private string ATCommand(string ATCmd, string StCmd)
- {
- string response = "";
- int i;
- if (!ATCmd.EndsWith("\x01a"))
- {
- if (!(ATCmd.EndsWith("\r") || ATCmd.EndsWith("\r\n")))
- {
- ATCmd = ATCmd + "\r";
- }
- }
- Sp.WriteLine(ATCmd);
- //第一次读响应数据
- if (Sp.BytesToRead > 0)
- {
- response = Sp.ReadExisting();
- //去除前端多可能多读取的字符
- if (response.IndexOf(ATCmd) > 0)
- {
- response = response.Substring(response.IndexOf(ATCmd));
- }
- else
- {
- }
- if (response == "" || response.IndexOf(StCmd) < 0)
- {
- if (response != "")
- {
- if (response.Trim() == "ERROR")
- {
- //throw vError = new UnknowException("Unknown exception in sending command:" + ATCmd);
- }
- if (response.IndexOf("+CMS ERROR") >= 0)
- {
- string[] cols = new string[100];
- cols = response.Split(';');
- if (cols.Length > 1)
- {
- string errorCode = cols[1];
- }
- }
- }
- }
- }
- //读第一次没有读完的响应数据,直到读到特征数据或超时
- for (i = 0; i < 3; i++)
- {
- Thread.Sleep(1000);
- response = response + Sp.ReadExisting();
- if (response.IndexOf(StCmd) >= 0)
- {
- break;
- }
- }
- return response;
- }
- /// <summary>
- /// 从注册表获取系统串口列表
- /// </summary>
- private void GetComList()
- {
- RegistryKey keyCom = Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm");
- if (keyCom != null)
- {
- string[] sSubKeys = keyCom.GetValueNames();
- this.cmID.Items.Clear();
- foreach (string sName in sSubKeys)
- {
- string sValue = (string)keyCom.GetValue(sName);
- this.cmID.Items.Add(sValue);
- }
- }
- }
- private void cmID_DropDown(object sender, EventArgs e)
- {
- GetComList();
- }
- }
- }