跳转至

数字输入与输出

数字输入与输出是最常用的一种外设通信方式,虽然每一个端口只有0和1两种状态,但却可以组合出各种各样的变化。

数字输入与输出原理

数字输入与输出,也称为通用输入输出,全称是General-purpose input/output,大部分情况下,我们都会用简称GPIO

GPIO的功能,主要是指这个管脚可以作为数字信号的输入或者输出使用,到底是输入还是输出呢,这需要我们使用系统寄存器来进行配置。

当GPIO被设置为输入模式时,就可以读取这个管脚上的电平高低,从而实现读取外部信号的功能,比如外部按键的信号,就是这样读取的。

当GPIO被设置为输出模式时,我们就可以主动改变管脚的电平高低了,这样就能通过电平的变化,控制外部的设备,比如点亮或者熄灭一个LED灯。

除此之外,一些IO口还可以配置成其他功能,比如PWM输出,串口通信等等。

image-20220614150538900

关于旭日X3派的管脚定义,大家可以参考这张图,他会显示每个管脚具体可以实现什么功能。

这里需要说明一点,旭日X3派的管脚序号定义有三种编码方式:

第一种就是Board编码,这种就是按照主板上管脚排针编号,分别对应1~40号排针。

第二种就是BCM编码,这种方式是参考 Broadcom SOC 的通道编号,侧重CPU寄存器,在使用BCM库或者使用python编程时,常采用的一种编码方式。

第三种就是X3编码,可以理解为是旭日X3派自己的编码方式,在使用旭日派自己的驱动库编程时,会使用到这种编码。

大家在后续编程开发中,需要结合函数接口的说明,使用对应的引脚编号,不然可能会出现意料之外的问题。

引脚复用配置工具

虽然从硬件上看,扩展出来的引脚只有40个,不过大部分引脚还可以配置成多种功能,这样延伸出来变化可就多了,那如何配置引脚的不同功能呢?

image-20220614150606500

我们可以使用旭日X3派中提供的srpi-config工具进行配置。

直接在终端中输入这个指令,就可以看到这样的窗口,okay配置对应管脚为专用功能,disabled配置对应管脚为GPIO模式,按照自己的需要进行配置即可,配置完成后重启才会生效。

了解了GPIO的概念,接下来我们就要开始编程啦。

数字输入编程

首先我们来看下最基本的数字输入测试,读取一个按键的状态。

硬件接线

image-20220614150750894

我们将按键的一边连接到旭日X3派的38号引脚上,这是一个GPIO的接口,另一边连接到39号引脚,也就是GND。

原理很简单,按键没按下时,导线是断开的,GPIO是默认的状态,按键按下后,导线就会导通,GPIO的状态变成了GND。

这样,我们就可以通过电平的变化,知道按键的状态啦。

运行例程

我们不妨来运行一下,看下实际效果是不是这样。

$ sudo python3 simple_input.py

我们将一个按键开关接到对应的管脚上, 然后连接到旭日X3PI当中,运行刚才的程序。之后我们按下或是松开按键时,他都会打印出对应的电平变化。

image-20220614150857325

按下显示的就是LOW,也就是低电平,松开就是HIGH,也就是高电平。

代码解析

数字输入的功能实现啦,我们来看下代码是如何实现的。

simple_input.py:

#!/usr/bin/env python3

import Hobot.GPIO as GPIO
import time

# 定义使用的GPIO通道为38
input_pin = 38 # BOARD 编码 38

def main():
    prev_value = None

    # 设置管脚编码模式为硬件编号 BOARD
    GPIO.setmode(GPIO.BOARD)
    # 设置为输入模式
    GPIO.setup(input_pin, GPIO.IN)

    print("Starting demo now! Press CTRL+C to exit")
    try:
        while True:
            # 读取管脚电平
            value = GPIO.input(input_pin)
            if value != prev_value:
                if value == GPIO.HIGH:
                    value_str = "HIGH"
                else:
                    value_str = "LOW"
                print("Value read from pin {} : {}".format(input_pin, value_str))
                prev_value = value
            time.sleep(1)
    finally:
        GPIO.cleanup()

if __name__=='__main__':
    main()

我们在Python中需要引入X3Pi的GPIO库,从而使用对应的GPIO功能。

  • 主函数里首先需要定义了一个变量来存储这个管脚的电平信号。

  • 进行初始化,设置管脚的编码模式为BOARD模式,之后定义输入用的管脚,这里使用的是BOARD编码,因为他是第38个管脚,所以为38号。

  • 之后的话就会进入到循环当中,这样的一个函数就可以读出当前的电平值。

  • 没有按下按键的时候,38管脚和GND是断开的,他就是高电平,按下按键时,就和GND导通了,这个管脚就会编程低电平。

  • 如果电平值和上一次存储的不一致,后面的判断就会判断出是升高还是降低,最后会把结果打印出来。
  • 松开按键时同理。

数字输出编程

GPIO不止有输入功能,还有输出功能,大家应该经常看到电子设别上的LED灯吧,这就是典型的IO输出控制的设备,我们也来试一试。

硬件接线

我们将一个LED灯的正极连接到了2号引脚,这是5V电源,用来给LED供电的,不过LED电阻小,为了不至于烧坏,我们最好还是在电路中串联一个电阻来限制电流大小。

image-20220614151226448

接下来,当LED的负极接到GND,也就是电源的0V上时,LED两边会因为有电势差而被点亮;当LED的负极也连接到高电平,也就是5V的时候,会因为两边没有电势差,也就不会被点亮。

这个负极的电平信号我们就用GPIO来输出,所以我们把LED的负极连接到任意的GPIO引脚上,比如38号,将这个引脚设置为输出模式,当输出高电平时,灯就会熄灭,输出低电平,灯就会被点亮。

image12

把这两个动作放到一个循环中,就可以实现闪烁的功能啦。

运行示例程序

快来运行例程试一试吧,按照刚才的设置,将实物连接完成,然后连接到X3Pi,运行程序,就可以看到这个LED就会开始闪烁了。

$ sudo python3 simple_input.py

image-20220614151501438

代码解析

simple_out.py:

#!/usr/bin/env python3

import Hobot.GPIO as GPIO
import time

# 定义使用的GPIO通道为38
output_pin = 38 # BOARD 编码 38

def main():
    # 设置管脚编码模式为硬件编号 BOARD
    GPIO.setmode(GPIO.BOARD)
    # 设置为输出模式,并且初始化为高电平
    GPIO.setup(output_pin, GPIO.OUT, initial=GPIO.HIGH)
    # 记录当前管脚状态
    curr_value = GPIO.HIGH
    print("Starting demo now! Press CTRL+C to exit")
    try:
        # 间隔1秒时间,循环控制LED灯亮灭
        while True:
            time.sleep(1)
            GPIO.output(output_pin, curr_value)
            curr_value ^= GPIO.HIGH
    finally:
        GPIO.cleanup()

if __name__=='__main__':
    main()

数字输入与输出集成

学习了GPIO的输入与输出功能后,我们就可以做一些自动化的功能了。

硬件接线

image-20220614151655707

比如我们同时连接一个按键和LED灯,尝试实现按键被按下,灯被点亮,松开,灯熄灭,这样的功能。

运行示例程序

我们通过这个例程来试一试效果如何?

$ sudo python3 button_led.py

image-20220614151739029

我们来看一下具体的操作,同样的,按照刚才的设置,将实物连接完成,然后连接到X3Pi,运行刚才的程序。按下按键后,就可以看到LED被点亮了,松开之后,LED就熄灭了。

image16

代码解析

button_led.py

#!/usr/bin/env python3

import Hobot.GPIO as GPIO
import time

# 定义使用的GPIO通道:
# 36号作为输出,可以点亮一个LED
# 38号作为输入,可以接一个按钮
led_pin = 36 # BOARD 编码 36
but_pin = 38 # BOARD 编码 38

# 禁用警告信息
GPIO.setwarnings(False)

def main():
    prev_value = None

    # Pin Setup:
    GPIO.setmode(GPIO.BOARD)  # BOARD pin-numbering scheme
    GPIO.setup(led_pin, GPIO.OUT)  # LED pin set as output
    GPIO.setup(but_pin, GPIO.IN)  # Button pin set as input

    # Initial state for LEDs:
    GPIO.output(led_pin, GPIO.LOW)
    print("Starting demo now! Press CTRL+C to exit")
    try:
        while True:
            curr_value = GPIO.input(but_pin)
            if curr_value != prev_value:
                GPIO.output(led_pin, curr_value)
                prev_value = curr_value
                print("Outputting {} to Pin {}".format(curr_value, led_pin))
            time.sleep(1)
    finally:
        GPIO.cleanup()  # cleanup all GPIO

if __name__ == '__main__':
    main()

基本的配置还是一样的,引入基本的库,然后设置为BOARD模式,然后初始化两个管脚,一个用来读取按键的通断,一个用来控制LED的亮灭,之后只需要判断按键的状态来做出对应的控制LED的动作就可以了。

图片1