前面已经学习了一些树莓派系统和GPIO的基本知识了,现在可以开始动手做一些简单的东西了。因为一些外设的连接会涉及到一些电路的知识,如果操作不当可能会损坏外设或者是树莓派。所以在哦动手之前最好还是补充点电路相关的知识。我是花了点时间又把初中电路稍微复习了下,然后又乱七八糟看了点模拟电路、数字电路。所以最终应该也没有太多用处。
网上对于树莓派第一个项目基本就是接LED,然后控制。所以我第一个程序也使用LED,只不过想做的稍微复杂一点。 结合数码管和蜂鸣器来模拟十字路口的交通信号灯。使用的材料主要有:
- 3个不同颜色的LED灯
- TM1637四位数码管
- 有源蜂鸣器
- 若干100欧以上的电阻
- 面包板和面包板连接线
- 若干杜邦线
一 使用LED
点亮测试
首先实现信号灯中最简单的LED。第一次连接设备,为了安全,先只通电测试,不连接树莓派,点亮LED灯看看。
使用了面包板外接电源板,可以使用USB或9V的DC电源作为输入。有两组供电,按+/- 插在面包板上。 3组LED灯并联。 每一组串联的一个100欧的电阻(几十欧也可以,根据外接电压和电流来算一下)。 LED灯实际是一个发光二极管,压降一般在2V-3.5V之间,而电流一般控制在20ma。 超过40ma可能会烧毁。 这里我使用外接3.3V电压(和GPIO口电压一致)。通电或的效果如下。其中黄色等感觉偏暗,所以吧电阻换成了47欧,还是有点。
然后替换掉外接电源,直接从树莓派接触3.3V和GND2条线,连接到面包板的+/-导线上,LED也能正常发光。
编程控制
电路连接好了之后就可以开始通过代码来编程控制LED的开关了。 所以LED灯的正级不直接接入3.3V,而是接入GPIO接口,当接口发出高电平点亮LED,低电平时LED熄灭。
选择GPIO口
只需要控制电平,所以使用任意的GPIO接口都可以。
- 红灯: GPIO25
- 蓝灯: GPIO8
- 绿灯: GPIO7
编写代码
这里我使用RPI.GPIO的python来开发,第一使用,先安装库。
sudo apt install rpi.gpio
安装完成之后就可以开始编码了,我在github上创建了一个仓库,这样就可以方便的把代码管理起来: https://github.com/cclover/RaspberrySample.git
本地把git仓库同步下来:
pi@raspberrypi-cc:~/source $ git clone https://github.com/cclover/RaspberrySample.git
Cloning into 'RaspberrySample'...
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 7 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (7/7), done.
创建相应的目录后就可以开始了, 这里创建了一个TrafficLight目录
pi@raspberrypi-cc:~/source cd RaspberrySample/
pi@raspberrypi-cc:~/source/RaspberrySample ls -l
total 16
-rw-r--r-- 1 pi pi 11349 Aug 18 16:48 LICENSE
-rw-r--r-- 1 pi pi 40 Aug 18 16:48 README.md
pi@raspberrypi-cc:~/source/RaspberrySample mkdir TrafficLight
pi@raspberrypi-cc:~/source/RaspberrySample cd TrafficLight/
pi@raspberrypi-cc:~/source/RaspberrySample/TrafficLight $
代码如下:
#-*- encoding=utf8 -*-
#import RPi.GPIO as GPIO
import sys
import time
import threading
import signal
sys.path.append('./timer.py')
from timer import LoopTimer
#define LED PIN
PIN_LIGHT_RED = 25
PIN_LIGHT_BLUE = 8
PIN_LIGHT_GREEN = 7
#LED Status
LED_STATUS_OFF = 0
LED_STATUS_ON = 1
LED_STATUS_BLINK = 2
#Traffic Light time
TIME_LIGHT_RED = 10
TIME_LIGHT_BLUE = 3
TIME_LIGHT_GREEN = 10
TIME_BLINK_GREEN = 3
TIME_INTERVAL = 1
#light list
light_list = [ PIN_LIGHT_RED, PIN_LIGHT_BLUE, PIN_LIGHT_GREEN ]
#remain timer
reaminTime = 0
def initLED():
print "Init LED!!"
#GPIO.setup(light_list, GPIO.OUT)
def init():
print "Init Traffic!!"
#GPIO.setmode(GPIO.BCM)
initLED()
def destory(signum, frame):
print "Destory Traffic!!"
#GPIO.cleanup()
exit()
def switchLight(light, status):
if not light in light_list:
return
if status == LED_STATUS_OFF:
print "LIGHT OFF {0}".format(light)
#GPIO.output(light, GPIO.LOW)
elif status == LED_STATUS_ON:
print "LIGHT ON {0}".format(light)
#GPIO.output(light, GPIO.HIGH)
def blinkLight(light):
print "blinkLight"
switchLight(light, LED_STATUS_OFF)
time.sleep(0.5)
switchLight(light, LED_STATUS_ON)
time.sleep(0.5)
switchLight(light, LED_STATUS_OFF)
time.sleep(0.5)
switchLight(light, LED_STATUS_ON)
def redInterval():
global reaminTime
reaminTime = reaminTime - 1
print "Read remain: {0}s".format(reaminTime)
def redTraffic():
#red timer
global reaminTime
reaminTime = TIME_LIGHT_RED
lightTimer = LoopTimer(TIME_LIGHT_RED, TIME_INTERVAL, redInterval, greenTraffic)
#light red
switchLight(PIN_LIGHT_GREEN, LED_STATUS_OFF)
switchLight(PIN_LIGHT_RED, LED_STATUS_ON)
switchLight(PIN_LIGHT_BLUE, LED_STATUS_OFF)
# start time
print "Light on red {0}s".format(reaminTime)
lightTimer.start()
def blueInterval():
global reaminTime
reaminTime = reaminTime - 1
print "Blue remain: {0}s".format(reaminTime)
def blueTraffic():
#blue timer
global reaminTime
reaminTime = TIME_LIGHT_BLUE
lightTimer = LoopTimer(TIME_LIGHT_BLUE, TIME_INTERVAL, blueInterval, redTraffic)
#light blue
switchLight(PIN_LIGHT_GREEN, LED_STATUS_OFF)
switchLight(PIN_LIGHT_RED, LED_STATUS_OFF)
switchLight(PIN_LIGHT_BLUE, LED_STATUS_ON)
# start time
print "Light on blue {0}s".format(reaminTime)
lightTimer.start()
def greenInterval():
global reaminTime
reaminTime = reaminTime - 1
print "Green remain: {0}s".format(reaminTime)
if reaminTime <= TIME_BLINK_GREEN:
blinkLight(PIN_LIGHT_GREEN)
def greenTraffic():
#green timer
global reaminTime
reaminTime = TIME_LIGHT_GREEN
lightTimer = LoopTimer(TIME_LIGHT_GREEN, TIME_INTERVAL, greenInterval, blueTraffic)
#light green
switchLight(PIN_LIGHT_GREEN, LED_STATUS_ON)
switchLight(PIN_LIGHT_RED, LED_STATUS_OFF)
switchLight(PIN_LIGHT_BLUE, LED_STATUS_OFF)
# start time
print "Light on green {0}s".format(reaminTime)
lightTimer.start()
def registerExit():
signal.signal(signal.SIGINT, destory)
signal.signal(signal.SIGTERM, destory)
#main funciton
init()
registerExit()
print "Start traffic!!"
print "Press 'Ctrl+C' to exit..."
greenTraffic()
整体比较简单,绿灯显示10秒,最后3秒闪烁, 然后切换到蓝灯,蓝灯3秒后切换到红灯,红灯显示10秒。 python没用几次还不太熟,花了一下午时间。 线也连接的有点问题。
修改一下连线, 从树莓派GPIO口的7、8、25引出3根线,直接和对应的LED灯的+ 连接,从GND连接到面包板的 – 级。运行程序,可以按照预想工作了。
二 蜂鸣器
一般交通信号绿灯最后3秒闪烁的同时也会有声音提示,所以这里用蜂鸣器模仿一下。这里使用的是有源蜂鸣器,只需要给一个低电平就可以发声。这个外设有3个针脚,VCC、GND和I/O,VCC支持3.3~5V,所以I/O接口接上任意一个GIOP就行了。
选择GPIO口
只需要控制电平,所以使用任意的GPIO接口都可以。
- I/O: GPIO24
编写代码
增加蜂鸣相关的代码,并在绿灯闪烁时调用一下
#define buzzer PIN
PIN_BUZZER = 24
def initBuzzer():
print "Init Buzzer"
GPIO.setup(PIN_BUZZER, GPIO.OUT, initial=GPIO.HIGH)
def beepBuzzer(trig):
print "beepBuzzer"
GPIO.output(trig,GPIO.LOW)
time.sleep(0.3)
GPIO.output(trig,GPIO.HIGH)
time.sleep(0.3)
GPIO.output(trig,GPIO.LOW)
time.sleep(0.3)
GPIO.output(trig,GPIO.HIGH)
因为蜂鸣器需要3.3V电源和GPIO24,所以在之前连线基础上引出了一根3.3V连接到面包板的+ (左下), 蜂鸣器的GND和VCC和面包版的+ / – 相连。 I/O和GPIO24连接。
接通树莓派电源,执行python程序, 绿灯闪烁时蜂鸣器可以发出beep、beep的声音了。
三 数码管
最后一项就是显示出倒计时时间,这里使用了TM1637的4位数码管。DIO和CLK接口可以选择任意的GPIO接口,这里选择GPIO14和GPIO15
TM1637 Board Pin | Function | Raspberry Pin |
---|---|---|
GND | Ground | GND |
VCC | +5V Power | 5V |
DIO | Data In | GPIO 14 |
CLK | Clock | GPIO 15 |
这里要注意,这个设备使用的是5V的VCC,在使用5V外设的时候要注意GPIO口是INPUT还是OUTPUT,如果是OUTPUT问题不大,如果是INPUT,那么要注意外设产生的电平可能是5V,而树莓派GPIO口能承受的电平是3.3V,所以可能会损坏树莓派,这个时候就需要一个5V-3.3V的电平转换,可以自己用电阻做一个(网上搜索一下就有),也可以直接买一个8路5V-3.3V的电平转换。 不做数码管是一个输入设备,所以我们这里不需要。
编写代码
相比前面的LED灯和有源蜂鸣器,这个四位数码管就复杂很多了,不是高低电平就能搞定的。而RPI.GPIO没有直接提供控制TM1637的库,要想让TM1637显示一种办法找他的文档自己撸,另一种就是别人写好的库。 对于我们来说一般选择后一种了。google一下还是很多的,有C写的,也有python的。
最早下载的是这个源码,但是这个有问题,缺少方法,不知道那些用这个的人是怎么用的。。。
wget https://raspberrytips.nl/files/tm1637.py
然后找了一个可以用的,这个里面有测试代码,注释掉就好了
wget https://raw.githubusercontent.com/timwaizenegger/raspberrypi-examples/master/actor-led-7segment-4numbers/tm1637.py
在我们之前的代码中增加显示相关的代码:
#define TM1637 pin
PIN_DIO = 14
PIN_CLK = 15
def initDisplay():
global display
display = TM1637(PIN_CLK, PIN_DIO, 2)
display.Clear()
def showTime(sec):
global display
display.ShowInt(sec)
另外在退出的时候要清空一下显示的内容
def destory(signum, frame):
print "Destory Traffic!!"
global display
display.cleanup()
GPIO.cleanup()
exit()
TM1637需要4根线,为了方便吧风扇拔掉了,这样4个线就可以连在一起了,方便一点。最终效果图如下,可以正确的显示数字了。
最终效果
不知道怎么我这不能播放优酷视频了,那就贴上链接
http://v.youku.com/v_show/id_XMzc4NzUxNDA0NA==.html?spm=a2hzp.8244740.0.0
发现在绿灯倒数3S的时候,1S的时间变长了。看了下代码,应该是time.sleep导致timer时间变长,所以用2个单独的线程来跑一下就好了。
def greenInterval():
global reaminTime
reaminTime = reaminTime - 1
print "Green remain: {0}s".format(reaminTime)
showTime(reaminTime)
if reaminTime <= TIME_BLINK_GREEN:
threading.Thread(target=blinkLight,args=(PIN_LIGHT_GREEN))
threading.Thread(target=beepBuzzer,args=(PIN_BUZZER))
项目地址:https://github.com/cclover/RaspberrySample/tree/master/TrafficLight