另類,用串口實現普通電腦的開關量輸入

来源:http://www.cnblogs.com/shouce/archive/2016/03/18/5290674.html
-Advertisement-
Play Games

普通電腦沒有通用的輸入輸出口(GPIO),但有時候我就想輸入一個開關量。 比如讓用戶拉一下拉繩開關就啟動某個應用,比如裝一個觸點開關判斷門是打開的還是關閉的,比如.... 需求是如此簡單,你都不願意花幾十塊錢去買一個單片機,更不用說PCI擴展卡、PLC之類的了。。怎麼辦吶? 有辦法!最簡單的用串口就


普通電腦沒有通用的輸入輸出口(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();
        }
    }

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言:最近在阿裡雲申請了一個雲伺服器,然後已買了一個功能變數名稱。比如www.haha.com ; 在雲伺服器上安裝了tomcat ,訪問伺服器就成了 http://www.haha.com:8080/ 。 這個8080怎麼看都不舒服,問題是怎麼去掉8080埠號呢? 訪問地址 : http://www.h
  • 使用redmine創建問題的時候,可能會發現沒有我們需要的屬性,這時候我們可以添加自定義的屬性。 以添加滿意度屬性為例: 1.進入redmine管理界面,選擇自定義屬性 2.選擇問題下麵的新建自定義屬性 3.按照需求添加屬性,把需要跟蹤的問題標簽勾選上 4.現在我們創建問題的時候就有自定義的屬性了
  • u8 是 unsigned charu16 是 unsigned shortu32 是 unsigned int
  • 1.在要配置互信的機器(web-1和web-2)上生成各自經過認證的key文件。 2.將所有的key文件彙總到一個總的認證文件夾中。 3.將打包的key發給想要進行互信的機器(web-1,web-2)
  • 開始學習hadoop啦!!! 在Ubuntu14.04上新建了一個名為hadoop的用戶,但總是遇到各種許可權問題,於是就想乾脆把這個賬戶變成root賬戶。 網上查到說是直接修改/etc/sudoers,修改時提示read-only,修改不了,自然而然想到去修改文件的許可權, sudo chown u+
  • 三、gdb調試(下)01.查看運行時數據print - 查看變數值ptype - 查看類型print array - 查看數組print *array@len - 查看動態記憶體print x =5 - 改變運行時數據#vi simple.c#include<stdio.h>long fun(int
  • 系統來自系統媽:http://www.xitongma.com 電腦公司最新GHOST win7系統32位優化精簡版V2016年3月 系統概述 電腦公司ghost win7 x86(32位)萬能裝機版集成的軟體符合電腦公司及電腦城裝機絕大多數人要求及喜好,既大眾,又時尚,人人喜歡,處處適用。自動判斷
  • asp.net 編譯錯誤類型“同時存在於”不同的dll中. 出現這種錯誤大概有三種情況: 1、ASPX頁面,一個*.ASPX,對應著一個*.cs文件,兩者其實是一個文件,通過兩者實現代碼分離,每個*.aspx頁面都引用著自身的CS文件:如果兩個頁面引用了相同得.CS文件,在發佈得時候也會出現這種錯誤
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...