什么是 GPIO

GPIO 是 General Purpose Input Output 的缩写,即“通用输入输出”。 Raspberry Pi 有两列 GPIO 引脚, Raspberry Pi 通过这两行引脚进行一些硬件上的扩展,与传感器进行交互等等。

Raspberry Pi B+/2B/3B/3B+/Zero 引脚图

简单的讲,每一个 GPIO 引脚都有两种模式:输出模式(OUTPUT)和输入模式(INPUT)。输出模式类似于一个电源,Raspberry Pi 可以控制这个电源是否向外供电,比如打开外部的 LED 小灯,当然最有用的还是向外部设备发送信号。和输出模式相反,输入模式是接收外部设备发来的信号。其中还包含两种特殊的输入模式:上拉输入(INPUT_PULLUP)和下拉输入(INPUT_PULLDOWN)。上拉输入就是内部的上拉电阻接 VCC ,将该引脚设置为高电平,下拉输入则相反。

GPIO 通常采用标准逻辑电平,即高电平和低电平,用二进制 0 和 1 表示。在这两值中间还有阈值电平,即高电平和低电平之间的界限。Arduino 会将 -0.5 ~ 1.5 V 读取为低电平,3 ~ 5.5 V 读取为高电平, Raspberry Pi 未查到相关资料。GPIO 还可用于中断请求,即设置 GPIO 为输入模式,值达到相应的要求时进行中断。

相关类

此处默认各位是面向对象的程序员,具有一定的 C# 基础,这里只介绍本人认为常用的方法,介绍将以代码注释的形式体现。

GPIO 操作主要依赖于 GpioController 类 。这个类位于 System.Device.Gpio 名称空间下。

GpioController

  1. // GpioController 即 GPIO 控制器
  2. // GPIO 引脚依靠 GpioController 初始化
  3. public class GpioController : IGpioController, IDisposable
  4. {
  5. // 构造函数
  6. public GpioController();
  7. // PinNumberingScheme 即引脚编号方案,是一个枚举类型,包含 Board 和 Logical 两个值。
  8. // 可以看上方的 Raspberry Pi 引脚图,以 GPIO 17 为例,如果实例化时选 Logical ,那么打开引脚时需要填写 17。
  9. // 如果实例化时选 Board ,那么打开引脚时需要填写右侧灰色方框内的值,即 11 。
  10. public GpioController(PinNumberingScheme numbering);
  11. // GpioDriver 用于指定要使用的 GPIO 驱动,比如 libgpiod 或 sysfs
  12. public GpioController(PinNumberingScheme numberingScheme, GpioDriver driver);
  13. // 方法
  14. // 打开 GPIO 引脚
  15. // pinNumber 需要填写和 PinNumberingScheme 相对应的值。
  16. // PinMode 是设置 GPIO 的模式,如输入、输出、上拉、下拉
  17. public void OpenPin(int pinNumber, PinMode mode);
  18. // 关闭 GPIO 引脚
  19. public void ClosePin(int pinNumber);
  20. // 判断某个引脚是否打开
  21. // 注意:引脚连续打开会抛出异常
  22. public bool IsPinOpen(int pinNumber);
  23. // 读取指定引脚的值
  24. public PinValue Read(int pinNumber);
  25. // 向指定的引脚写入值
  26. public void Write(int pinNumber, PinValue value);
  27. // 为指定引脚的值改变时注册回调(即上文中提到的 GPIO 中断)
  28. // PinEventTypes 是值改变的类型,包括上升沿(Rising,0->1)和下降沿(Falling,1->0),注意当设置为 None 时不会触发
  29. // PinChangeEventHandler 为回调事件
  30. public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback);
  31. // 为指定引脚的值改变时注销回调
  32. public void UnregisterCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback);
  33. }

人体红外传感器实验

人体红外传感器是基于周围区域的红外热来检测运动的,也称被动红外传感器(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 (Pin 11)

LED

  • VCC & 220 Ω resistor - GPIO 27 (Pin 14)
  • GND - GND

使用 Docker 运行示例

示例地址:https://github.com/ZhangGaoxing/dotnet-core-iot-demo/tree/master/src/Hcsr501

  1. docker build -t pir-sample -f Dockerfile .
  2. docker run --rm -it --device /dev/gpiomem pir-sample

代码

  1. 打开 Visual Studio ,新建一个 .NET Core 控制台应用程序,项目名称为“PIR”。

  2. 引入 System.Device.Gpio NuGet 包。

  3. 新建类 Hcsr501,替换如下代码:

    1. public class Hcsr501 : IDisposable
    2. {
    3. private GpioController _controller;
    4. private readonly int _outPin;
    5. /// <summary>
    6. /// 构造函数
    7. /// </summary>
    8. /// <param name="pin">OUT Pin</param>
    9. public HCSR501(int outPin, PinNumberingScheme pinNumberingScheme = PinNumberingScheme.Logical)
    10. {
    11. _outPin = outPin;
    12. _controller = new GpioController(pinNumberingScheme);
    13. _controller.OpenPin(outPin, PinMode.Input);
    14. }
    15. /// <summary>
    16. /// 是否检测到人体
    17. /// </summary>
    18. public bool IsMotionDetected => _controller.Read(_outPin) == PinValue.High;
    19. /// <summary>
    20. /// Cleanup
    21. /// </summary>
    22. public void Dispose()
    23. {
    24. _controller?.Dispose();
    25. _controller = null;
    26. }
    27. }
  4. Program.cs 中,将主函数代码替换如下:

    1. static void Main(string[] args)
    2. {
    3. // HC-SR501 OUT Pin
    4. int hcsr501Pin = 17;
    5. // LED Pin
    6. int ledPin = 27;
    7. // 获取 GPIO 控制器
    8. using GpioController ledController = new GpioController(PinNumberingScheme.Logical);
    9. // 初始化 PIR 传感器
    10. using Hcsr501 sensor = new Hcsr501(hcsr501Pin, PinNumberingScheme.Logical);
    11. // 打开 LED 引脚
    12. ledController.OpenPin(ledPin, PinMode.Output);
    13. while (true)
    14. {
    15. // 检测到了人体
    16. if (sensor.IsMotionDetected == true)
    17. {
    18. ledController.Write(ledPin, PinValue.High);
    19. Console.WriteLine("Detected! Turn the LED on.");
    20. }
    21. else
    22. {
    23. ledController.Write(ledPin, PinValue.Low);
    24. Console.WriteLine("Undetected! Turn the LED off.");
    25. }
    26. Thread.Sleep(1000);
    27. }
    28. }
  5. 发布、拷贝、更改权限、运行

效果图

  如何改进?

剔除主函数循环,尝试使用 RegisterCallbackForPinValueChangedEvent() 注册一个回调进行检测。

供参考

  1. General-purpose input/output - Wikipedia:https://en.wikipedia.org/wiki/General-purpose_input/output
  2. GPIO - Raspberry Pi Documentation:https://www.raspberrypi.org/documentation/usage/gpio/
  3. GPIO source code:https://github.com/dotnet/iot/tree/master/src/System.Device.Gpio/System/Device/Gpio

张高兴的 .NET Core IoT 入门指南:(二)GPIO 的使用的更多相关文章

  1. 张高兴的 .NET Core IoT 入门指南:(一)环境配置、Blink、部署

    如何在 Raspberry Pi 的 Raspbian 上构建使用 GPIO 引脚的 IoT 程序?你可能会回答使用 C++ 或 Python 去访问 Raspberry Pi 的引脚.现在,C# 程 ...

  2. 张高兴的 .NET Core IoT 入门指南:(四)使用 SPI 进行通信

    什么是 SPI 和上一篇文章的 I2C 总线一样,SPI(Serial Peripheral Interface,串行外设接口)也是设备与设备间通信方式的一种.SPI 是一种全双工(数据可以两个方向同 ...

  3. 张高兴的 .NET Core IoT 入门指南:(三)使用 I2C 进行通信

    什么是 I2C 总线 I2C 总线(Inter-Integrated Circuit Bus)是设备与设备间通信方式的一种.它是一种串行通信总线,由飞利浦公司在1980年代为了让主板.嵌入式系统或手机 ...

  4. 张高兴的 .NET Core IoT 入门指南:(五)PWM 信号输出

    什么是 PWM 在解释 PWM 之前首先来了解一下电路中信号的概念,其中包括模拟信号和数字信号.模拟信号是一种连续的信号,与连续函数类似,在图形上表现为一条不间断的连续曲线.数字信号为只能取有限个数值 ...

  5. 张高兴的 .NET Core IoT 入门指南:(五)串口通信入门

    在开始之前,首先要说明的是串口通信所用到的 SerialPort 类并不包含在 System.Device.Gpio NuGet 包中,而是在 System.IO.Ports NuGet 包中.之所以 ...

  6. 张高兴的 .NET IoT 入门指南:(七)制作一个气象站

    距离上一篇<张高兴的 .NET Core IoT 入门指南>系列博客的发布已经过去 2 年的时间了,2 年的时间 .NET 版本发生了巨大的变化,.NET Core 也已不复存在,因此本系 ...

  7. 张高兴的 .NET IoT 入门指南:(八)基于 GPS 的 NTP 时间同步服务器

    时间究竟是什么?这既可以是一个哲学问题,也可以是一个物理问题.古人对太阳进行观测,利用太阳的投影发明了日晷,定义了最初的时间.随着科技的发展,天文观测的精度也越来越准确,人们发现地球的自转并不是完全一 ...

  8. require.js入门指南(二)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  9. kotlin 语言入门指南(二)--代码风格

    语言风格 这里整理了 kotlin 惯用的代码风格,如果你有喜爱的代码风格,可以在 github 上给 kotlin 提 pull request . 创建DTOs(POJSs/POCOs) 文件: ...

随机推荐

  1. Visual Studio 监视与快速监视即时窗口没有智能提示

    工具->选项->文本编辑器->C# 将 自动列出成员 参数信息 都勾选上

  2. MyCat安装配置

    Mycat : 数据库分库分表中间件 http://www.mycat.io/ mycat运行需要JVM,所以先安装java环境,JDK1.7以上.数据库采用mysql5.7,或者8.0 下载 下载地 ...

  3. [日常] Go语言圣经-Panic异常,Recover捕获异常习题

    Go语言圣经-Panic异常1.当panic异常发生时,程序会中断运行,并立即执行在该goroutine中被延迟的函数(defer 机制)2.不是所有的panic异常都来自运行时,直接调用内置的pan ...

  4. JVM 堆内存和非堆内存

    转载自:http://www.importnew.com/27645.html 堆和非堆内存 按照官方的说法:“Java 虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此 ...

  5. java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/animation/AnimatorCompatHelper

    在开发过程中,有的时候引入了多个三方库.在调用的时候会出现版本对应不上的原因.就会出现如标题的异常. 原因 经过查找,项目中使用的RecycleView类,进入类里面发现AnimatorCompatH ...

  6. JAVA设计模式详解(二)----------观察者模式

    有一个模式可以帮助你的对象知悉现况,不会错过该对象感兴趣的事,对象甚至在运行时可以决定是否要继续被通知,如果一个对象状态的改变需要通知很多对这个对象关注的一系列对象,就可以使用观察者模式 .观察者模式 ...

  7. H5添加禁止缩放功能

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scal ...

  8. git 本地安装

    一.基本安装 1.下载Git   官方地址为:https://git-scm.com/download/win 2.下载完之后,双击安装,全部选择默认. 3.选择安装目录 4.选择组件 5.开始菜单目 ...

  9. JAVA中销毁session的代码

    ServletActionContext.getRequest().getSession().invalidate();

  10. php判断是不是移动设备

    <?php function isMobile() {     // 如果有HTTP_X_WAP_PROFILE则一定是移动设备     if (isset ($_SERVER['HTTP_X_ ...