所謂串口,也叫串列介面,即COM口,採用串列通訊方式(即資料一位一位的傳送)的介面。也就是電腦後面D形9針插口。
最近做了兩個都和串口編程有關的功能,一個是不斷電供應系統,一個是RS232型串口印表機。因為是串口所以主要的用法都不難,痛點是對裝置的相應命令的理解和使用上。因為不同類型的、不同廠家的裝置命令是不同的,因為也沒法總一個總結。那就對於串口的簡單用法做一些總結吧。
主要用到的類是SerialPort,在System.IO.Ports下。傳裝置的基本使用步驟如下:
1、設定串口的參數。因為不同的裝置對串口的參數要求是不同的,最常見就是傳輸速率,一般好像都是9600。
2、開啟串口。也就是SerialPort的Open()方法。
3、想串口寫命令或寫常值內容。一般情況下,如果是數字類型的命令都是十六進位的,當然也有十進位的,不過如果有十六進位和十進位兩種,我覺得最好用十六進位的,因為十六進位好轉換為byte數組。
向串口寫命令的方法是SerialPort的Write(byte[] buffer, int offset, int count)。比如一個命令,十六進位下:00 FF,十進位下:00 255;那麼這段命令最終轉為byte[]時,00和FF分別轉換,但是對於00和255顯然就不怎麼方便了。看一下後面的一個例子就明白了。
4,接收傳回值。向串口發送命令,有的是指示執行操作的,有的是查詢狀態的,因此需要讀取傳回值。
下面對於某一個串口裝置的控制,寫一個簡單的例子。
1、字元操作類,因為串口寫入的須要是byte數組型,讀出又要將byte數組轉為string,一般命令也是十六進位的。所以轉換的方法需要用到。
/// <summary> /// 串口字元類 /// </summary> public class CharOperated { public static string ByteArrayToHexString(byte[] byteData) { StringBuilder result = new StringBuilder(byteData.Length * 3); foreach (byte b in byteData) { result.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' ')); } return result.ToString().ToUpper(); } /// <summary> /// 十六進位的字串轉成byte數組 /// </summary> /// <returns></returns> public static byte[] HexStringToByteArray(string content) { content = content.Replace(" ", ""); byte[] buffer = new byte[content.Length / 2]; for (int i = 0; i < content.Length; i += 2)//因為十六進位命令一般都是兩位十六進位一起。 { buffer[i / 2] = (byte)Convert.ToByte(content.Substring(i, 2), 16); } return buffer; } /// <summary> /// 16進位編碼的字串解析成 ascii碼 /// </summary> /// <param name="statusCode"></param> /// <returns></returns> public static string DecodeHexToAsc(string statusCode) { string rtn = ""; statusCode = statusCode.Replace(" ", ""); for (int i = 0; i < (statusCode.Length / 2); i++) { string key = statusCode.Substring(2 * i, 2); int asii = Convert.ToInt32(key, 16);//將16進位字串轉換成其ASCII碼(實際是Unicode碼) rtn += Chr(asii); } return rtn; } /// <summary> /// ascii碼轉字元 /// </summary> /// <param name="asciiCode"></param> /// <returns></returns> public static string Chr(int asciiCode) { if (asciiCode >= 0 && asciiCode <= 255) { System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding(); byte[] byteArray = new byte[] { (byte)asciiCode }; string strCharacter = asciiEncoding.GetString(byteArray); return (strCharacter); } return string.Empty; } }
2、對串口的開啟,發送命令,關閉等的類。
public class ComManager { private SerialPort comm = null; private static string currentPortName = string.Empty; private static object sendCommandLock = new object(); public ComManager(SerialPort comm) { if (this.comm == null) { this.comm = comm; } } /// <summary> /// 串口參數設定 /// </summary> private void SetSerialPort() { //根據裝置要求設定參數,比如某一裝置要求參數如下: comm.BaudRate = 9600; comm.Encoding = System.Text.Encoding.GetEncoding("GB2312"); comm.RtsEnable = true; } /// <summary> /// 開啟串口裝置 /// </summary> private void SerialPortOpen() { try { if (comm.IsOpen) { comm.Close(); } currentPortName = "COM1";//此處可指定串口,也可以即時讀取裝置到底串連在那個串口,實際情況根據裝置情況而定。 //currentPortName = DoGetUPSPortName();以某一裝置為例遍曆所有串口,找到串連該裝置的串口 SetSerialPort(); if (string.IsNullOrEmpty(currentPortName)) { return; } comm.PortName = currentPortName; comm.Open(); } catch { } } /// <summary> /// 向串口發送命令 /// </summary> /// <param name="sendstring"></param> public void SendDatastring(string sendstring) { lock (sendCommandLock) { //16進位轉二進位 byte[] data = CharOperated.HexStringToByteArray(sendstring); //開啟口串口裝置 SerialPortOpen(); //發送命令到串口裝置 if (comm.IsOpen) { comm.DiscardInBuffer(); comm.Write(data, 0, data.Length); } } } /// <summary> /// 向串口寫字串 /// </summary> /// <param name="sendstring"></param> public void WriteLingContent(string content) { lock (sendCommandLock) { //開啟口串口裝置 SerialPortOpen(); //發送報文到串口裝置 if (comm.IsOpen) { comm.WriteLine(content); comm.DiscardInBuffer(); } } } /// <summary> /// 讀取連接埠傳回值 /// </summary> /// <returns></returns> private string DoReadPortResult() { string resultString = string.Empty; try { int bytes = comm.BytesToRead; byte[] buffer = new byte[bytes]; comm.Read(buffer, 0, bytes); string rtnStrPort = CharOperated.ByteArrayToHexString(buffer); resultString = CharOperated.DecodeHexToAsc(rtnStrPort); if (comm.IsOpen) { comm.DiscardInBuffer(); } } catch { } return resultString; } /// <summary> /// 擷取某一裝置的連接埠號碼 /// </summary> /// <returns></returns> private string DoGetUPSPortName() { string commName = string.Empty; try { Computer localComputer = new Computer(); foreach (string portItem in localComputer.Ports.SerialPortNames) { try { if (string.IsNullOrEmpty(portItem)) { continue; } commName = portItem; byte[] data = CharOperated.HexStringToByteArray("發送的命令"); comm.Close(); SetSerialPort(); comm.PortName = portItem; comm.Open(); //發送報文到串口裝置 if (comm.IsOpen) { comm.DiscardInBuffer(); comm.Write(data, 0, data.Length); } Thread.Sleep(500); //if (條件) //{ //} //else //{ // commName = string.Empty; //} } catch { } finally { if (comm.IsOpen) { comm.Close(); } } } } catch { } finally { if (comm.IsOpen) { comm.Close(); } } return commName; } }
使用
class Program { private static SerialPort serialPortCom = new SerialPort();//串口定義 。 private static string receiveResult = string.Empty; //接收資料。 static void Main(string[] args) { ComManager cm = new ComManager(serialPortCom); cm.SendDatastring("00FF");//命令 cm.WriteLingContent("內容"); Thread.Sleep(200);//停幾百毫秒,然後讀取 string result = SerialPortComDataReceived(); } private static string SerialPortComDataReceived() { if (serialPortCom == null || !serialPortCom.IsOpen) { return string.Empty; } int bytes = serialPortCom.BytesToRead; byte[] buffer = new byte[bytes]; serialPortCom.Read(buffer, 0, bytes); receiveResult = string.Empty; receiveResult = CharOperated.ByteArrayToHexString(buffer); receiveResult = receiveResult.Trim(); return receiveResult; } }
詳細代碼下載:http://download.csdn.net/detail/yysyangyangyangshan/5516631