普通電腦沒有通用的輸入輸出口(GPIO),但有時候我就想輸入一個開關量。
比如讓用戶拉一下拉繩開關就啟動某個應用,比如裝一個觸點開關判斷門是打開的還是關閉的,比如....
需求是如此簡單,你都不願意花幾十塊錢去買一個單片機,更不用說PCI擴展卡、PLC之類的了。。怎麼辦吶?
有辦法!最簡單的用串口就能實現。
原理:
串口的pin4[DTR]和pin7[RTS] 可以輸出+6V的電(好吧,你的電腦上不一定是+6V,但肯定大於+3V就可以了),將該輸出分別接入到pin1[DCD]、pin6[DSR]、pin8[CTS],在PC上就能檢測出來,從而實現開關量輸入。
核心代碼:
//往PIN口輸出電壓 SerialPort.DtrEnable = true; SerialPort.RtsEnable = true; //判斷PIN是否有電壓輸入 bool cd = SerialPort.CDHolding; bool dsr = SerialPort.DsrHolding; bool cts = SerialPort.CtsHolding;
知道原理,剩下的就好辦了。
首先是接線:(你需要一個9針串口母頭、若干個開關、導線、電烙鐵)
如圖,我接了3個開關,4作為公共引腳,1、6、8分別接一個開關用於輸入信號。當然,你只接一個開關也可以的。
(電腦主板上的帶針的是公頭,接線要用母頭否則插不到電腦上,如果沒有可以到電子城去買一個很便宜的,上面的編號很小要仔細看
沒有串口的筆記本可以淘寶上買一條USB轉串口線也可以的)
然後寫一段代碼不停檢測1、6、8口是否有輸入
/******************************************** * ------------- * \ 1 2 3 4 5 / * \ 6 7 8 9 / * --------- * 原理: * 4[DTR]作為+6V電源 也可以用[RTS]替代[DTR] * 軟件中不停檢測 * 1[CD ] * 6[DSR] * 8[CTS] * 三個端口的電壓變化 *********************************************/ using System; using System.IO.Ports; using System.Threading; namespace PortSignalReader { /// <summary> /// /// </summary> public delegate void SwitchEventHandler(Pin pin); /// <summary> /// 用一個串口采集3路開關輸入信號(也叫鋼節點或繼電器輸入) /// </summary> public class SerialPortSwitch { private const int PRIORITY = 20; /// <summary> /// 瞬時信號過濾時間 /// </summary> private const int FILTER = 100; private readonly SerialPort port = new SerialPort(); private readonly PinState[] pins; public event SwitchEventHandler SwitchOn; public event SwitchEventHandler SwitchOff; public bool IsRunning { get; private set; } public bool StopPedding { get; private set; } public SerialPortSwitch(string portName) { this.port.PortName = portName; this.port.BaudRate = 9600; this.port.Parity = Parity.None; this.port.DataBits = 8; this.port.StopBits = StopBits.Two; this.port.ReadBufferSize = 8; this.port.WriteBufferSize = 8; this.port.DtrEnable = true; this.port.RtsEnable = true; pins = new[] { new PinState {PinName = Pin.CD}, new PinState {PinName = Pin.CTS}, new PinState {PinName = Pin.DSR}, }; } public void Start() { if(IsRunning) return; IsRunning = true; StopPedding = false; try { Thread thread = new Thread(OnRunning); thread.Name = "SerialPortSwitch"; thread.Start(); } catch { IsRunning = false; StopPedding = false; throw; } } public void Stop(bool waitUntilStoped = true) { if (IsRunning) StopPedding = true; if (waitUntilStoped) { int timeout = Environment.TickCount + 10 * 1000; while (Environment.TickCount < timeout) { Thread.Sleep(100); if (IsRunning == false) return; } throw new TimeoutException("Stop SerialPortSwitch failed"); } } private void OnRunning() { try { port.Open(); while (StopPedding == false) { foreach (PinState pin in pins) { CheckState(pin); } Thread.Sleep(PRIORITY); } } catch (Exception ex) { //TODO:log error. System.Diagnostics.Debug.WriteLine("SerialPortSwitch term:" + ex); } finally { IsRunning = false; StopPedding = false; } } private void CheckState(PinState pin) { bool newHoding = GetPinHoding(pin.PinName); if (pin.IsHoding == newHoding) { pin.HodingStableTime = Environment.TickCount; } if (Environment.TickCount - pin.HodingStableTime > FILTER) { pin.IsHoding = newHoding; if (pin.IsHoding) { if (SwitchOn != null) SwitchOn(pin.PinName); } else { if (SwitchOff != null) SwitchOff(pin.PinName); } } } private bool GetPinHoding(Pin pin) { switch (pin) { case Pin.CD: return port.CDHolding; case Pin.DSR: return port.DsrHolding; case Pin.CTS: return port.CtsHolding; default: throw new ArgumentOutOfRangeException(); } } } /// <summary> /// 串口中的3個信號針 /// </summary> public enum Pin { CD = 1, DSR = 6, CTS = 8, } public class PinState { public Pin PinName { get; set; } public bool IsHoding { get; set; } public int HodingStableTime { get; set; } } }
Man函數:
class Program { static void Main(string[] args) { const string PORT_NAME = "COM6";//設置成你自己的端口 SerialPortSwitch portSwitch = new SerialPortSwitch(PORT_NAME); portSwitch.SwitchOn += pin => { Console.WriteLine(pin + "\tOn"); }; portSwitch.SwitchOff += pin => { Console.WriteLine(pin + "\tOff"); }; portSwitch.Start(); Console.WriteLine("串口輸入運行中,按任意鍵結束..."); Console.ReadKey(); portSwitch.Stop(); } }