树莓派笔记(三) 使用 RPi.GPIO 模块

我的未来我决定 提交于 2020-10-09 18:15:31

树莓派笔记(三) 使用 RPi.GPIO 模块

RPi.GPIO

RPI.GPIO是python的一个模块,树莓派官方系统默认已经安装

使用python控制GPIO需要导入RPI.GPIO模块

  1. 导入模块
#导入模块并检查它是否成功:
import RPi.GPIO  as GPIO 
tryimport RPi.GPIO  as GPIO 
except RuntimeError :
    print"导入RPi.GPIO时出错,可能是权限问题"

引脚简介

引脚编号

RPi.GPIO中使用的IO引脚编号有两种方法。

  1. BOARD编号系统。如下图中物理接口。使用此编号系统的优点是,无论树莓派的版本如何,您的硬件将始终可以工作。您无需重新连接连接器或更改代码。
  2. BCM编号系统。不同版本的树莓派不一样可能要重新修改代码,这是一种较低级别的工作方式-指Broadcom SOC上的通道号。您必须始终使用哪个通道号到达树莓派板上哪个引脚的图表。您的脚本可能会在树莓派板的修订版之间中断。

引脚功能
如下图,功能名一栏写名了树莓派引脚的功能
主要有如下分类

  • 电源引脚
    • 5v、3.3v :为输出5v、3.3v电源
    • 0v /GND :即负极,或接地级
  • GPIO引脚
    • 通用输入输出引脚,可编程控制高低电平
  • 其他功能引脚
    • i2c --> SDA,SCL
    • SPI —> MOSI,MISO,SCLK 等等

查询引脚编号
若忘了引脚编号,又找不到图,你可以在树莓派linux终端中输入命令查询引脚编号,如下

gpio readall

引脚图

在这里插入图片描述

引脚设置

指定引脚编号系统

上面提到,树莓派有多个编号系统,在编程之前需要指定一个编号系统。指定后,即使用该编号进行编程,若使用其他编号会导致错误

GPIO.setmode(GPIO.BOARD) #指定为BOARD编号
  # or
GPIO.setmode(GPIO.BCM)#指定为BCM编号

若要检测已经使用了什么编号可使用

mode = GPIO.getmode()

mode为GPIO.BOARD,GPIO.BCM、None,其意义显而易见

配置通道

GPIO引脚是通用输入输出引脚,其是可以作为输入或输出所用
因此使用之前,你需要告诉系统,该引脚你需要作为输入还是输出

设置为输入模式

GPIO.setup(引脚,GPIO.IN)

还可以设置上拉电阻(具体用处后面会介绍)
GPIO.setup(引脚,GPIO.IN,pull_up_down=GPIO.PUD_UP)
下拉电阻
GPIO.setup(引脚,GPIO.IN,pull_up_down=GPIO.PUD_DOWN)

设置为输出模式

GPIO.setup(引脚,GPIO.OUT)

设置为输出并初始为为HIGH或LOW
GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)

可以同时 设置多个引脚
chan_list  =  [ 1112 ]      
                       #你可以用元组代替,即:
                       #chan_list =11,12)
GPIO.setup(chan_list, GPIO.OUT)

注意 引脚的编号为你上面指定的编号系统 ❗️❗️❗️

释放引脚

程序结束不释放引脚是一个很危险的行为❗️❗️❗️❗️❗️❗️

假如执行程序时 你设置引脚输出为高电平,而程序结束时你未释放引脚它将保持这一状态,一旦意外接触到该引脚与GND将会短路,烧毁你的树莓派

释放引脚:

GPIO.cleanup()

注意,同时GPIO.cleanup()也会清除正在使用的引脚编号系统。

输出

根据上文,进行输出操作前,应有

import RPi.GPIO  as GPIO 
tryimport RPi.GPIO  as GPIO 
except RuntimeError :
    print"导入RPi.GPIO时出错,可能是权限问题")
GPIO.setmode(GPIO.BCM)#指定为BCM编号
GPIO.setup(17,GPIO.OUT)

设置 GPIO 针脚的输出状态:


GPIO.output(channel, state) 
state可以是0 / GPIO.LOW / False   ---  低电平
      或者 1 / GPIO.HIGH / True   ---  高电平

输出切换,高变低,低变高

GPIO.output(channel, not GPIO.input(channel))

pwm

脉宽调制(PWM)是指用微处理器的数字输出来对模拟电路进行控制,是一种对模拟信号电平进行数字编码的方法

创建一个 PWM 实例:
p = GPIO.PWM(channel, frequency)
启用 PWM:
p.start(dc)   # dc 代表占空比(范围:0.0 <= dc >= 100.0)
更改频率:
p.ChangeFrequency(freq)   # freq 为设置的新频率,单位为 Hz
更改占空比:
p.ChangeDutyCycle(dc)  # 范围:0.0 <= dc >= 100.0
停止 PWM:
p.stop()

示例

import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
  
p = GPIO.PWM(12, 50)  # 通道为 12 频率为 50Hz
p.start(0)
try:
    while 1:
        for dc in range(0, 101, 5):
            p.ChangeDutyCycle(dc)
            time.sleep(0.1)
        for dc in range(100, -1, -5):
            p.ChangeDutyCycle(dc)
            time.sleep(0.1)
except KeyboardInterrupt:
    pass
p.stop()
GPIO.cleanup()

输入

输入要比输出复杂一些

上拉/下拉电阻

如果输入引脚没有接其他器件(或者开关关闭),那么这个引脚将处于浮动的状态,即可能高电平可能低电平,或者在两者之间切换。这时候读取引脚的值没有意义。所以我们需要上拉/下拉电阻,使引脚状态确定

  1. 物理方法
    将一个 10K 的电阻连接在输入通道与 3.3V(上拉)
    或 输入通道与0V之间(下拉)

  2. 程序方法
 上拉电阻 
GPIO.setup(引脚,GPIO.IN,pull_up_down=GPIO.PUD_UP)
下拉电阻
GPIO.setup(引脚,GPIO.IN,pull_up_down=GPIO.PUD_DOWN)

轮询输入

这是最简易的一种方式,在某个时间点检查输入值。这即是所谓的“轮询 ”,而且如果您的程序在错误的时间里进行了读取,可能会错过某个输入值。在循环中运用轮询,有可能使处理器资源紧张。

示例

if GPIO.input(channel):
    print('Input was HIGH')
else:
    print('Input was LOW')
    
循环中等待按钮被按下后进行轮询
while GPIO.input(channel) == GPIO.LOW:
    time.sleep(0.01)  # 为 CPU 留出 10 毫秒,供其处理其它事物

中断和边检检测

用这种方法输入不会因为cpu在忙其他事而错过输入,且占用 CPU 资源很少

边缘就是是从 HIGH 到 LOW 的过度(下降临界值falling edge)或从 LOW 到 HIGH 的过度(上升临界值rising edge)

检测到边缘时执行线程回调函数

  1. wait_for_edge(channel, state) 函数

    用于在检测到边缘之前阻止程序的运行。
    上面的示例中,等待按钮被按下的语句可以改写为:
    GPIO.wait_for_edge(channel, GPIO.RISING)

    如果您只想等待一段时间,则可以使用timeout参数:

#上升沿等待最多5秒(超时以毫秒为单位)
pin= GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
if pin is None:
    print('Timeout occurred')
else:
    print('Edge detected on pin', pin)
  1. event_detected(channel, state) 函数

    函数被设计用于循环中有其它东西时使用,但不同于轮询的是,它不会错过当 CPU 忙于处理其它事物时输入状态的改变。这在类似使用 Pygame 或 PyQt 时主循环实时监听和响应 GUI 的事件是很有用的。

GPIO.add_event_detect(channel, GPIO.RISING)  # 在通道上添加上升临界值检测
do_something()
if GPIO.event_detected(channel):
    print('Button pressed')

state可以为GPIO.RISING、GPIO.FALLING、GPIO.BOTH

线程回调

RPi.GPIO 在第二条线程中执行回调函数。这意味着回调函数可以同您的主程序同时运行,并且可以立即对边缘进行响应。例如:

def my_callback(channel):
    print('这是一个边缘事件回调函数!')
    print('在通道 %s 上进行边缘检测'%channel)
    print('该程序与您的主程序运行在不同的进程中')
  
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback)  # 在通道上添加上升临界值检测
... 其它程序代码 ...

如果您需要多个回调函数:

def my_callback_one(channel):
    print('回调 1')
  
def my_callback_two(channel):
    print('回调 2')
  
GPIO.add_event_detect(channel, GPIO.RISING)
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)

注意,在该示例中,回调函数为顺序运行而不是同时运行。这是因为当前只有一个进程供回调使用,而回调的运行顺序是依据它们被定义的顺序。

开关防抖

每次按钮按下时,回调操作被调用不止一次。这种现象被称作“开关抖动 ”。这里有两种方法解决开关抖动问题:

  1. 物理方法 将一个 0.1uF 的电容连接到开关上。
  2. 软件方法防止抖动
    使用软件方式抖动,可以在您指定的回调函数中添加 bouncetime= 参数。
    抖动时间需要使用毫秒为单位进行书写。例如:
    在通道上添加上升临界值检测,忽略由于开关抖动引起的小于 200ms 的边缘操作


GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)

或者

GPIO.add_event_callback(channel, my_callback, bouncetime=200)
remove_event_detect()

如果你不希望你的程序检测边缘事件,可以将它停止:

GPIO.remove_event_detect(channel)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!