我要实现一个读取IC卡数据的软件,要用到串口通信,我用的类是SerialPort。问题是:当我用软件给串口发送“读取”指令时,必须要延时,才能收到“返回”的数据(因为读卡器的硬件速度和PC比起来比较慢)。大致相当于这样的过程>>>>发送
>>>>sleep
>>>>接收
>>>>sleep
>>>>发送
>>>>sleep
>>>>接收
……这样做的话造成延时不精确,有时候交互的次数多,延时很大,软件运行比较慢。我想知道有没有“检测串口有数据到来”的消息或者其他方法,就是当有数据到来之后,我立即进行读取数据,这样就比较快了。ps:我试了一下
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
receiveData.Initialize();
mySerialPort.Read(receiveData, 0, receiveLength);
}貌似不行,请高手指点一下。串口通信
>>>>sleep
>>>>接收
>>>>sleep
>>>>发送
>>>>sleep
>>>>接收
……这样做的话造成延时不精确,有时候交互的次数多,延时很大,软件运行比较慢。我想知道有没有“检测串口有数据到来”的消息或者其他方法,就是当有数据到来之后,我立即进行读取数据,这样就比较快了。ps:我试了一下
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
receiveData.Initialize();
mySerialPort.Read(receiveData, 0, receiveLength);
}貌似不行,请高手指点一下。串口通信
有可能数据是分成几次触发该事件,建议改一下保存数据的方式,以免当数据分成两次的时候,后面的数据将之前的覆盖掉
每次收到数据都加放到receiveData里
用mySerialPort.Read(receiveData, 0, receiveLength);只能存储一次的数据
你先看一下这几个方法,我再仔细说:
一、串口类 class Class1
{
public SerialPort mySerialPort = new SerialPort();
public byte[] receiveData = new byte[0xFF];
public byte receiveLength = 0;
public bool flag = true; public void OpenSerialPort()
{
mySerialPort.PortName = "COM5";
mySerialPort.BaudRate = 9600;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
} public void SendData(byte[] sendByte, int offset, int count)
{
mySerialPort.BaseStream.Flush();
mySerialPort.Write(sendByte, offset, count);
} public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
if (mySerialPort.BytesToRead == receiveLength)
{
receiveData.Initialize();
mySerialPort.Read(receiveData, 0, receiveLength);
flag = false;
}
}
}二、Form类 public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Class1 c = new Class1();
private void button1_Click(object sender, EventArgs e)
{
byte[] sendData = {0xff,0xa1,0x20,0x30};
c.receiveLength = 0x30 + 3;
c.SendData(sendData, 0, sendData.Length);
while (c.flag)
;
for (int i = 3; i < c.receiveLength;i++ )
{
richTextBox1.Text += c.receiveData[i].ToString("X2") + " ";
}
richTextBox1.Text += "\r\n"; //再发送一次数据
c.flag = true;
c.receiveLength = 0x30 + 3;
c.SendData(sendData, 0, sendData.Length);
while (c.flag)
;
c.flag = true;
for (int i = 3; i < c.receiveLength; i++)
{
richTextBox1.Text += c.receiveData[i].ToString("X2") + " ";
}
} private void Form1_Load(object sender, EventArgs e)
{
c.OpenSerialPort();
}
}
三、窗体如果发一次数据的话,就是没有button消息处理里的这段代码: //再发送一次数据
c.flag = true;
c.receiveLength = 0x30 + 3;
c.SendData(sendData, 0, sendData.Length);
while (c.flag)
;
c.flag = true;
for (int i = 3; i < c.receiveLength; i++)
{
richTextBox1.Text += c.receiveData[i].ToString("X2") + " ";
}
程序正常运行。
加上之后,死循环了,收不到数据,软件没有反应。现象就是这样的,请问这是什么原因?
;
你想类似CPU啊,都不休息下的,至少要添加Thread.Sleep(1);另外所有的数据接收处理逻辑都必须写在mySerialPort.DataReceived事件里面,你却写在他处,大错,后面就不看了,这个问题不纠正,你的程序就没法使用。
我经常用的串口都是整一个串口的类,上面是一个例子,建议你下载看看。
关于加sleep()这个,我遇到的有的设备是需要加的,发送过后sleep(N),再去接数据,这个正常
要读的数据少的时候,大概sleep(100)就够了,读的数据多的时候,有时得sleep(1000),没有一个sleep的标准,sleep多少秒是凭经验给给的。万一在程序中不够就很得不到数据,很麻烦。所以,我就想说能不能不用sleep,而用类似于消息或者其他方式来快速得到数据,避免用sleep延时造成的麻烦。
在第二次发送那打个断点,就在此处c.SendData(sendData, 0, sendData.Length);
等程序运行到此处,继续在Class1内部打断点,打在if (mySerialPort.BytesToRead == receiveLength),这样可以查看发送第二次数据时,串口是否有收到来自IC卡的数据。如果第二次发送数据根本没有收到IC卡回传的数据,那程序会卡在第二次的while(c.flag)
首先想知道你是读卡用的,还是来采集数据用的?
如果读卡用的,应该想要的结果是读到卡之后一直等待有返回值(超过多长时间的延迟). /// <summary>
/// 同步读取串口数据,不使用DataReceived事件时的方法,指定outTime时间会超时
/// </summary>
/// <param name="outTime">指定超时时间</param>
/// <returns>返回16进制命令字符串</returns>
public string SyncReadData(int outTime)
{
string rHex = string.Empty;
int timeOut = 0; //保存当前已经等待的时间
int maxTimeOut = outTime * 1000; //最多等待时间
int sleepTime = 10;//接受等待时间
while (true)
{
int r = this.BytesToRead;
if (r > 0)
{
byte[] buff = new byte[r];
this.Read(buff, 0, r);
rHex = ByteArrToHex(buff);
break;
}
Thread.Sleep(sleepTime);
timeOut += sleepTime;
if (timeOut > maxTimeOut)
{
//等待超时
break;
}
}
return rHex;
}
如果是"采集"数据,下位机将数据发过来,可以用DataReceivedHandler事件,
一个线程一直发送"给我数据",另一个线程来处理接收到的数据