張高興的 .NET Core IoT 入門指南:(二)GPIO 的使用
什麼是 GPIO
GPIO 是 General Purpose Input Output 的縮寫,即“通用輸入輸出”。 Raspberry Pi 有兩行 GPIO 引腳, Raspberry Pi 通過這兩行引腳進行一些硬體上的擴充套件,與感測器進行互動等等。
Raspberry Pi B+/2B/3B/3B+/Zero 引腳圖
簡單的講,每一個 GPIO 引腳都有兩種模式:輸出模式(OUTPUT)和輸入模式(INPUT)。輸出模式類似於一個電源,Raspberry Pi 可以控制這個電源是否向外供電,比如開啟外部的 LED 小燈,當然最有用的還是向外部裝置傳送訊號。輸入模式相當於電源的陰極,還是以 LED 小燈為例,只不過這次 LED 小燈的陽極接著外部電源,一個電路只有產生電壓差時才會有電流,因此要想讓小燈亮需要讓電流流入 Raspberry Pi 中。和輸出模式相反,輸入模式是接收外部裝置發來的訊號。
GPIO 通常採用標準邏輯電平,即高電平和低電平,用二進位制 0 和 1 表示。在這兩值中間還有閾值電平,即高電平和低電平之間的界限。 Arduino 會將 -0.5 ~ 1.5 V 讀取為低電平,3 ~ 5.5 V 讀取為高電平, Raspberry Pi 未查到相關資料。GPIO 還可用於中斷請求,即設定 GPIO 為輸入模式,值達到相應的要求時進行中斷。
相關類(Class)
此處預設各位是面向物件的程式設計師,具有一定的 C# 基礎,這裡只介紹本人認為常用的方法,介紹將以程式碼註釋的形式體現。
GPIO 操作主要依賴於兩個類: GpioController 、 GpioPin 。這兩個類位於 System.Devices.Gpio 名稱空間下。
GpioController
// GpioController 即 GPIO 控制器 // GPIO 引腳依靠 GpioController 初始化 public class GpioController : IDisposable { // 建構函式 /* PinNumberingScheme 即引腳編號方案,是一個列舉型別,包含 Board 和 Gpio 兩個值。 * 可以看上方的 Raspberry Pi 引腳圖,以 GPIO 17 為例,如果例項化時選 Gpio ,那麼開啟引腳時需要填寫 17。 * 如果例項化時選 Board ,那麼開啟引腳時需要填寫右側灰色方框內的值,即 11 。 */ public GpioController(PinNumberingScheme numbering = PinNumberingScheme.Gpio); // 第二個建構函式中的 GpioDriver 應該是用於擴充套件的,一般還是用 Raspberry Pi 預設的 GPIO 驅動。 public GpioController(GpioDriver driver, PinNumberingScheme numbering = PinNumberingScheme.Gpio); // 屬性 // 獲取已開啟的所有 GPIO 引腳 public IEnumerable<GpioPin> OpenPins { get; } // 方法 // 開啟 GPIO 引腳,pinNumber 需要填寫和 PinNumberingScheme 相對應的值。 public GpioPin OpenPin(int pinNumber); // 關閉 GPIO 引腳 public void ClosePin(int pinNumber); public void ClosePin(GpioPin pin); // 判斷某個引腳是否開啟 // 注意:引腳連續開啟會丟擲異常 public bool IsPinOpen(int pinNumber); }
GpioPin
// GpioPin 表示單個的引腳實體 // 需要通過 GpioController.OpenPin() 獲取 public class GpioPin : IDisposable { // 屬性 // 一個去抖時間,即在此時間間隔引腳電平變化,不觸發 ValueChanged 事件 public TimeSpan DebounceTimeout { get; set; } // 事件 // 引腳電平變化時觸發 public event EventHandler<PinValueChangedEventArgs> ValueChanged; // 方法 // 讀取當前引腳電平 public PinValue Read(); // 向引腳寫入指定電平 public void Write(PinValue value); }
人體紅外感測器實驗
示例地址: https://github.com/ZhangGaoxing/dotnet-core-iot-demo/tree/master/src/PIR
人體紅外感測器是基於周圍區域的紅外熱來檢測運動的,也稱被動紅外感測器(Passive Infra-Red, PIR)。
這裡使用的是 HC-SR501 。當感測器檢測到人體時,LED 小燈亮,當感測器未檢測到人體時,LED 小燈滅。
感測器影象
HC-SR501
硬體
名稱 | 數量 |
---|---|
HC-SR501 | x1 |
LED 小燈 | x1 |
220 Ω 電阻 | x1 |
杜邦線 | 若干 |
電路
HC-SR501
- VCC - 5V
- GND - GND
- OUT - GPIO 17
LED
- VCC & 220 Ω resistor - GPIO 27
- GND - GND
程式碼
- 開啟 Visual Studio ,新建一個 .NET Core 控制檯應用程式,專案名稱為“PIR”。
- 引入 System.Devices.Gpio NuGet 包。
-
新建類 HCSR501 ,替換如下程式碼(此處略有精簡,只為必要的程式碼,不包含自定義事件,詳細可檢視提供的示例):
public class HCSR501 : IDisposable { private GpioPin sensor; private readonly int pinOut; /// <summary> /// 建構函式 /// </summary> /// <param name="pin">OUT Pin</param> public HCSR501(int pin) { pinOut = pin; } /// <summary> /// 初始化 /// </summary> public void Initialize() { // 例項化 GpioController GpioController controller = new GpioController(PinNumberingScheme.Gpio); // 開啟引腳,設定模式為輸入模式 sensor = controller.OpenPin(pinOut, PinMode.Input); } /// <summary> /// 讀取 /// </summary> /// <returns>是否檢測到人體</returns> public bool Read() { // 當電平為高時,認為檢測到人體 if (sensor.Read() == PinValue.High) { return true; } else { return false; } } }
-
在 Program.cs 中,將主函式程式碼替換如下:
static void Main(string[] args) { // get the GPIO controller // 獲取 GPIO 控制器 GpioController controller = new GpioController(PinNumberingScheme.Gpio); // open PIN 27 for led // 為 led 開啟引腳 27 GpioPin led = controller.OpenPin(27, PinMode.Output); // initialize PIR sensor // 初始化感測器 HCSR501 sensor = new HCSR501(17); sensor.Initialize(); // loop // 迴圈 while (true) { if (sensor.Read() == true) { // turn the led on when the sensor detected infrared heat // 當感測器檢測到熱量時開啟 led led.Write(PinValue.High); Console.WriteLine("Detected! Turn the LED on."); } else { // turn the led off when the sensor undetected infrared heat // 當感測器未檢測到熱量時關閉 led led.Write(PinValue.Low); Console.WriteLine("Undetected! Turn the LED off."); } // wait for a second // 等待 1s Thread.Sleep(1000); } }
-
釋出、拷貝、更改許可權、執行
效果圖
如何改進?
剔除主函式迴圈,嘗試在自定義事件中進行檢測,即 GpioPin 的 ValueChanged 事件。
備註
下一篇文章將談談 IIC 匯流排的使用。