RPi.GPIO Python模块
本文搬运于https://sourceforge.net/p/raspberry-gpio-python/wiki/Home/,进行了机器翻译与部分修改,2020.06.13更新。如有错误或翻译不当之处,劳烦各位指出,我会及时修改。
文章目录
Wiki: 代码示例
基本用法
要导入RPi.GPIO模块:
import RPi.GPIO as GPIO
通过这种方式,您可以在其余脚本中将其仅称为GPIO。
导入模块并检查是否成功:
try:
import RPi.GPIO as GPIO
except RuntimeError:
print("Error importing RPi.GPIO! This is probably because you need superuser privileges. You can achieve this by using 'sudo' to run your script")
引脚编号
RPi.GPIO中的Raspberry Pi上的IO引脚编号有两种方法。第一种是使用BOARD编号系统。这是指Raspberry Pi板的P1接头上的引脚号。使用此编号系统的优点是,无论RPi的主板版本如何,您的硬件将始终可以工作。您无需重新连接连接器或更改代码。
第二个编号系统是BCM编号。这是一种较低级别的工作方式-指Broadcom SOC上的通道号。您必须始终使用哪个通道号转到RPi板上哪个引脚的图表。您的脚本可能会在Raspberry Pi板的修订版之间中断。
要使用(强制)指定要使用的对象,请执行以下操作:
GPIO.setmode(GPIO.BOARD)
# or
GPIO.setmode(GPIO.BCM)
要检测设置了哪个引脚编号系统(例如,通过另一个Python模块):
mode = GPIO.getmode()
模式可设置为GPIO.BOARD,GPIO.BCM或无
警告事项
Raspberry Pi的GPIO上可能有多个脚本/电路。结果,如果RPi.GPIO检测到某个引脚已配置为默认值(输入)以外的其他值,则在尝试配置脚本时会收到警告。要禁用这些警告:
GPIO.setwarnings (False)
设置频道
您需要设置用作输入或输出的每个通道。要将通道配置为输入:
GPIO.setup(channel, GPIO.IN)
(其中channel是基于您指定的编号系统(BOARD或BCM)的通道号)。
有关设置输入通道的更多高级信息,请参见此处。
要将通道设置为输出:
GPIO.setup(channel, GPIO.OUT)
(其中channel是基于您指定的编号系统(BOARD或BCM)的通道号)。
您还可以为输出通道指定一个初始值:
GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)
设置多个频道
您可以为每个使用设置多个频道(从0.5.8版本开始)。例如:
chan_list = [11,12] # add as many channels as you want!
# you can tuples instead i.e.:
# chan_list = (11,12)
GPIO.setup(chan_list, GPIO.OUT)
输入项
读取GPIO引脚的值:
GPIO.input(channel)
(其中channel是基于您指定的编号系统(BOARD或BCM)的通道号)。这将返回其中一项 0 / GPIO.LOW / False or 1 / GPIO.HIGH / True.
输出量
设置GPIO引脚的输出状态:
GPIO.output(channel, state)
(其中channel是基于您指定的编号系统(BOARD或BCM)的通道号)。
状态可以是0 / GPIO.LOW / False or 1 / GPIO.HIGH / True.
输出到多个通道
您可以在同一使用中输出到多个频道(从0.5.8开始支持)。例如:
chan_list = [11,12] # also works with tuples
GPIO.output(chan_list, GPIO.LOW) # sets all to GPIO.LOW
GPIO.output(chan_list, (GPIO.HIGH, GPIO.LOW)) # sets first HIGH and second LOW
清理
在任何程序的最后,清理您可能使用过的所有资源都是一个好习惯。这种思想同样存在于RPi.GPIO中。通过将您使用过的所有通道返回到没有上拉/下拉的输入状态,可以避免因为引脚短路意外损坏你的树莓派。请注意,这只会清除脚本已使用的GPIO通道。另外,GPIO.cleanup()还会清除使用中的引脚编号系统。
在脚本末尾进行清理:
GPIO.cleanup()
可能不希望清理每个通道而在程序退出时留下一些设置。您可以清理单个频道,频道列表或频道组:
GPIO.cleanup(channel)
GPIO.cleanup( (channel1, channel2) )
GPIO.cleanup( [channel1, channel2] )
RPi板信息和RPi.GPIO版本
要查看有关您的树莓派的信息:
GPIO.RPI_INFO
要查看树莓派的主板版本:
GPIO.RPI_INFO['P1_REVISION']
GPIO.RPI_REVISION (deprecated)
要查看RPi.GPIO库的版本:
GPIO.VERSION
输入
有几种方法可以将GPIO输入程序中。第一种也是最简单的方法是在某个时间点检查输入值。这称为“轮询”,如果程序在错误的时间读取值,则可能会丢失输入。轮询是循环执行的,可能会占用大量处理器资源。响应GPIO输入的另一种方法是使用“中断”(边沿检测)。边缘是从HIGH到LOW(下降沿)或从LOW到HIGH(上升沿)的过渡的名称。
上拉/下拉电阻
如果您没有将输入引脚连接到任何东西,它将“浮动”。换句话说,读入的值是不确定的,因为在按下按钮或开关之前,它没有连接任何东西。由于受到电源干扰,它可能会改变很多值。
为了解决这个问题,我们使用上拉或下拉电阻。这样,可以设置输入的默认值。可以在硬件中和使用软件中具有上拉/下拉电阻。在硬件中,通常在输入通道和3.3V(上拉)或0V(上拉)之间使用10K电阻。RPi.GPIO模块允许您配置Broadcom SOC以在软件中执行此操作:
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# or
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
(其中channel是基于您指定的编号系统-BOARD或BCM的通道号)。
测试输入(polling)
您可以随时对输入进行快照:
if GPIO.input(channel):
print('Input was HIGH')
else:
print('Input was LOW')
要等待按钮,请循环轮询:
while GPIO.input(channel) == GPIO.LOW:
time.sleep(0.01) # wait 10 ms to give CPU chance to do other things
(这假设按下按钮会将输入从LOW更改为HIGH)
中断和边缘检测
边沿是电信号的状态从低到高(上升沿)或从高到低(下降沿)的变化。通常,我们更关心输入状态的变化而不是其值的变化。状态的改变是一个事件。
为了避免在程序忙于执行其他操作时错过按键,有两种方法可以解决此问题:
- wait_for_edge()函数
- event_detected()函数
- 当检测到边缘时运行的线程回调函数(a threaded callback function that is run when an edge is detected)
wait_for_edge()函数
wait_for_edge()函数旨在阻止程序执行,直到检测到边缘为止。换句话说,上面等待按钮按下的示例可以重写为:
GPIO.wait_for_edge(channel, GPIO.RISING)
请注意,您可以检测到GPIO.RISING,GPIO.FALLING或GPIO.BOTH类型的边沿。这样做的好处是使用的CPU量可以忽略不计,因此还有很多其他任务可以使用。
如果您只想等待一定的时间长度,则可以使用timeout参数:
# wait for up to 5 seconds for a rising edge (timeout is in milliseconds)
channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
if channel is None:
print('Timeout occurred')
else:
print('Edge detected on channel', channel)
event_detected()函数
event_detected()函数旨在与其他事物循环使用,但是与轮询不同,它不会丢失CPU在忙于其他事情时的输入状态变化。当使用诸如Pygame或PyQt之类的东西时,如果有主循环及时监听并响应GUI事件,这可能会很有用。
GPIO.add_event_detect(channel, GPIO.RISING) # add rising edge detection on a channel
do_something()
if GPIO.event_detected(channel):
print('Button pressed')
请注意,您可以检测到GPIO.RISING,GPIO.FALLING或GPIO.BOTH的事件。
线程回调
RPi.GPIO运行第二个用于回调函数的线程。这意味着回调函数可以与主程序同时运行,以立即响应边缘。例如:
def my_callback(channel):
print('This is a edge event callback function!')
print('Edge detected on channel %s'%channel)
print('This is run in a different thread to your main program')
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) # add rising edge detection on a channel
...the rest of your program...
如果您需要多个回调函数:
def my_callback_one(channel):
print('Callback one')
def my_callback_two(channel):
print('Callback two')
GPIO.add_event_detect(channel, GPIO.RISING)
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)
请注意,在这种情况下,回调函数是顺序运行的,而不是同时运行的。这是因为只有一个线程用于回调,每个线程都按照其定义的顺序运行。
开关反跳
您可能会注意到,每次按下按钮都会多次调用回调。这是所谓的“开关弹跳”的结果。有两种处理开关反弹的方法:
- 在开关两端添加一个0.1uF电容器。
- 软件反跳
- 两者的结合
要使用软件进行反跳,请在指定回调函数的函数中添加bouncetime =参数。跳出时间应以毫秒为单位指定。例如:
# add rising edge detection on a channel, ignoring further edges for 200ms for switch bounce handling
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)
或者
GPIO.add_event_callback(channel, my_callback, bouncetime=200)
删除事件检测
如果由于某种原因,您不再希望程序检测边缘事件,则可以将其停止:
GPIO.remove_event_detect(channel)
输出
- 首先设置RPi.GPIO
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
- 高电平输出:
GPIO.output(12, GPIO.HIGH)
# or
GPIO.output(12, 1)
# or
GPIO.output(12, True)
3.低电平输出:
GPIO.output(12, GPIO.LOW)
# or
GPIO.output(12, 0)
# or
GPIO.output(12, False)
4.同时多个通道输出:
chan_list = (11,12)
GPIO.output(chan_list, GPIO.LOW) # all LOW
GPIO.output(chan_list, (GPIO.HIGH,GPIO.LOW)) # first LOW, second HIGH
5.在程序结束时进行关闭输出通道
GPIO.cleanup()
请注意,您可以使用input()函数读取设置为输出的通道的当前状态。例如,切换输出:
GPIO.output(12, not GPIO.input(12))
脉宽调制(PWM)
要创建PWM输出实例:
p = GPIO.PWM(channel, frequency)
要启动PWM:
p.start(dc) # where dc is the duty cycle (0.0 <= dc <= 100.0)
更改频率:
p.ChangeFrequency(freq) # where freq is the new frequency in Hz
更改占空比:
p.ChangeDutyCycle(dc) # where 0.0 <= dc <= 100.0
停止PWM:
p.stop()
请注意,如果实例变量“ p”超出范围,PWM也会停止。
每两秒闪烁一次LED的示例:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
p = GPIO.PWM(12, 0.5)
p.start(1)
input('Press return to stop:') # use raw_input for Python 2
p.stop()
GPIO.cleanup()
增亮/调暗LED的示例:
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
p = GPIO.PWM(12, 50) # channel=12 frequency=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()
GPIO通道检查功能
gpio_function(channel)
显示GPIO通道的功能。
例如:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
func = GPIO.gpio_function(pin)
将从以下位置返回值:
GPIO.IN,GPIO.OUT,GPIO.SPI,GPIO.I2C,GPIO.HARD_PWM,GPIO.SERIAL,GPIO.UNKNOWN
Wiki:技术参考
Raspberry Pi / BCM2835技术参考
详细的技术参考可以在以下位置找到:
- http://elinux.org/RPi_Low-level_peripherals
- http://elinux.org/RPi_BCM2835_GPIO
- http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
请注意,RPi引脚3和5(Rev2和B + GPIO 02和03,Rev1-GPIO 00和01)具有1K8上拉电阻至3v3。
Wiki:安装
RPi.GPIO安装
树莓派中默认安装了RPi.GPIO模块。为确保它是最新版本:
$ sudo apt-get update
$ sudo apt-get install python-rpi.gpio python3-rpi.gpio
要从项目源代码库安装最新的开发版本:
$ sudo apt-get install python-dev python3-dev
$ sudo apt-get install mercurial
$ sudo apt-get install python-pip python3-pip
$ sudo apt-get remove python-rpi.gpio python3-rpi.gpio
$ sudo pip install hg+http://hg.code.sf.net/p/raspberry-gpio-python/code#egg=RPi.GPIO
$ sudo pip-3.2 install hg+http://hg.code.sf.net/p/raspberry-gpio-python/code#egg=RPi.GPIO
要恢复为Raspbian的默认版本,请执行以下操作:
$ sudo pip uninstall RPi.GPIO
$ sudo pip-3.2 uninstall RPi.GPIO
$ sudo apt-get install python-rpi.gpio python3-rpi.gpio
其他
建议您使用pip程序以超级用户的权限(root)安装RPi.GPIO:
# pip install RPi.GPIO