读书人

求解 c# SerialPort 接收老是要过很久

发布时间: 2012-03-25 20:55:17 作者: rapoo

求解 c# SerialPort 接收老是要过很久才能收到
程序如下,电脑发下去之后,设备马上有返回,但是我的接收事件要等很久才能收到,高手指点

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Threading;

namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
SerialPort SP1 = new SerialPort();
List<string> xieyi = new List<string>();

public Form1()
{

InitializeComponent();
SP1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);

}



private void Form1_Load(object sender, EventArgs e)
{
string rdline;
int i;
comboBox1.SelectedItem=comboBox1.Items[0];
comboBox2.SelectedItem = comboBox2.Items[0];

try
{
FileStream sFile = new FileStream(".\\d645.txt", FileMode.Open);
StreamReader sr = new StreamReader(sFile);

rdline = sr.ReadLine();
while(rdline!=null)
{
xieyi.Add(rdline);
rdline = sr.ReadLine();
}

label1.Text = xieyi[0];

for (i=1;i<xieyi.Count;i++)
{
checkedListBox1.Items.Add(xieyi[i].Substring(0,4));
checkedListBox1.SetItemChecked(i-1, true);

}

}
catch (Exception ee)
{
MessageBox.Show("加载文件失败:"+ee);
}



}

private void button1_Click(object sender, EventArgs e)
{
try
{

SP1.PortName = comboBox1.SelectedItem.ToString();
SP1.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString());
SP1.Parity = Parity.Even;

SP1.ReceivedBytesThreshold = 1;
SP1.Open();
}
catch (Exception ee) { MessageBox.Show(comboBox1.SelectedItem.ToString() + "失败:"+ee); }

}

private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{

}

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{

}

private void button2_Click(object sender, EventArgs e)
{

}

private void label2_Click(object sender, EventArgs e)
{

}

private void button2_Click_1(object sender, EventArgs e)
{
int i=0;
while (checkedListBox1.GetItemChecked(i))
{
string s = xieyi[i+1];
int len = s.Length / 2;
byte[] bytes = new byte[len];
for (int j = 0; j < len; j++)
{
bytes[j] = Convert.ToByte((s.Substring(j * 2, 2)), 16);
}



try
{
SP1.Write(bytes, 0, len);
}
catch (Exception ee) { MessageBox.Show(comboBox1.SelectedItem.ToString() + "失败:" + ee); }
Thread.Sleep(1000);
richTextBox1.Text += "\r\n";

i++;
if (i >= checkedListBox1.Items.Count)
break;

}
}

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{

string tmpstr = "";
for (int i = 0; i < SP1.BytesToRead; i++)
{
tmpstr += Convert.ToString(SP1.ReadByte(), 16) + " ";

}
safeAddtrText(tmpstr);
}

public delegate void _SafeAddtrTextCall(string text);

private void safeAddtrText(string text)
{
if (this.InvokeRequired)
{
_SafeAddtrTextCall call =
delegate(string s)
{
richTextBox1.Text += s;
};

this.Invoke(call, text);
}
else
{
richTextBox1.Text += text;

}
}

private void richTextBox1_TextChanged(object sender, EventArgs e)
{

}

}
}

[解决办法]
1。检查波特率、奇偶校验等两边是否一致。
2。DataReceived方法越快越好(慢的话会导致缓冲区中的待读数据越来越多,最后溢出),所以最好把Invoke改成BeginInvoke,防止长时间同步等待UI线程更新界面。
3。DataReceived中的for循环:for (int i = 0; i < SP1.BytesToRead; i++),应把SP1.BytesToRead提到循环外:int bytesToRead = SP1.BytesToRead; 这样缓冲区中有多个数据时才能正确执行。
4。发送过程中不要用Thread.Sleep(1000); 这样会阻塞UI线程(当此时有接收数据到达,会因为要更新界面而被迫等待1秒),改成循环Application.DoEvents(); 并在循环中判断等待的时间是否超过1秒。
[解决办法]

C# code
 string tmpstr = "";  for (int i = 0; i < SP1.BytesToRead; i++)  {  tmpstr += Convert.ToString(SP1.ReadByte(), 16) + " ";  }
[解决办法]
C# code
 private void comPort_DataReceiveed(object sender, SerialDataReceivedEventArgs e)        {            if (bClosing)            {                return;            }            try            {                bListening = true;                int n = comPort.BytesToRead;                byte[] receiveByte = new byte[n];                comPort.Read(receiveByte, 0, n);                AddItemToListBox(receiveByte);                ReceiveCount += n;                ChangStatus("接收成功!");            }            finally            {                bListening = false;            }        }
[解决办法]
在for循环中,SP1.BytesToRead是不断变化的,每次调用ReadByte(),BytesToRead就会减1,
所以如果缓冲区有2个以上数据的时候,你的循环方式就读不到后面的数据。

byte[] readBuffer = new byte[SP.BytesToRead];
int byteLength = SP.Read(readBuffer, 0, SP.BytesToRead);
tmpstr = BitConverter.ToString(readBuffer).Replace('-', ' ');

[解决办法]
tmpstr = readBuffer.Aggregate("", (s, b) => s+b.ToString("x")+ ' ');

读书人网 >C#

热点推荐