C#串口通信
在C#中使用串口通信比较方便,.Net 提供了现成的类, SerialPort类。
本文不对原理啥的进行介绍,只介绍SerialPort类的使用。
SerialProt类内部是调用了CreateFile,WriteFile等WinAPI函数来实现串口通信。
在后期的Windows编程系列中,我会详细介绍Windows的IO
打开串口
1 SerialPort sp = new SerialPort();2 3 public bool OpenSerialPort(string portName, string strBaudRate, string strDataBit, int stopBitIndex, int parityIndex)4 {5 6 if (sp.IsOpen)7 sp.Close();8 9 sp.PortName = portName; //串口号 10 sp.BaudRate = Convert.ToInt32(strBaudRate); //波特率 11 sp.DataBits = Convert.ToInt32(strDataBit); //数据位 12 sp.StopBits = (StopBits)stopBitIndex; //停止位 13 sp.Parity = (Parity)parityIndex; //奇偶校验位 14 sp.RtsEnable = true; //启用请求发送 (RTS) 信号 15 sp.ReadTimeout = 500; //超时时间 16 17 sp.Open(); //打开串口 18 19 }
关闭串口
1 public bool CloseSerialPort()2 {3 try4 {5 if (sp.IsOpen == true)6 {7 sp.Close(); //关闭串口8 return true;9 } 10 catch 11 { 12 return false; 13 } 14 }
发送普通字符数据
1 public bool SendNormalString(string data)2 {3 try4 {5 sp.Encoding = Encoding.ASCII;6 sp.Write(data);7 return true;8 }9 catch 10 { 11 return false; 12 } 13 }
发送十六进制数据
1 /// <summary>2 /// 转换成ASCII字符3 /// </summary>4 /// <param name="str"></param>5 /// <param name="format"></param>6 /// <returns></returns>7 private string GetASCIIString(string str, string format = "X2")8 {9 var asciiStr = ""; 10 11 for (int i = 0; i < str.Length; i++) 12 { 13 var asciiCode = (int)str[i]; 14 asciiStr += asciiCode.ToString(format); 15 } 16 17 return asciiStr; 18 }
1 /// <summary>2 /// ASCII字符转换成十六进制字节数组3 /// </summary>4 /// <param name="str"></param>5 /// <returns></returns>6 private byte[] ASCIIStringToHexByteArray(string str)7 {8 try9 { 10 str = str.Replace(" ", ""); 11 12 byte[] buffer = new byte[str.Length / 2]; 13 14 for (int i = 0; i < str.Length; i += 2) 15 { 16 buffer[i / 2] = Convert.ToByte(str.Substring(i, 2), 16); 17 } 18 19 return buffer; 20 } 21 catch 22 { 23 return new byte[] { }; 24 } 25 }
发送
1 sp.Write(buffer, 0, buffer.Length);
接收串口数据
接收串口数据需要响应SerialProt类的DataReceived事件,指示已通过由 SerialPort 对象表示的端口接收了数据。然后在DataReceived的事件处理函数中,使用SerialPort.Read函数来读取接收到的数据
1 sp.DataReceived += ReceiveData;
1 private void ReceiveData(object sender, SerialDataReceivedEventArgs e) 2 { 3 //在这里处理接收到的数据 4 }
处理接收到的数据
1 /// <summary>2 /// 接收原始数据3 /// </summary>4 /// <returns></returns>5 public string GetRawReceiveData()6 {7 try8 {9 var buffer = new byte[sp.BytesToRead]; 10 sp.Read(buffer, 0, sp.BytesToRead); 11 var data = ""; 12 if (buffer.Length > 0) 13 data = Encoding.ASCII.GetString(buffer); 14 return data; 15 } 16 catch (Exception ex) 17 { 18 return ""; 19 } 20 } 21 22 /// <summary> 23 /// 接收十六进制数据 24 /// </summary> 25 /// <returns></returns> 26 public string GetHexReceiveData() 27 { 28 try 29 { 30 var buffer = new byte[sp.BytesToRead]; 31 sp.Read(buffer, 0, sp.BytesToRead); 32 var data = ""; 33 if (buffer.Length > 0) 34 data = HexByteArrayToString(buffer); 35 return data; 36 } 37 catch (Exception ex) 38 { 39 return ""; 40 } 41 } 42 43 public string HexByteArrayToString(byte[] data) 44 { 45 try 46 { 47 StringBuilder sb = new StringBuilder(data.Length * 3); 48 foreach (byte b in data) 49 sb.Append(Convert.ToString(b, 16).PadLeft(2, '0')); 50 return sb.ToString().ToUpper(); 51 } 52 catch (Exception ex) 53 { 54 return ""; 55 } 56 }
注意:一次接收到的数据可能并不能组成我们定义的通信协议。建议:使用一个变量来记录接收到的数据。当接收 到的数据能组成一个完整的通信协议时,就返回这个通信协议。并从记录的数据中移除这一段数据。
示例代码