普通电脑没有通用的输入输出口(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(); } }