我要实现一个读取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);
        }貌似不行,请高手指点一下。串口通信

解决方案 »

  1.   

    注册这个事件是怎么不行了呢?
    有可能数据是分成几次触发该事件,建议改一下保存数据的方式,以免当数据分成两次的时候,后面的数据将之前的覆盖掉
    每次收到数据都加放到receiveData里
    用mySerialPort.Read(receiveData, 0, receiveLength);只能存储一次的数据
      

  2.   


    你先看一下这几个方法,我再仔细说:
    一、串口类    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") + " ";
                }
    程序正常运行。
    加上之后,死循环了,收不到数据,软件没有反应。现象就是这样的,请问这是什么原因?
      

  3.   

    while (c.flag)
                    ;
    你想类似CPU啊,都不休息下的,至少要添加Thread.Sleep(1);另外所有的数据接收处理逻辑都必须写在mySerialPort.DataReceived事件里面,你却写在他处,大错,后面就不看了,这个问题不纠正,你的程序就没法使用。
      

  4.   

    “所有的数据接收处理逻辑都必须写在mySerialPort.DataReceived事件里面”没懂是什么意思。我在mySerialPort.DataReceived事件里只是获取“返回的数据”,在其他地方处理不行吗?求大神再说仔细点,谢了!
      

  5.   

    http://www.cnblogs.com/jxnclyk/archive/2010/06/07/1753290.html
    我经常用的串口都是整一个串口的类,上面是一个例子,建议你下载看看。
    关于加sleep()这个,我遇到的有的设备是需要加的,发送过后sleep(N),再去接数据,这个正常
      

  6.   

    我知道用sleep,但是sleep不精确。
    要读的数据少的时候,大概sleep(100)就够了,读的数据多的时候,有时得sleep(1000),没有一个sleep的标准,sleep多少秒是凭经验给给的。万一在程序中不够就很得不到数据,很麻烦。所以,我就想说能不能不用sleep,而用类似于消息或者其他方式来快速得到数据,避免用sleep延时造成的麻烦。
      

  7.   

    发送两次导致界面不响应,可能是卡在 while (c.flag);
    在第二次发送那打个断点,就在此处c.SendData(sendData, 0, sendData.Length);
    等程序运行到此处,继续在Class1内部打断点,打在if (mySerialPort.BytesToRead == receiveLength),这样可以查看发送第二次数据时,串口是否有收到来自IC卡的数据。如果第二次发送数据根本没有收到IC卡回传的数据,那程序会卡在第二次的while(c.flag)
      

  8.   

    读卡器端在连续发送给pc机之间最好sleep一下,并且SerialPort,ReceivedBytesThreshold=1设置为1,否则会出现问题的,希望对你有帮助
      

  9.   

    巧了,这两天也在做一个IC卡系统
    首先想知道你是读卡用的,还是来采集数据用的?
    如果读卡用的,应该想要的结果是读到卡之后一直等待有返回值(超过多长时间的延迟).        /// <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事件,
    一个线程一直发送"给我数据",另一个线程来处理接收到的数据
      

  10.   

    在DataReceivedHandler 是说已经读到串口数据了,访问e就可以了, 该事件里再去读就冲突了.