欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-02-26 18:49:22
...

树莓派笔记(三) 使用 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

引脚图

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

引脚设置

指定引脚编号系统

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

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)