串口通信
SerialPort类
SerialPort sp = new SerialPort("COM1"); 或者 SerialPort sp = new SerialPort();sp.PortName = "COM1";
这两种写法是等效的;获得串口“COM1”的操作权,就是创建一个SerialPort对象,然后对象的属性PortName初始化为指定的串口名“COM1”,即可用该对象操作串口“COM1”,如:设置串口的通信参数,打开串口,发送数据,接收数据,关闭串口等;
SerialPort类的重要属性:
(1)PortName
赋予哪个串口名字,就是操作哪个串口;
(2)DataBits
数据位的位数,有7,8,9三种情况,计算机编程语言认为8bit为一个字节,所以一般我们用8bit做为一帧数据帧的数据部分,这样数据帧到达接收方,接收方解析一个数据帧提取出数据位即是一个字节;
(3)Parity
奇偶校验的方式,Parity.Even 奇校验;Parity.Odd 偶校验;Parity.None 不校验;不校验数据帧,能增加传输数据的效率,但是通信的可靠性降低;
(4)StopBits
停止位的位数,StopBits.One StopBits.OnePointFive Two 指的是停止位持续几个电平;
(5)BaudRate
波特率,串口通信的速率,值越大串口传输数据越快;如果是异步串口通信的话,二者的波特率应该尽可能无限接近,允许有细微误差;同步串口通信的话,双方一般使用同一个时钟,保证通信双方的波特率严格一致;
检查机器上有无串口,串口的数量,具体串口名字
string[] GetPortName() //返回的数组的Length ==0,表示无串口 //Length > 0时候,表示有串口,Length的大小就是串口的数量 //字符串数组的每一个元素就是串口的名字
打开串口和关闭串口
sp.IsOpen //指示串口是否处于打开状态,true打开,false未打开;打开已经打开过的串口会抛出异常; sp.Open() //打开串口 sp.Close() //关闭串口
向串口写数据
public void Write(string) //发送字符串 //假设sp的Encoding属性是ASCII,写入字符串“abc”,那么实际写入发送缓存3个字节; //如果Encoding属性是Unicode,那么实际写入发送缓存6个字节; public void Write(byte[],int32,int32) //发送字节数组 //第一个参数是函数外已经创建好的字节数组的引用,第二个参数是从字节数组的第几个字节开始写,一般为0,第三个参数表示本次要写入几个字节; public void Write(char[],int32,int32) //发送字符数组 //用法参考上述两个重载;特别说明,Encoding属性同样影响写入发送缓存的字节数量,不同的编码方式,虽然发送的是同一个字符数组,但是实际上写入发送缓存的字节数量不同! public void WriteLine(string) //发送一行字符串 //发送完string,紧接着向发送缓存写入一个NewLine字符串;
从串口读数据
public int Read (byte[] buffer, int offset, int count); //返回读到的字节数量 public int Read (char[] buffer, int offset, int count); //返回读到的字节数量
public int ReadByte(); //从SerialPort输入缓冲区同步读取一个字节 //如果读到末尾,返回-1 public int ReadChar() //从SerialPort输入缓冲区同步读取一个字符
读取数据可比发送数据复杂多了!
接收方接收到的数据都在接收缓存中,ReadBufferSize是设定的缓存的大小,默认是4096;BytesToRead表示缓存中暂存到的已经收到的字节数量;
当串口检查到有字节到达时,会触发DataReceived事件,ReceivedBytesThreshold属性能设置缓存中接收到多少字节后才触发该事件,默认是1。
值得注意的是,该事件在辅助线程中触发,所以并不能保证每个字节到达都能触发一次该事件。所以假设:
我收到10个字节,却只触发了2次;如果这两次读不干净缓存中的所有数据,那么剩下的数据在你下一次read()之前就一直留在缓存中而无法利用。
解决方案:
1,开辟一个线程,该线程实时检查BytesToRead,不为0就读取;
2,制定通信协议,在触发事件中,一直检查到结束字节,再停止
private static void DataReceivedHandler( object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string indata = sp.ReadExisting(); Console.WriteLine("Data Received:"); Console.Write(indata); }