C#串口通讯数据异常
本篇文章只适合刚开始学习C#.Net,并使用串口通讯的同学借鉴。笔者也是在写C#与Arduino串口进行通讯的时候收到的数据异常,翻阅了其他CSDN博主对串口通讯的建议,最好就是使用线程对接收的数据进行处理。废话不多说,下面展示线程方法和原方法。
- 使用线程的方法
//定义
private delegate void SetTextCallBack(string strValue);
private SetTextCallBack setCallBack;
Thread threadPortData;
SerialPort serialPort1 = new SerialPort();
//窗口初始化
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
string[] str = SerialPort.GetPortNames();
if (str == null)
{
MessageBox.Show("没有检测到串口,请先连接底板上的USB再打开软件!", "Error");
return;
}
//添加串口项目 获取计算机上有多少个串口
foreach (string s in System.IO.Ports.SerialPort.GetPortNames())
{
cb_SerialPort.Items.Add(s);
}
}
/// <summary>
/// 打开串口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void B_OpenSerialPort_Click(object sender, EventArgs e)
{
string SerName = cb_SerialPort.SelectedItem.ToString();//获取串口号的选择项
string SerBaudRate = "115200";//获取当前的波特率
Int32 SBaudRate = Convert.ToInt32(SerBaudRate);
serialPort1.PortName = SerName; //设置串口号
serialPort1.BaudRate = SBaudRate; //设置波特率
serialPort1.DataBits = 8; //设置数据位
serialPort1.StopBits = StopBits.One;//设置停止位
serialPort1.Parity = Parity.None; //设置校验位
serialPort1.Open();//打开串口
if (serialPort1.IsOpen == true)
{
MessageBox.Show("打开串口成功");
setCallBack = new SetTextCallBack(SetValue);//设置回调文本
threadPortData = new Thread(new ThreadStart(DataRecive));//初始化
threadPortData.IsBackground = true;//设置为后台线程
threadPortData.Start();//启动线程
}
}
/// <summary>
/// 接收数据线程
/// </summary>
private void DataRecive()
{
while (true)
{
string strData = serialPort1.ReadExisting();//读取流入串口的数据
this.tb_test.Invoke(setCallBack, strData);//在窗口线程上执行指定委托
serialPort1.DiscardInBuffer();//清空缓冲区数据,等待下次接收
Thread.Sleep(1000);
}
}
/// <summary>
/// 处理串口数据并显示(这里并没有进行详细的处理,可根据自己的需求来处理)
/// </summary>
/// <param name="strValue"></param>
private void SetValue(string strValue)
{
tb_test.Text = strValue;
}
笔者是用的winform来编程的,因此在使用串口的时候需要导入一些类using System.Threading;using System.IO.Ports;,在此过程中用到了委托事件,因为winform的窗口是用的一个线程来实现的,不能在一个线程里面对窗口的控件进行处理,委托事件就不受影响,接下来的是笔者利用委托事件来进行串口数据接收的
使用事件接收串口数据
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
//检查是否含有串口
string[] str = SerialPort.GetPortNames();
if (str == null)
{
MessageBox.Show("没有检测到串口,请先连接底板上的USB再打开软件!", "Error");
return;
}
//添加串口项目 获取计算机上有多少个串口
foreach (string s in System.IO.Ports.SerialPort.GetPortNames())
{
cb_SerialPort.Items.Add(s);
}
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);//事件处理实例化
}
/// <summary>
/// 串口消息接收
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string strData;//用于存取串口的数据
//readLine()方法在进行读取一行时,只有遇到回车(\r)或者换行符(\n)才会返回读取结果
strData = serialPort1.ReadExisting();//串口收到的数据
tb_test.Text = strData;
serialPort1.DiscardInBuffer();//清空缓冲区数据,等待下次接收
}
在事件处理过程中,只要缓冲区有消息,系统就会自动读取,因此需要清除缓冲,在接收过程中数据接收不完整大概是因为缓冲区的数据还没有读取完整就被清理掉了,因此建议使用串口通讯还是用线程比较合适。