首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

求解 c# SerialPort 接收老是要过很久才能收到,该怎么处理

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

求解 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")+ ' ');

热点排行