在本章中,我们将介绍以下主题:
Raspberry Pi 计算机区别于大多数其他家庭/办公室计算机的一个关键特性是,它能够直接与其他硬件接口。Raspberry Pi 上的通用输入/输出(GPIO)引脚可以控制范围广泛的低电平电子设备,从发光二极管(LED)到开关、传感器、电机、伺服甚至额外的显示器。
本章将重点介绍如何使用一些简单的电路连接 Raspberry Pi,以及如何使用 Python 控制和响应连接的组件。
Raspberry Pi 硬件接口由位于电路板一侧的 40 个引脚组成。
The GPIO pins and their layout will vary slightly according to the particular model you have.
RespberryPi 3、RespberryPi 2 和 RespberryPi B+都具有相同的 40 针布局。
较旧的 Raspberry Pi 1 型号(非 PLUS 类型)具有 26 针头,与较新型号的 1-26 针头相同。
Raspberry Pi 2, Raspberry Pi B+, and Raspberry Pi Model Plus GPIO header pins (pin functions)
连接器的布局如上图所示;引脚编号如 GPIO 头引脚 1 所示。
引脚 1位于离 SD 卡最近的一端,如下图所示:
The Raspberry Pi GPIO header location
使用 GPIO 头时应小心,因为它还包括电源引脚(3V3 和 5V)以及接地(接地)引脚。所有 GPIO 引脚都可以用作标准 GPIO,但也有几个引脚具有特殊功能;它们被标记并用不同的颜色高亮显示。
It is common for engineers to use a 3V3 notation to specify values in schematics in order to avoid using decimal places that could easily be missed (using 33V rather than 3.3V would cause severe damage to the circuitry). The same can be applied to the values of other components, such as resistors, for example, 1.2K ohms can be written as 1K2 ohms.
TX和RX引脚用于串行通信,在电压电平转换器的帮助下,信息可以通过串行电缆传输到另一台计算机或设备。
我们还有SDA和SCL引脚,能够支持一个名为I2C的双线总线通信协议(Raspberry Pi 3 和 Model Plus 板上有两个 I2C 通道:【T12 通道 1 ARM】,用于通用,通道 0 VC,通常用于识别附在顶部(帽模块)上的硬件。还有SPI MOSI、SPI MISO、SPI SCLK、SPI CE0和SPI CE1引脚,它们支持另一种称为SPI的高速数据总线协议。最后,我们有PWM0/1引脚,它允许生成脉宽调制信号,这对伺服和生成模拟信号非常有用。
但是,在本章中,我们将重点介绍仅使用标准 GPIO 函数。GPIO 引脚布局如下图所示:
Raspberry Pi GPIO header pins (GPIO.BOARD and GPIO.BCM)
与 Raspberry Pi 2 GPIO 布局相比,Raspberry Pi Rev 2(2014 年 7 月之前)具有以下差异:
Raspberry Pi Rev 2 P5 GPIO header pins
Raspberry Pi Rev 1 GPIO header differences
RPi.GPIO
库可以使用两种系统中的一种来参考树莓 Pi 上的管脚。中间显示的数字表示引脚的物理位置,也是GPIO.BOARD模式下RPi.GPIO
库引用的数字。外部的数字(GPIO.BCM是处理器物理端口的实际参考号,用于指示哪些管脚已连接(这就是为什么它们没有按任何特定顺序连接)。当模式设置为GPIO.BCM时使用它们,它们允许控制 GPIO 头引脚以及连接到其他 GPIO 线路的任何外围设备。这包括 BCM GPIO 4 上附加摄像头上的 LED 和主板上的状态 LED。但是,这也可能包括用于读取/写入 SD 卡的 GPIO 线,如果受到干扰,将导致严重错误。
如果您使用其他编程语言访问 GPIO 引脚,则编号方案可能不同,因此,如果您知道 BCM GPIO 参考,即处理器的物理 GPIO 端口,这将很有帮助。
Be sure to check out the Appendix, Hardware and Software List, which lists all the items used in this chapter and the places that you can obtain them from.
hello world
的硬件等价物是一个 LED 闪光灯,这是一个很好的测试,可以确保一切正常,并且您已经正确连接了它。为了让它更有趣一点,我建议使用红色、蓝色和绿色(RGB)LED,但如果您只有这些,请随意使用单独的 LED。
您将需要以下设备:
前面的每个组件都不应该花费很多美元,并且可以在以后的其他项目中重用。试验板是一个特别有用的部件,允许您在不需要焊接的情况下尝试自己的电路:
Diagrams of an RGB LED, a standard LED, and an RGB circuit
下图显示了试验板电路:
The wiring of an RGB LED/standard LEDs connected to the GPIO header There are several different kinds of RGB LEDs available, so check the datasheet of your component to confirm the pin order and type you have. Some are RGB, so ensure that you wire accordingly or adjust the RGB_
pin settings in the code. You can also get common anode variants, which will require the anode to be connected to 3V3 (GPIO-pin 1) for it to light up (and they will also require RGB_ENABLE
and RGB_DISABLE
to be set to 0
and 1
respectively
).
本书的实验板和部件图是使用名为Fritzing(www.Fritzing.org的免费工具创建的;这是伟大的规划自己的树莓 Pi 项目。
ledtest.py
脚本,如下所示:#!/usr/bin/python3
#ledtest.py
import time
import RPi.GPIO as GPIO
# RGB LED module
#HARDWARE SETUP
# GPIO
# 2[======XRG=B==]26[=======]40
# 1[=============]25[=======]39
# X=GND R=Red G=Green B=Blue
#Setup Active States
#Common Cathode RGB-LED (Cathode=Active Low)
RGB_ENABLE = 1; RGB_DISABLE = 0
#LED CONFIG - Set GPIO Ports
RGB_RED = 16; RGB_GREEN = 18; RGB_BLUE = 22
RGB = [RGB_RED,RGB_GREEN,RGB_BLUE]
def led_setup():
#Setup the wiring
GPIO.setmode(GPIO.BOARD)
#Setup Ports
for val in RGB:
GPIO.setup(val,GPIO.OUT)
def main():
led_setup()
for val in RGB:
GPIO.output(val,RGB_ENABLE)
print("LED ON")
time.sleep(5)
GPIO.output(val,RGB_DISABLE)
print("LED OFF")
try:
main()
finally:
GPIO.cleanup()
print("Closed Everything. END")
#End
RPi.GPIO
库需要sudo
权限才能访问 GPIO 引脚硬件,因此您需要使用以下命令运行脚本:sudo python3 ledtest.py
当您运行脚本时,您应该看到 LED 的红色、绿色和蓝色部分(或者每个 LED,如果您使用的是单独的 LED)依次亮起。如果没有,请再次检查您的接线,或通过将红色、绿色或蓝色导线临时连接到 3V3 引脚(GPIO 头的引脚 1)来确认 LED 是否正常工作。
The sudo
command is required for most hardware-related scripts because it isn't normal for users to directly control hardware at such a low level. For example, setting or clearing a control pin that is part of the SD card controller could corrupt data being written to it. Therefore, for security purposes, superuser permissions are required to stop programs from using hardware by accident (or with malicious intent).
为了使用 Python 访问 GPIO 引脚,我们导入了RPi.GPIO
库,它允许通过模块函数直接控制引脚。我们还要求time
模块将程序暂停设定的秒数。
然后,我们定义 LED 接线和激活状态的值(请参见本配方的部分中控制 GPIO 电流部分,还有更多…部分)。
在程序使用 GPIO 引脚之前,我们需要通过指定编号方法-GPIO.BOARD
-和方向-GPIO.OUT
或GPIO.IN
(在这种情况下,我们将所有 RGB 引脚设置为输出)来设置它们。如果一个引脚配置为输出,我们将能够设置引脚状态;类似地,如果将其配置为输入,我们将能够读取引脚状态。
接下来,我们使用GPIO.ouput()
来控制管脚,方法是说明 GPIO 管脚的编号和我们希望它处于的状态(1
=高/开和0
=低/关)。我们打开每个 LED,等待五秒钟,然后再将其关闭。
最后,我们使用GPIO.cleanup()
将 GPIO 引脚返回到其原始默认状态,并释放对引脚的控制,以供其他程序使用。
在 Raspberry Pi 上使用 GPIO 引脚时必须小心,因为这些引脚直接连接到 Raspberry Pi 的主处理器,没有任何额外的保护。必须小心,因为任何不正确的接线都可能损坏 Raspberry Pi 处理器并导致其完全停止工作。
或者,您可以使用可直接插入 GPIO 头引脚的众多模块之一(减少接线错误的机会):
For example, the Pi-Stop is a simple pre-built LED board that simulates a set of traffic lights, designed to be a stepping stone for those who are interested in controlling hardware but want to avoid the risk of damaging their Raspberry Pi. After the basics have been mastered, it also makes an excellent indicator to aid debugging.
只需确保更新ledtest.py
脚本中的LED CONFIG
管脚引用,以引用您正在使用的硬件所使用的管脚布局和位置。
树莓 Pi 硬件零售商名单见附录硬件和软件清单。
每个 GPIO 引脚仅能在其耗尽之前处理特定电流(单个引脚的最大电流为 16 mA 或总共 30 mA),同样,RGB LED 应限制在不超过 100 mA。通过在 LED 之前或之后添加电阻器,我们将能够限制通过它的电流,并控制它的亮度(电流越大,LED 越亮)。
由于我们可能希望一次为多个 LED 供电,因此我们通常会将电流设置为尽可能低,同时仍提供足够的功率点亮 LED。
我们可以用欧姆定律来告诉我们提供一个特定电流需要多少电阻。该规律如下图所示:
Ohm's law: The relationship between the current, resistance, and voltage in electrical circuits
我们的目标是最小电流(3 毫安)和最大电流(16 毫安),同时仍能从每个 LED 发出合理的亮光。为了获得 RGB LED 的平衡输出,我测试了不同的电阻器,直到它们发出接近白光(通过卡观看时)。为每一个选择了 470 欧姆的电阻器(您的 LED 可能略有不同):
Resistors are needed to limit the current that passes through the LEDs
电阻器上的电压等于 GPIO 电压(Vgpio=3.3V)减去特定 LED 上的压降(Vfwd);然后,我们可以使用该电阻计算每个 LED 使用的电流,如以下公式所示:
We can calculate the current drawn by each of the LEDs
许多使用 Raspberry Pi 的应用程序需要激活操作,而不需要键盘和屏幕。GPIO 引脚为 Raspberry Pi 提供了一种很好的方式,可以由您自己的按钮和开关控制,而无需鼠标/键盘和屏幕。
您将需要以下设备:
开关如下图所示:
The push-button switch and other types of switch The switches used in the following examples are single-pole, single-throw (SPST), momentary close, push-button switches. Single pole (SP) means that there is one set of contacts that makes a connection. In the case of the push switch used here, the legs on each side are connected together with a single-pole switch in the middle. A double-pole (DP) switch acts just like a SP switch, except that the two sides are separated electrically, allowing you to switch two separate components on/off at the same time.
单掷**ST表示开关只与一个位置连接;另一侧将保持打开状态。双掷(DT**表示开关的两个位置将连接到不同的部件。
瞬间关闭表示按钮按下时关闭开关,松开时自动打开开关。一个锁定的按钮开关将保持关闭状态,直到再次按下。
The layout of the button circuit
我们将在本例中使用声音,因此您还需要将扬声器或耳机连接到 Raspberry Pi 的音频插座。
您需要使用以下命令安装一个名为flite
的程序,该命令将使 Raspberry Pi 对话:
sudo apt-get install flite
安装后,可以使用以下命令对其进行测试:
sudo flite -t "hello I can talk"
如果声音太小(或太大),可以使用以下命令调整音量(0-100%):
amixer set PCM 100%
创建btntest.py
脚本,如下所示:
#!/usr/bin/python3
#btntest.py
import time
import os
import RPi.GPIO as GPIO
#HARDWARE SETUP
# GPIO
# 2[==X==1=======]26[=======]40
# 1[=============]25[=======]39
#Button Config
BTN = 12
def gpio_setup():
#Setup the wiring
GPIO.setmode(GPIO.BOARD)
#Setup Ports
GPIO.setup(BTN,GPIO.IN,pull_up_down=GPIO.PUD_UP)
def main():
gpio_setup()
count=0
btn_closed = True
while True:
btn_val = GPIO.input(BTN)
if btn_val and btn_closed:
print("OPEN")
btn_closed=False
elif btn_val==False and btn_closed==False:
count+=1
print("CLOSE %s" % count)
os.system("flite -t '%s'" % count)
btn_closed=True
time.sleep(0.1)
try:
main()
finally:
GPIO.cleanup()
print("Closed Everything. END")
#End
与上一个配方一样,我们根据需要设置 GPIO 引脚,但这次作为输入,我们还使用以下代码启用内部上拉电阻器(请参见中的上拉和下拉电阻器电路,此配方中的部分有更多……了解更多信息):
GPIO.setup(BTN,GPIO.IN,pull_up_down=GPIO.PUD_UP)
设置 GPIO 引脚后,我们创建一个循环,使用GPIO.input()
持续检查BTN
的状态。如果返回值为false
,则该引脚已通过开关连接到 0V(地),每次按下按钮时,我们将使用flite
为我们大声计数。
由于我们已经在try
/finally
条件下调用了主函数,所以即使我们使用Ctrl+Z关闭程序,它仍然会调用GPIO.cleanup()
。
We use a short delay in the loop; this ensures that any noise from the contacts on the switch is ignored. This is because when we press the button, there isn't always perfect contact as we press or release it, and it may produce several triggers if we press it again too quickly. This is known as software debouncing; we ignore the bounce in the signal here.
RespberryPi GPIO 引脚必须小心使用;用于输入的电压应在特定范围内为 ,并且应使用 保护电阻器将从其引出的任何电流降至最低。
我们必须确保只连接 0(接地)和 3V3 之间的输入。一些处理器使用 0V 到 5V 之间的电压,因此需要额外的组件来安全地与它们连接。切勿连接使用 5V 电压的输入或组件,除非您确定它是安全的,否则会损坏 Raspberry Pi 的 GPIO 端口。
前面的代码将 GPIO 引脚设置为使用内部上拉电阻器。GPIO 引脚上没有上拉电阻器(或下拉电阻器),电压可以在 3V3 和 0V 之间自由浮动,实际逻辑状态仍不确定(有时为 1,有时为 0)。
Raspberry Pi 的内部上拉电阻为 50K-65K 欧姆,下拉电阻为 50K-65K 欧姆。GPIO 电路中经常使用外部上拉/下拉电阻器(如下图所示),出于类似原因,通常使用 10K 欧姆或更大的电阻(当它们未激活时,电流消耗非常小)。
上拉电阻器允许少量电流流过 GPIO 引脚,并在未按下开关时提供高电压。当按下开关时,小电流被流向 0V 的大电流所取代,因此我们在 GPIO 引脚上得到一个低电压。按下开关时,开关处于低电平激活状态,逻辑为 0。其工作原理如下图所示:
A pull-up resistor circuit
下拉电阻器的工作方式相同,但开关为高电平(按下时 GPIO 引脚为逻辑 1)。其工作原理如下图所示:
A pull-down resistor circuit
除开关外,电路还包括一个与开关串联的电阻器,以保护 GPIO 引脚,如下图所示:
A GPIO protective current-limiting resistor
保护电阻器的用途是在 GPIO 引脚意外设置为输出而非输入时保护该引脚。例如,假设我们的开关连接在 GPIO 和接地之间。现在 GPIO 引脚被设置为输出并打开(将其驱动到 3V3),只要我们按下开关,在没有电阻器的情况下,GPIO 引脚将直接连接到 0V。GPIO 仍将尝试将其驱动到 3V3;这将导致 GPIO 引脚烧坏(因为它将使用过多电流将引脚驱动到高状态)。如果我们在这里使用 1K 欧姆的电阻器,则可以使用可接受的电流量(I=V/R=3.3/1K=3.3 mA)将引脚驱动到高电平。
Raspberry Pi 应始终正确关闭,以避免 SD 卡损坏(在对 SD 卡执行写入操作时断电)。如果您没有连接键盘或屏幕(您可能正在运行自动化程序或通过网络远程控制它,但忘记关闭它),这可能会造成问题,因为您无法键入命令或查看正在执行的操作。通过添加我们自己的按钮和 LED 指示灯,我们可以轻松地命令关机和复位,然后再次启动以指示系统何时处于活动状态。
您将需要以下设备:
停机回路的整个布局如下图所示:
The controlled shutdown circuit layout
shtdwn.py
脚本,如下所示:#!/usr/bin/python3
#shtdwn.py
import time
import RPi.GPIO as GPIO
import os
# Shutdown Script
DEBUG=True #Simulate Only
SNDON=True
#HARDWARE SETUP
# GPIO
# 2[==X==L=======]26[=======]40
# 1[===1=========]25[=======]39
#BTN CONFIG - Set GPIO Ports
GPIO_MODE=GPIO.BOARD
SHTDWN_BTN = 7 #1
LED = 12 #L
def gpio_setup():
#Setup the wiring
GPIO.setmode(GPIO_MODE)
#Setup Ports
GPIO.setup(SHTDWN_BTN,GPIO.IN,pull_up_down=GPIO.PUD_UP)
GPIO.setup(LED,GPIO.OUT)
def doShutdown():
if(DEBUG):print("Press detected")
time.sleep(3)
if GPIO.input(SHTDWN_BTN):
if(DEBUG):print("Ignore the shutdown (<3sec)")
else:
if(DEBUG):print ("Would shutdown the RPi Now")
GPIO.output(LED,0)
time.sleep(0.5)
GPIO.output(LED,1)
if(SNDON):os.system("flite -t 'Warning commencing power down 3 2 1'")
if(DEBUG==False):os.system("sudo shutdown -h now")
if(DEBUG):GPIO.cleanup()
if(DEBUG):exit()
def main():
gpio_setup()
GPIO.output(LED,1)
while True:
if(DEBUG):print("Waiting for >3sec button press")
if GPIO.input(SHTDWN_BTN)==False:
doShutdown()
time.sleep(1)
try:
main()
finally:
GPIO.cleanup()
print("Closed Everything. END")
#End
~/bin
(如果我们只想复制它,我们可以使用cp
而不是mv
,并使用以下代码将它添加到crontab
:mkdir ~/bin
mv shtdwn.py ~/bin/shtdwn.py
crontab -e
@reboot sudo python3 ~/bin/shtdwn.py
这一次,当我们设置 GPIO 引脚时,我们将连接到关机按钮的引脚定义为输入,将连接到 LED 的引脚定义为输出。我们打开 LED 以指示系统正在运行。
通过将DEBUG
标志设置为True
,我们可以测试脚本的功能,而不会导致实际关机(通过读取终端消息);我们只需要确保在实际使用脚本时将DEBUG
设置为False
。
我们进入一个while
循环,每秒检查一次引脚,看 GPIO 引脚是否设置为LOW
(即检查开关是否被按下);如果是,我们进入doShutdown()
功能。
程序将等待三秒钟,然后再次测试,以查看按钮是否仍在按下。如果不再按下按钮,我们将返回到上一个while
循环。但是,如果三秒钟后仍在按下,程序将闪烁 LED 并触发关机(并使用flite
提供音频警告)。
当我们对脚本的运行方式感到满意时,我们可以禁用DEBUG
标志(通过将其设置为False
,并将脚本添加到crontab
。crontab
是一个在后台运行的特殊程序,允许我们在系统启动时安排(在特定时间、日期或定期)程序和操作(@reboot
。这使得脚本可以在每次 Raspberry Pi 通电时自动启动。当我们按住关机按钮超过三秒时,它会安全地关闭系统并进入低功率状态(LED 在此之前关闭,表示稍后可以安全地断开电源)。为了重新启动覆盆子皮,我们短暂地切断电源;这将重新启动系统,当覆盆子 Pi 加载后,LED 将亮起。
我们可以通过添加额外的功能和使用额外的 GPIO 连接(如果可用),使用重置标头进一步扩展此示例。
Raspberry Pi 具有用于安装复位集管的孔(Raspberry Pi 3/2 上标记为RUN,Raspberry Pi 1 型号 a 和型号 B 版本 2 上标记为P6。重置引脚允许使用按钮重置设备,而不是每次卸下 micro USB 接口以循环电源:
Raspberry Pi reset headers - on the left, Raspberry Pi Model A/B (Rev2), and on the right, Raspberry Pi 3
要使用它,您需要将一根导线或引脚头焊接到 Raspberry Pi 上,并将一个按钮连接到它(或者每次在两个孔之间短暂地触摸一根导线)。或者,我们可以扩展之前的电路,如下图所示:
The controlled shutdown circuit layout and reset button
我们可以将这个额外的按钮添加到我们的电路中,它可以连接到重置标题(这是最靠近 Raspberry Pi 3 中间的孔,或最靠近其他型号边缘的孔)。当该引脚通过接地(例如其旁边的孔或另一个接地点,例如 GPIO 收割台的引脚 6)临时拉低时,将重置 Raspberry Pi,并允许其在关机后再次启动。
由于我们现在有脚本一直监控关机按钮,我们可以同时添加额外的按钮/开关/跳线进行监控。这将允许我们只需更改输入即可触发特定程序或设置特定状态。以下示例允许我们轻松地在自动 DHCP 联网(默认联网设置)和使用直接 IP 地址之间切换,如第 1 章中的直接联网到笔记本电脑或计算机配方中使用的开始使用覆盆子 Pi 3 计算机,用于直接局域网连接。
将以下元件添加到上一个回路:
在添加上述组件后,我们的受控关机电路如下所示:
The controlled shutdown circuit layout, reset button, and jumper pins
在前面的脚本中,我们添加了一个额外的输入,以使用以下代码检测LAN_SWA
引脚(我们添加到电路中的跳线引脚)的状态:
LAN_SWA = 11 #2
确保使用以下代码将其设置为gpio_setup()
功能中的输入(带上拉电阻器):
GPIO.setup(LAN_SWA,GPIO.IN,pull_up_down=GPIO.PUD_UP)
添加一个新功能,在 LAN 模式之间切换并读取新的 IP 地址。doChangeLAN()
功能检查LAN_SWA
引脚的状态自上次调用以来是否发生了变化,如果是,则将网络适配器设置为 DHCP 或相应地设置直接 LAN 设置(并使用flite
说出新的 IP 设置,如果可用)。最后,设置为直接连接的 LAN 会导致 LED 在该模式激活时缓慢闪烁。使用以下代码执行此操作:
def doChangeLAN(direct):
if(DEBUG):print("Direct LAN: %s" % direct)
if GPIO.input(LAN_SWA) and direct==True:
if(DEBUG):print("LAN Switch OFF")
cmd="sudo dhclient eth0"
direct=False
GPIO.output(LED,1)
elif GPIO.input(LAN_SWA)==False and direct==False:
if(DEBUG):print("LAN Switch ON")
cmd="sudo ifconfig eth0 169.254.69.69"
direct=True
else:
return direct
if(DEBUG==False):os.system(cmd)
if(SNDON):os.system("hostname -I | flite")
return direct
添加另一个功能flashled()
,每次调用该功能时,只需切换 LED 的状态即可。此功能的代码如下所示:
def flashled(ledon):
if ledon:
ledon=False
else:
ledon=True
GPIO.output(LED,ledon)
return ledon
最后,我们将主循环调整为也调用doChangeLAN()
,并使用结果决定是否使用ledon
调用flashled()
,以跟踪每次 LED 的先前状态。main()
功能现在应更新如下:
def main():
gpio_setup()
GPIO.output(LED,1)
directlan=False
ledon=True
while True:
if(DEBUG):print("Waiting for >3sec button press")
if GPIO.input(SHTDWN_BTN)==False:
doShutdown()
directlan= doChangeLAN(directlan)
if directlan:
flashled(ledon)
time.sleep(1)
我们已经了解了如何监控 GPIO 上的输入以启动应用程序和控制 Raspberry Pi;然而,有时我们需要控制第三方程序。使用uInput
库,我们可以模拟键盘上的按键(甚至鼠标移动),使用我们自己的定制硬件控制任何程序。
有关使用uInput
的更多信息,请访问http://tjjr.fi/sw/python-uinput/ 。
执行以下步骤安装uInput
:
uInput
。您需要使用以下命令从 GitHub(~50KB)下载uInput
Python 库:
wget https://github.com/tuomasjjrasanen/python-uinput/archive/master.zip
unzip master.zip
库将解压缩到名为python-uinput-master
的目录。
rm master.zip
apt-get
命令将忽略它们):sudo apt-get install python3-setuptools python3-dev
sudo apt-get install libudev-dev
uInput
:cd python-uinput-master
sudo python3 setup.py install
uinput
内核模块:sudo modprobe uinput
为确保启动时加载,我们可以使用以下命令将uinput
添加到modules
文件中:
sudo nano /etc/modules
将uinput
放在文件中的新行并保存(Ctrl+X、Y)。
GPIO keypad circuit layout
通过将元件焊接到 Vero 原型板(也称为剥离板)中,键盘电路也可以内置到永久性电路中,如下图所示:
GPIO keypad Pi hardware module This circuit is available as a solder-yourself kit from PiHardware.com.
| | 按钮 | GPIO 引脚 | | GND | | 6. | | v | B 下来 | 22 | | < | B 左 | 18 | | ^ | 加油 | 15 | | > | 对 | 13 | | 1. | B_1 | 11 | | 2. | B_2 | 7. |
创建一个gpiokeys.py
脚本,如下所示:
#!/usr/bin/python3
#gpiokeys.py
import time
import RPi.GPIO as GPIO
import uinput
#HARDWARE SETUP
# GPIO
# 2[==G=====<=V==]26[=======]40
# 1[===2=1>^=====]25[=======]39
B_DOWN = 22 #V
B_LEFT = 18 #<
B_UP = 15 #^
B_RIGHT = 13 #>
B_1 = 11 #1
B_2 = 7 #2
DEBUG=True
BTN = [B_UP,B_DOWN,B_LEFT,B_RIGHT,B_1,B_2]
MSG = ["UP","DOWN","LEFT","RIGHT","1","2"]
#Setup the DPad module pins and pull-ups
def dpad_setup():
#Set up the wiring
GPIO.setmode(GPIO.BOARD)
# Setup BTN Ports as INPUTS
for val in BTN:
# set up GPIO input with pull-up control
#(pull_up_down can be:
# PUD_OFF, PUD_UP or PUD_DOWN, default PUD_OFF)
GPIO.setup(val, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def main():
#Setup uinput
events = (uinput.KEY_UP,uinput.KEY_DOWN,uinput.KEY_LEFT,
uinput.KEY_RIGHT,uinput.KEY_ENTER,uinput.KEY_ENTER)
device = uinput.Device(events)
time.sleep(2) # seconds
dpad_setup()
print("DPad Ready!")
btn_state=[False,False,False,False,False,False]
key_state=[False,False,False,False,False,False]
while True:
#Catch all the buttons pressed before pressing the related keys
for idx, val in enumerate(BTN):
if GPIO.input(val) == False:
btn_state[idx]=True
else:
btn_state[idx]=False
#Perform the button presses/releases (but only change state once)
for idx, val in enumerate(btn_state):
if val == True and key_state[idx] == False:
if DEBUG:print (str(val) + ":" + MSG[idx])
device.emit(events[idx], 1) # Press.
key_state[idx]=True
elif val == False and key_state[idx] == True:
if DEBUG:print (str(val) + ":!" + MSG[idx])
device.emit(events[idx], 0) # Release.
key_state[idx]=False
time.sleep(.1)
try:
main()
finally:
GPIO.cleanup()
#End
首先,我们导入uinput
并定义键盘按钮的接线。对于BTN
中的每个按钮,我们将其作为输入启用,并启用内部上拉。
接下来,我们设置uinput
,定义要模拟的键,并将它们添加到uinput.Device()
函数中。我们等待几秒钟,让uinput
初始化,设置初始按钮和键状态,然后开始main
循环。
main
循环分为两部分:第一部分通过按钮检查并记录btn_state
中的状态,第二部分将btn_state
与当前key_state
数组进行比较。这样,我们就可以检测到btn_state
的变化并调用device.emit()
来切换按键的状态。
为了让我们在后台运行这个脚本,我们可以使用&
来运行它,如下面的
命令所示:
sudo python3 gpiokeys.py &
The &
character allows the command to run in the background, so we can continue with the command line to run other programs. You can use fg
to bring it back to the foreground, or %1
, %2
, and so on if you have several commands running. Use jobs
to get a list.
您甚至可以通过按Ctrl+Z将一个进程/程序置于等待状态,以进入命令提示符,然后用bg
将其恢复(这将使其在后台运行)。
我们可以使用uinput
为其他程序提供硬件控制,包括需要鼠标输入的程序。
您可以在文件中创建多个不同的密钥映射以支持不同的程序。例如,events_z80
键映射对于频谱模拟器非常有用,例如Fuse(浏览至http://raspi.tv/2012/how-to-install-fuse-zx-spectrum-emulator-on-raspberry-pi 了解更多详细信息)。events_omx
键映射适用于使用以下命令控制通过 OMXPlayer 播放的视频:
omxplayer filename.mp4
您可以使用-k
参数获取omxplayer
支持的密钥列表。
用新的键映射替换定义events
列表的行,并通过使用以下代码将它们分配给事件来选择不同的键映射:
events_dpad = (uinput.KEY_UP,uinput.KEY_DOWN,uinput.KEY_LEFT,
uinput.KEY_RIGHT,uinput.KEY_ENTER,uinput.KEY_ENTER)
events_z80 = (uinput.KEY_Q,uinput.KEY_A,uinput.KEY_O,
uinput.KEY_P,uinput.KEY_M,uinput.KEY_ENTER)
events_omx = (uinput.KEY_EQUAL,uinput.KEY_MINUS,uinput.KEY_LEFT,
uinput.KEY_RIGHT,uinput.KEY_P,uinput.KEY_Q)
您可以在input.h
文件中找到所有KEY
定义;您可以使用less
命令查看(按Q退出),如下命令所示:
less /usr/include/linux/input.h
uinput
库可以模拟鼠标和操纵杆事件,以及键盘按下。要使用按钮模拟鼠标,我们可以使用以下代码调整脚本以使用鼠标事件(以及定义mousemove
以设置移动的步长):
MSG = ["M_UP","M_DOWN","M_LEFT","M_RIGHT","1","Enter"]
events_mouse=(uinput.REL_Y,uinput.REL_Y, uinput.REL_X,
uinput.REL_X,uinput.BTN_LEFT,uinput.BTN_RIGHT)
mousemove=1
我们还需要修改按钮处理以提供连续的移动,因为我们不需要跟踪鼠标键的状态。为此,请使用以下代码:
#Perform the button presses/releases
#(but only change state once)
for idx, val in enumerate(btn_state):
if MSG[idx] == "M_UP" or MSG[idx] == "M_LEFT":
state = -mousemove
else:
state = mousemove
if val == True:
device.emit(events[idx], state) # Press.
elif val == False:
device.emit(events[idx], 0) # Release.
time.sleep(0.01)
本章的下一个示例演示了一些看似简单的硬件如果用软件控制,可以产生一些令人印象深刻的结果。为此,我们将回到使用 RGB LED。我们将使用五个接线的 RGB LED,这样我们只需要使用八个 GPIO 引脚,就可以使用一种称为硬件复用的方法来控制它们的红色、绿色和蓝色元素(请参阅中的硬件复用小节,本配方中还有更多的……部分)。
您需要下图所示的 RGB LED 模块:
The RGB LED module from PiHardware.com
如上图所示,中的 RGB LED 模块 http://pihardware.com/ 配有 GPIO 引脚和用于连接的杜邦阴对阴电缆。虽然有两组引脚标记为 1 到 5,但只需连接一侧。
或者,您可以使用五个公共阴极 RGB LED、3 x 470 欧姆电阻器和 Vero 原型板(或大型试验板)重新创建自己的电路。电路将如下图所示:
Circuit diagram for the RGB LED module Strictly speaking, we should use 15 resistors in this circuit (one for each RGB LED element), which will avoid interference from LEDs sharing the same resistor, and will also prolong the life of the LEDs themselves if switched on together. However, there is only a slight advantage in using this, particularly since we intend to drive each RGB LED independently of the other four to achieve multi-color effects.
您需要将电路连接到 Raspberry Pi GPIO 标头,如下所示:
| RGB 发光二极管 | | | | | | 1. | | 2. | 3. | | 4. | | | | | | | | | | | Rpi GPIO 引脚 | 2. | 4. | 6. | 8. | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | | Rpi GPIO 引脚 | 1. | 3. | 5. | 7. | 9 | 11 | 13 | 15 | 17 | 19 | 21 | 23 | 25 | 27 | 29 | 31 | 33 | 35 | 37 | 39 | | RGB 发光二极管 | | | | 5. | | R | G | B | | | | | | | | | | | | |
创建rgbled.py
脚本并执行以下步骤:
#!/usr/bin/python3
#rgbled.py
import time
import RPi.GPIO as GPIO
#Setup Active states
#Common Cathode RGB-LEDs (Cathode=Active Low)
LED_ENABLE = 0; LED_DISABLE = 1
RGB_ENABLE = 1; RGB_DISABLE = 0
#HARDWARE SETUP
# GPIO
# 2[=====1=23=4==]26[=======]40
# 1[===5=RGB=====]25[=======]39
#LED CONFIG - Set GPIO Ports
LED1 = 12; LED2 = 16; LED3 = 18; LED4 = 22; LED5 = 7
LED = [LED1,LED2,LED3,LED4,LED5]
RGB_RED = 11; RGB_GREEN = 13; RGB_BLUE = 15
RGB = [RGB_RED,RGB_GREEN,RGB_BLUE]
#Mixed Colors
RGB_CYAN = [RGB_GREEN,RGB_BLUE]
RGB_MAGENTA = [RGB_RED,RGB_BLUE]
RGB_YELLOW = [RGB_RED,RGB_GREEN]
RGB_WHITE = [RGB_RED,RGB_GREEN,RGB_BLUE]
RGB_LIST = [RGB_RED,RGB_GREEN,RGB_BLUE,RGB_CYAN,
RGB_MAGENTA,RGB_YELLOW,RGB_WHITE]
def led_setup():
'''Setup the RGB-LED module pins and state.'''
#Set up the wiring
GPIO.setmode(GPIO.BOARD)
# Setup Ports
for val in LED:
GPIO.setup(val, GPIO.OUT)
for val in RGB:
GPIO.setup(val, GPIO.OUT)
led_clear()
def led_gpiocontrol(pins,state):
'''This function will control the state of
a single or multiple pins in a list.'''
#determine if "pins" is a single integer or not
if isinstance(pins,int):
#Single integer - reference directly
GPIO.output(pins,state)
else:
#if not, then cycle through the "pins" list
for i in pins:
GPIO.output(i,state)
def led_activate(led,color):
'''Enable the selected led(s) and set the required color(s)
Will accept single or multiple values'''
#Enable led
led_gpiocontrol(led,LED_ENABLE)
#Enable color
led_gpiocontrol(color,RGB_ENABLE)
def led_deactivate(led,color):
'''Deactivate the selected led(s) and set the required
color(s) will accept single or multiple values'''
#Disable led
led_gpiocontrol(led,LED_DISABLE)
#Disable color
led_gpiocontrol(color,RGB_DISABLE)
def led_time(led, color, timeon):
'''Switch on the led and color for the timeon period'''
led_activate(led,color)
time.sleep(timeon)
led_deactivate(led,color)
def led_clear():
'''Set the pins to default state.'''
for val in LED:
GPIO.output(val, LED_DISABLE)
for val in RGB:
GPIO.output(val, RGB_DISABLE)
def led_cleanup():
'''Reset pins to default state and release GPIO'''
led_clear()
GPIO.cleanup()
def main():
'''Directly run test function.
This function will run if the file is executed directly'''
led_setup()
led_time(LED1,RGB_RED,5)
led_time(LED2,RGB_GREEN,5)
led_time(LED3,RGB_BLUE,5)
led_time(LED,RGB_MAGENTA,2)
led_time(LED,RGB_YELLOW,2)
led_time(LED,RGB_CYAN,2)
if __name__=='__main__':
try:
main()
finally:
led_cleanup()
#End
首先,我们通过定义启用和禁用LED 所需的状态来定义硬件设置,具体取决于所使用的 RGB LED(公共阴极)的类型。如果您使用的是普通阳极装置,只需反转启用和禁用状态即可。
接下来,我们定义到管脚的 GPIO 映射,以匹配我们之前所做的布线。
我们还通过将红色、绿色和/或蓝色组合在一起来定义一些基本颜色组合,如下图所示:
LED color combinations
我们定义了一系列有用的函数,第一个是led_setup()
,它将 GPIO 编号设置为GPIO.BOARD
,并定义要用作输出的所有管脚。我们还调用了一个名为led_clear()
的函数,该函数将在禁用所有管脚的情况下将管脚设置为默认状态。
This means that the LED pins, 1-5 (the common cathode on each LED), are set to HIGH
, while the RGB pins (the separate anodes for each color) are set to LOW
.
我们创建了一个名为led_gpiocontrol()
的函数,它允许我们设置一个或多个管脚的状态。isinstance()
函数允许我们测试一个值,看看它是否匹配一个特定的类型(在本例中是一个整数);然后,我们可以设置单个管脚的状态,或者遍历管脚列表并设置每个管脚。
接下来,我们定义两个函数,led_activate()
和led_deactivate()
,它们将启用和禁用指定的 LED 和颜色。最后,我们定义了led_time()
,这将允许我们指定 LED、颜色和打开时间。
我们还创建led_cleanup()
将引脚(和 LED)重置为默认值,并调用GPIO.cleanup()
释放正在使用的 GPIO 引脚。
此脚本旨在成为一个库文件,因此在直接运行该文件时,我们将使用if __name__=='__main__'
检查仅运行我们的测试代码:
By checking the value of __name__
, we can determine whether the file was run directly (it will equal __main__
) or whether it was imported by another Python script.
这允许我们定义一个特殊的测试代码,它只在我们直接加载并运行文件时执行。如果我们将此文件作为模块包含在另一个脚本中,则不会执行此代码。
与之前一样,我们将使用try
/finally
来允许我们始终执行清理操作,即使我们提前退出。
为了测试脚本,我们将设置 LED 以各种颜色依次点亮。
我们可以通过一次打开 RGB LED 的一个或多个部分来创建几种不同的颜色。然而,通过一些巧妙的编程,我们可以创建一个完整的颜色光谱。此外,我们可以在每个 LED 上同时显示不同的颜色。
LED 需要阳极侧的高电压和阴极侧的低电压才能点亮。电路中使用的 RGB LED 是公共阴极,因此我们必须在 RGB 引脚上施加高电压(3V3),在阴极引脚上施加低电压(0V)(连接到每个 LED 的引脚 1 至 5)。
阴极和 RGB 引脚状态如下所示:
Cathode and RGB pin states
因此,我们可以启用一个或多个 RGB 引脚,但仍然可以控制哪些 LED 点亮。我们启用要点亮的 LED 的引脚,禁用不需要的引脚。这使我们能够使用比单独控制 15 条 RGB 线所需的管脚少得多的管脚。
我们可以向库中添加新函数以产生不同的效果,例如生成随机颜色。以下函数使用randint()
获取介于 1 和颜色数之间的值。我们忽略超过可用颜色数量的任何值,以便控制 LED 关闭的频率。执行以下步骤以添加所需的功能:
random
模块中的randint()
函数添加到rgbled.py
脚本中:from random import randint
led_rgbrandom()
:def led_rgbrandom(led,period,colors):
''' Light up the selected led, for period in seconds,
in one of the possible colors. The colors can be
1 to 3 for RGB, or 1-6 for RGB plus combinations,
1-7 includes white. Anything over 7 will be set as
OFF (larger the number more chance of OFF).'''
value = randint(1,colors)
if value < len(RGB_LIST):
led_time(led,RGB_LIST[value-1],period)
main()
功能中的以下命令创建一系列
闪烁 LED:for i in range(20):
for j in LED:
#Select from all, plus OFF
led_rgbrandom(j,0.1,20)
到目前为止,我们在一个或多个 LED 上一次只显示一种颜色。如果你考虑电路是如何布线的,你可能会想知道我们如何能同时得到一个 LED 显示一种颜色和另一种颜色。简单的答案是,我们不需要,我们只需要快速完成!
我们所需要做的就是一次显示一种颜色,但来回改变它,如此之快,颜色看起来就像两种颜色的混合(甚至是三个红/绿/蓝 LED 的组合)。幸运的是,这是像 Raspberry Pi 这样的计算机可以很容易做到的事情,甚至允许我们将 RGB 元素组合在一起,在所有五个 LED 上形成多种颜色。执行以下步骤混合颜色:
rgbled.py
脚本的顶部:#Combo Colors
RGB_AQUA = [RGB_CYAN,RGB_GREEN]
RGB_LBLUE = [RGB_CYAN,RGB_BLUE]
RGB_PINK = [RGB_MAGENTA,RGB_RED]
RGB_PURPLE = [RGB_MAGENTA,RGB_BLUE]
RGB_ORANGE = [RGB_YELLOW,RGB_RED]
RGB_LIME = [RGB_YELLOW,RGB_GREEN]
RGB_COLORS = [RGB_LIME,RGB_YELLOW,RGB_ORANGE,RGB_RED,
RGB_PINK,RGB_MAGENTA,RGB_PURPLE,RGB_BLUE,
RGB_LBLUE,RGB_CYAN,RGB_AQUA,RGB_GREEN]
前面的代码将提供创建阴影所需的颜色组合,RGB_COLORS
提供平滑的渐变。
led_combo()
的函数来处理单个或多个颜色。该功能的代码如下所示:def led_combo(pins,colors,period):
#determine if "colors" is a single integer or not
if isinstance(colors,int):
#Single integer - reference directly
led_time(pins,colors,period)
else:
#if not, then cycle through the "colors" list
for i in colors:
led_time(pins,i,period)
rgbledrainbow.py
,以利用rgbled.py
模块中的新函数。rgbledrainbow.py
脚本如下:#!/usr/bin/python3
#rgbledrainbow.py
import time
import rgbled as RGBLED
def next_value(number,max):
number = number % max
return number
def main():
print ("Setup the RGB module")
RGBLED.led_setup()
# Multiple LEDs with different Colors
print ("Switch on Rainbow")
led_num = 0
col_num = 0
for l in range(5):
print ("Cycle LEDs")
for k in range(100):
#Set the starting point for the next set of colors
col_num = next_value(col_num+1,len(RGBLED.RGB_COLORS))
for i in range(20): #cycle time
for j in range(5): #led cycle
led_num = next_value(j,len(RGBLED.LED))
led_color = next_value(col_num+led_num,
len(RGBLED.RGB_COLORS))
RGBLED.led_combo(RGBLED.LED[led_num],
RGBLED.RGB_COLORS[led_color],0.001)
print ("Cycle COLORs")
for k in range(100):
#Set the next color
col_num = next_value(col_num+1,len(RGBLED.RGB_COLORS))
for i in range(20): #cycle time
for j in range(5): #led cycle
led_num = next_value(j,len(RGBLED.LED))
RGBLED.led_combo(RGBLED.LED[led_num],
RGBLED.RGB_COLORS[col_num],0.001)
print ("Finished")
if __name__=='__main__':
try:
main()
finally:
RGBLED.led_cleanup()
#End
main()
功能将首先在 LED 之间循环,在所有 LED 上设置RGB_COLORS
阵列中的每种颜色。然后,它将在颜色之间循环,在 LED 上产生彩虹效果:
Cycling through multiple colors on the five RGB LEDs
视觉持久性(POV)显示器可以产生一种近乎神奇的效果,通过非常快速地来回移动一行 LED 或绕圈子来显示空中的图像。这种效果之所以有效,是因为您的眼睛无法快速调整以分离出单个闪光,因此您观察到一个合并图像(显示的消息或图片):
Persistence of vision using RGB LEDs
此配方使用上一配方中使用的 RGB LED 套件;您还需要以下附加项目:
应将倾斜开关添加到 RGB LED(如多路复用彩色 LED配方的准备部分所述)。倾斜开关的接线如下所示:
The tilt switch is connected to GPIO Input (GPIO pin 24) and Gnd (GPIO pin 6)
要再现 POV 图像,您需要能够快速移动 LED 并前后倾斜开关。请注意倾斜开关的安装方式与侧面成一定角度,以便开关向左移动时打开。建议将硬件安装在一段木材或类似设备上。您甚至可以使用便携式 USB 电池组和 Wi-Fi 加密狗通过远程连接为 Raspberry Pi 供电和控制(参见第 1 章中的使用 SSH(和 X11 转发)通过网络远程连接到 Raspberry Pi 开始使用 Raspberry Pi 3 计算机,了解详细信息):
Persistence of vision hardware setup
您还需要完整的rgbled.py
文件,我们将在如何操作中进一步扩展该文件。。。部分
tilt.py
的脚本来报告倾斜开关的状态:#!/usr/bin/python3
#tilt.py
import RPi.GPIO as GPIO
#HARDWARE SETUP
# GPIO
# 2[===========T=]26[=======]40
# 1[=============]25[=======]39
#Tilt Config
TILT_SW = 24
def tilt_setup():
#Setup the wiring
GPIO.setmode(GPIO.BOARD)
#Setup Ports
GPIO.setup(TILT_SW,GPIO.IN,pull_up_down=GPIO.PUD_UP)
def tilt_moving():
#Report the state of the Tilt Switch
return GPIO.input(TILT_SW)
def main():
import time
tilt_setup()
while True:
print("TILT %s"% (GPIO.input(TILT_SW)))
time.sleep(0.1)
if __name__=='__main__':
try:
main()
finally:
GPIO.cleanup()
print("Closed Everything. END")
#End
sudo python3 tilt.py
rgbled_pov()
函数添加到我们之前创建的rgbled.py
脚本中;这将允许我们显示一行图像:def rgbled_pov(led_pattern,color,ontime):
'''Disable all the LEDs and re-enable the LED pattern in the required color'''
led_deactivate(LED,RGB)
for led_num,col_num in enumerate(led_pattern):
if col_num >= 1:
led_activate(LED[led_num],color)
time.sleep(ontime)
rgbledmessage.py
的文件,以执行显示消息所需的操作。首先,我们将导入使用的模块:更新的rgbled
模块、新的tilt
模块和 Pythonos
模块。最初,我们将DEBUG
设置为True
,因此 Python 终端将在脚本运行时显示附加信息:#!/usr/bin/python3
# rgbledmessage.py
import rgbled as RGBLED
import tilt as TILT
import os
DEBUG = True
readMessageFile()
函数读取letters.txt
文件的内容,然后添加processFileContent()
生成每个字母 LED 图案的Python 字典:def readMessageFile(filename):
assert os.path.exists(filename), 'Cannot find the message file: %s' % (filename)
try:
with open(filename, 'r') as theFile:
fileContent = theFile.readlines()
except IOError:
print("Unable to open %s" % (filename))
if DEBUG:print ("File Content START:")
if DEBUG:print (fileContent)
if DEBUG:print ("File Content END")
dictionary = processFileContent(fileContent)
return dictionary
def processFileContent(content):
letterIndex = [] #Will contain a list of letters stored in the file
letterList = [] #Will contain a list of letter formats
letterFormat = [] #Will contain the format of each letter
firstLetter = True
nextLetter = False
LETTERDIC={}
#Process each line that was in the file
for line in content:
# Ignore the # as comments
if '#' in line:
if DEBUG:print ("Comment: %s"%line)
#Check for " in the line = index name
elif '"' in line:
nextLetter = True
line = line.replace('"','') #Remove " characters
LETTER=line.rstrip()
if DEBUG:print ("Index: %s"%line)
#Remaining lines are formatting codes
else:
#Skip firstLetter until complete
if firstLetter:
firstLetter = False
nextLetter = False
lastLetter = LETTER
#Move to next letter if needed
if nextLetter:
nextLetter = False
LETTERDIC[lastLetter]=letterFormat[:]
letterFormat[:] = []
lastLetter = LETTER
#Save the format data
values = line.rstrip().split(' ')
row = []
for val in values:
row.append(int(val))
letterFormat.append(row)
LETTERDIC[lastLetter]=letterFormat[:]
#Show letter patterns for debugging
if DEBUG:print ("LETTERDIC: %s" %LETTERDIC)
if DEBUG:print ("C: %s"%LETTERDIC['C'])
if DEBUG:print ("O: %s"%LETTERDIC['O'])
return LETTERDIC
createBuffer()
功能,将一条消息转换为每个字母的一系列 LED 图案(假设字母由letters.txt
文件定义):def createBuffer(message,dictionary):
buffer=[]
for letter in message:
try:
letterPattern=dictionary[letter]
except KeyError:
if DEBUG:print("Unknown letter %s: use _"%letter)
letterPattern=dictionary['_']
buffer=addLetter(letterPattern,buffer)
if DEBUG:print("Buffer: %s"%buffer)
return buffer
def addLetter(letter,buffer):
for row in letter:
buffer.append(row)
buffer.append([0,0,0,0,0])
buffer.append([0,0,0,0,0])
return buffer
displayBuffer()
功能,使用rgbled
模块中的rgbled_pov()
功能显示 LED 图案:def displayBuffer(buffer):
position=0
while(1):
if(TILT.tilt_moving()==False):
position=0
elif (position+1)<len(buffer):
position+=1
if DEBUG:print("Pos:%s ROW:%s"%(position,buffer[position]))
RGBLED.rgbled_pov(buffer[position],RGBLED.RGB_GREEN,0.001)
RGBLED.rgbled_pov(buffer[position],RGBLED.RGB_BLUE,0.001)
main()
函数来执行所需的每个步骤:letters.txt
文件。rgbled
模块显示缓冲器,用tilt
模块控制:def main():
RGBLED.led_setup()
TILT.tilt_setup()
dict=readMessageFile('letters.txt')
buffer=createBuffer('_COOKBOOK_',dict)
displayBuffer(buffer)
if __name__=='__main__':
try:
main()
finally:
RGBLED.led_cleanup()
print("Closed Everything. END")
#End
letters.txt
的文件,以定义显示示例'_COOKBOOK_'
消息所需的 LED 模式。请注意,此文件只需要为消息中的每个唯一字母或符号定义一个模式:#COOKBOOK
"C"
0 1 1 1 0
1 0 0 0 1
1 0 0 0 1
"O"
0 1 1 1 0
1 0 0 0 1
1 0 0 0 1
0 1 1 1 0
"K"
1 1 1 1 1
0 1 0 1 0
1 0 0 0 1
"B"
1 1 1 1 1
1 0 1 0 1
0 1 0 1 0
"_"
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
第一个函数readMessageFile()
将打开并读取给定文件的内容。然后,它将使用processFileContent()
返回一个 Python 字典,其中包含所提供文件中定义的字母的对应模式。处理文件中的每一行,忽略包含#
字符的任何行,并检查"
字符以指示后面的 LED 图案的名称。处理完文件后,我们得到一个 Python 字典,其中包含'_'
、'C'
、'B'
、'K'
和'O'
字符的 LED 模式:
'_': [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
'C': [[0, 1, 1, 1, 0], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1]]
'B': [[1, 1, 1, 1, 1], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0]]
'K': [[1, 1, 1, 1, 1], [0, 1, 0, 1, 0], [1, 0, 0, 0, 1]]
'O': [[0, 1, 1, 1, 0], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [0, 1, 1, 1, 0]]
现在我们可以选择字母,我们可以使用createBuffer()
功能创建一系列 LED 图案。顾名思义,该函数将通过查找消息中的每个字母并逐行添加相关图案来建立 LED 图案的缓冲区。如果在字典中找不到字母,则将使用空格代替。
最后,我们现在有一个准备好显示的 LED 模式列表。为了控制启动顺序的时间,我们将使用倾斜模块并检查倾斜开关的状态:
The tilt switch position when not moving (left) and moving (right)
倾斜开关由一个小滚珠轴承组成,该轴承封闭在一个中空的绝缘圆筒内;当钢球位于气缸底部时,两个销之间的连接闭合。当球移动到油缸的另一端,脱离销接触时,倾斜开关打开:
The tilt switch circuit with the switch closed and with the switch open
当开关闭合时,上述倾斜开关电路将允许 GPIO 针脚 24 接地。然后,如果我们读取 pin,它将在静止时返回False
。通过将 GPIO 引脚设置为输入并启用内部上拉电阻器,当倾斜开关打开时,它将报告True
。
如果倾斜开关打开(报告True
,则我们将假设装置正在移动,并开始显示 LED 序列,每次显示一行 LED 图案时,增加当前位置。为了使图案更鲜艳一点(因为我们可以!),我们用另一种颜色重复每一行。一旦TILT.tilt_moving()
功能报告我们已停止移动或正在朝相反方向移动,我们将重置当前位置,准备重新启动整个模式:
The message is displayed by the RGB LEDs - here, we are using green and blue together
当 RGB LED 模块和倾斜开关前后移动时,我们会看到空中显示的信息!
尝试不同的颜色组合、速度和手臂波浪度,看看你能产生什么效果。您甚至可以创建一个安装在轮子上的类似设置,以产生连续的 POV 效果。