最近寫C#串口通信程序,系統(tǒng)是B/S架構(gòu)。SerialPort類有一個DataReceived事件,用來接收串口返回的數(shù)據(jù),但這種方式在C/S架構(gòu)下很好用,但B/S就不好處理了。所以寫了一個同步模式接收返回數(shù)據(jù)的方法,不使用DataReceived事件。經(jīng)過測試,可以正常使用。
一、MachineFactory類
為什么使用工廠類:售貨機由不止一個廠家提供,接口協(xié)議都不一樣。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;using System.IO;using System.IO.Ports;namespace IMachineDll{ /// <summary> /// 售貨機工廠類 /// </summary> public class MachineFactory { /// <summary> /// 貨機接口緩存 /// </summary> PRivate static Dictionary<string, IMachine> dicMachine = new Dictionary<string, IMachine>(); /// <summary> /// 鎖變量 /// </summary> public static object _lock = new object(); /// <summary> /// 創(chuàng)建售貨機類 /// </summary> /// <param name="path">DLL物理路徑</param> /// <param name="dllName">DLL名稱(不含擴展名),命名空間必須為DLL名稱加“Dll”后綴,類名必須和DLL名稱相同</param> /// <param name="com">串口名稱,如:COM1</param> public static IMachine Create(string path, string dllName, string com) { if (!dicMachine.ContainsKey(dllName) || dicMachine[dllName] == null) { using (FileStream fs = new FileStream(path + dllName + ".dll", FileMode.Open, Fileaccess.Read)) { using (MemoryStream ms = new MemoryStream()) { byte[] byteArray = new byte[4096]; while (fs.Read(byteArray, 0, byteArray.Length) > 0) { ms.Write(byteArray, 0, byteArray.Length); } Assembly assembly = Assembly.Load(ms.ToArray()); dicMachine[dllName] = (IMachine)assembly.CreateInstance(dllName + "Dll." + dllName, false, BindingFlags.Default, null, new object[] { com }, null, null); } } } return dicMachine[dllName]; } }}View Code二、Machine類
1、變量與構(gòu)造函數(shù)

/// <summary>/// 串口資源/// </summary>private SerialPort serialPort = null;public Machine(string com){ serialPort = new SerialPort(com, 9600, Parity.None, 8, StopBits.One); serialPort.ReadBufferSize = 1024; serialPort.WriteBufferSize = 1024;}View Code2、向串口發(fā)送數(shù)據(jù),同步接收返回數(shù)據(jù)的方法:

/// <summary>/// 向串口發(fā)送數(shù)據(jù),讀取返回數(shù)據(jù)/// </summary>/// <param name="sendData">發(fā)送的數(shù)據(jù)</param>/// <returns>返回的數(shù)據(jù)</returns>private byte[] ReadPort(byte[] sendData){ lock (MachineFactory._lock) { //打開連接 if (!serialPort.IsOpen) serialPort.Open(); //發(fā)送數(shù)據(jù) serialPort.Write(sendData, 0, sendData.Length); //讀取返回數(shù)據(jù) DateTime dt = DateTime.Now; while (serialPort.BytesToRead == 0) { Thread.Sleep(1); if (DateTime.Now.Subtract(dt).TotalMilliseconds > 5000) //如果5秒后仍然無數(shù)據(jù)返回,則視為超時 { throw new Exception("主版無響應(yīng)"); } } Thread.Sleep(50); byte[] recData = new byte[serialPort.BytesToRead]; serialPort.Read(recData, 0, recData.Length); //關(guān)閉連接 if (serialPort.IsOpen) serialPort.Close(); return recData; }}View Code優(yōu)化版:

/// <summary>/// 向串口發(fā)送數(shù)據(jù),讀取返回數(shù)據(jù)/// </summary>/// <param name="sendData">發(fā)送的數(shù)據(jù)</param>/// <returns>返回的數(shù)據(jù)</returns>private byte[] ReadPort(byte[] sendData){ lock (MachineFactory._lock) { //打開連接 if (!serialPort.IsOpen) serialPort.Open(); //發(fā)送數(shù)據(jù) serialPort.Write(sendData, 0, sendData.Length); //讀取返回數(shù)據(jù) DateTime dt = DateTime.Now; while (serialPort.BytesToRead < 2) { Thread.Sleep(1); if (DateTime.Now.Subtract(dt).TotalMilliseconds > 5000) //如果5秒后仍然無數(shù)據(jù)返回,則視為超時 { throw new Exception("主版無響應(yīng)"); } } List<byte> recList = new List<byte>(); byte[] recData = new byte[serialPort.BytesToRead]; serialPort.Read(recData, 0, recData.Length); recList.AddRange(recData); int length = recData[1] + 3; //報文數(shù)據(jù)總長度 while (recList.Count < length) { if (serialPort.BytesToRead > 0) { recData = new byte[serialPort.BytesToRead]; serialPort.Read(recData, 0, recData.Length); recList.AddRange(recData); } Thread.Sleep(1); } //關(guān)閉連接 if (serialPort.IsOpen) serialPort.Close(); return recList.ToArray(); }}View Code3、發(fā)送聯(lián)機指令:

/// <summary>/// 聯(lián)機/// </summary>/// <param name="msg">傳出錯誤信息</param>/// <returns>聯(lián)機是否成功</returns>public bool Connect(out string msg){ byte[] sendData = new byte[] { 0x01, 0x01, 0x00, 0x00 }; CommonUtil.CalCheckCode(sendData); byte[] recData = ReadPort(sendData); if (recData.Length >= 4 && recData[0] == 0x01 && recData[1] == 0x02 && recData[2] == 0x00 && CommonUtil.ValidCheckCode(recData)) { switch (recData[3]) { case 0x00: msg = "控制主板正在重啟"; return false; case 0x01: msg = "聯(lián)機成功"; return true; case 0x02: msg = "控制主板正在維護"; return false; case 0x03: msg = "控制主板收到的數(shù)據(jù)格式不正確"; return false; default: msg = "未知狀態(tài)"; return false; } } else if (IsRunning(recData, out msg) || !IsConnected(recData, out msg)) { return false; } else { throw new Exception("貨機返回的數(shù)據(jù)格式不正確"); }}View Code三、如何使用
1、Controller層代碼(還不完善,僅測試,真實情況是根據(jù)硬件信息,確定調(diào)用哪個Dll使用哪個串口):
新聞熱點
疑難解答