在.net下使用serialPort做串口通信开发,在环境状态比较好的情况下还是比较容易的。我们可是使用serialPort.write(),将组织好的byte数组写入到串口中。也可以通过serialPort的DataReceived 事件来触发读取。

    但是,如果通信情况不好,或者比特率较低的情况下,在接受的时候会出现很多情况,当触发一次Datareceived的事件,可能是收到了全部数据帧,也可能只收到了半个帧,第二次触发的时候,也许就是完整的一个帧了,这样就给写程序带来的N多问题。无法通过DataReceived事件来触发读取了。

   最后,没办法,想出一个变通的手法,因为我们可以知道serialPort中当前输入缓冲区的内容的大小,BytesToRead,我们可以在一段时间间隔内,获取这个值,如果它不改变了,说明后面没有数据了,也就是下位机发送完成。这个时间是和serialPort的波特率有关的。

  波特率的单位是 bps 就是 bit 每秒,所以换成字节的话,得除以8,在考虑上完成字节的头尾等,完成的一个字节是11bit,所以,我们就可以换算出 (波特率/11) 得到一秒可以发送的字节数,然后我们在拿 1000ms除以这个值,就可以得到 一个字节需要多少毫秒来发送: 1000/(波特率/11) 。

  理论上,我们等待这个时间,就可以获取到下一个字节了,但是考虑到实际情况,可能需要适当的延长时间,所以,我们可是适当的增加等待时间。

  我们可以使用timer来实现;

 

timer1.Interval = (1000 / (serialPort1.BaudRate / 11)) + 20;
int timer2Bytes = -1;
private void timer2_Tick(object sender, EventArgs e)
        {
int newBytes = serialPort1.BytesToRead;
if (timer2Bytes == newBytes && newBytes != 0)
            {
byte[] data = new byte[newBytes];
                serialPort1.Read(data, 0, data.Length);
if (data != null)
                {
                    textBoxResult.Text += BitConverter.ToString(data) + "\r\n";
                    Application.DoEvents();
                }
                timer2Bytes = -1;

            }
else
            {
                timer2Bytes = newBytes;
            }
        }


       OK,这样就基本完成了,但是依然还是有可能出现接受的帧不完整的情况,这个时候可以尝试在发送一次命令读取一次。这个好处是可以读取到通信时间,只需要在里面添加一个计时器,比如在 else下 添加 time += timer2.Interval ;  但是这个时间很不准确,不知道为什么。

最后一个比较好的方法就是:通过bytesToRead的长度来确定是否接受完成,并指定超时时限,这样的好处是,能保证接受到的就是长度符合的,否则就继续等,知道超时,可是,问题是必须事先知道,我读取的长度将会是多少,这对程序的扩展性等,都引来很多问题。纠结中。

继续研究如何比较好的实现,并精确的记录下通信时间;