這篇博文是我Coursera學習筆記整理所得,入門操作基本都在這里了。閑話不多說,直接進入正題。
1.樹莓派的GPIO##
GPIO是General Purpose Input Output (通用輸入/輸出)的縮寫,一般譯為總線擴展器,人們利用工業標準I2C、SMBus或SPI接口簡化了I/O口的擴展。當微控制器或芯片組沒有足夠的I/O端口,或當系統需要采用遠端串行通信或控制時,GPIO產品能夠提供額外的控制和監視功能。摘自百度百科
除了Raspberry Zero之外,其他版本的樹莓派GPIO都帶標準的GPIO,而且都是公頭(與Arduino Uno正好相反)。Raspberry Zero比較奇葩。它是專門為制作嵌入式系統設計的,為了減小體積和成本(主要是體積),它的GPIO不帶頭。對于需要使用GPIO的研發人員,需要自己動手焊上去。
因為各個版本的樹莓派GPIO的數量不一樣,所以,可想而知,各個版本樹莓派的GPIO布局也是不一樣的。這在開發的時候有些小麻煩。本文以樹莓派3代為例,不過,先給出各版本樹莓派GPIO的布局以供參考:
-
樹莓派A型和B型###


-
樹莓派A+型、B+型和2代###


-
樹莓派3代###
以上我們可以看到一個GPIO針頭既有GPIO號標識,也可以用物理物質標識,編程時你需要說明你用何種方式標識,后文還會提到。
2.樹莓派編程基礎##
樹莓派基本都預裝好了Python的GPIO庫,通常在文件開頭使用import RPi.GPIO as GPIO
導入。
-
設置模式——GPIO.setmode###
GPIO.setmode(mode)
,mode參數有兩個值,GPIO.BOARD和GPIO.BCM,注意全是大寫。前者是告訴程序按物理位置找GPIO頭(或者叫channel),后者按GPIO號。兩種模式各有各的好處,前者方便找,后者方便程序在不同的樹莓派版本上跑,具體區別大家自己體會。
-
設置GPIO頭的輸入和輸出——GPIO.setup###
GPIO.setup(channel,mode)
,channel就是你要用的GPIO頭,mode分為輸入GPIO.IN和輸出GPIO.OUT。
GPIO.output(channel, GPIO.HIGH) #輸出高電平,就是輸出信號1
GPIO.output(channel, GPIO.LOW) #輸出低電平,就是輸出信號0
- ###調制脈寬,輸出模擬信號——GPIO.PWM###
樹莓派本身既不能接受模擬信號,也不能輸出模擬信號,要么輸出1,要么輸出0。不過可以通過改變數字信號的輸出占空比(就是一個周期內,GPIO打開時間占總時間的比例),使輸出效果近似的模擬信號。例如,我們牽絆周期打開GPIO輸出1,后半周期關閉GPIO,接受的設備(例如一個舵機或者一盞LED燈)沒方法反應過來,就會輸出0.5。樹莓派3代一般使用pin12和pin24調制脈寬。
p = GPIO.PWM(channel,frequency) #channel是GPIO頭,frequency是頻率
p.start(dc) #dc 是占空比 (0.0 <= dc <= 100.0)改變頻率:
p.ChangeFrequency(freq) #改變頻率到 freq Hz
p.ChangeDutyCycle(dc) #改變占空比: 0.0 <= dc <= 100.0
p.stop() # 停止 PWM:
- ###事件和回調函數——GPIO.add_event_detect###
熟悉交互編程的人都知道“事件”和“回調函數”。比如右擊鼠標是個事件,程序接受到這個事件,就會調用一個函數,這就是回調函數(個人淺薄的理解,很可能不正確,請雅正)。
GPIO.add_event_detect(channel,event, callback = functionname)
#channel就是你要用的GPIO頭,event是觸發事件,例如電平上升GPIO.RISING和電平下降GPIO.FALLING,functionname就是你要調用的函數的函數名。
##3.LED燈實驗##
有了語法基礎我們就可以做一些小實驗了,這里給出介紹閃爍燈、呼吸燈和開關控制燈的代碼。
- ###閃爍燈###
這段代碼的效果是:按下按鈕,LED保持長亮;松開按鈕,LED燈一直閃爍。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT) #設置pin8負責輸出電壓
GPIO.setup(12, GPIO.IN) #設置pin12負責讀取按鈕的信號
def blink():
#通過交替輸出高低電頻來是LED燈閃爍
GPIO.output(8,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(8,GPIO.LOW)
time.sleep(0.5)
主程序
try:
#如果pin12接受到按鈕的信號,那么使LED燈亮; 否則燈就閃爍
while True:
if GPIO.input(12):
GPIO.output(8,GPIO.HIGH)
else:
blink()
except KeyboardInterrupt:
pass
GPIO.cleanup()
- ###呼吸燈###
這段代碼是讓LED等漸明漸暗。
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
p = GPIO.PWM(12, 50)
啟動pwm
p.start(0)
try:
while True:
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
停止pwm
p.stop()
GPIO.cleanup()
- ###按鈕開關###
這段代碼的效果是:按一下按鈕,關閉燈;再按一下,打開燈。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT) #設置pin8負責輸出電壓
GPIO.setup(12, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #設置pin12負責讀取按鈕的信號,pin12初始狀態是GND(0電勢,相當于接地電壓)
全局變量ledStatus是一個邏輯開關,一開始設為False
ledStatus = False
定義回調函數
def my_callback(channel):
print("button pressed")
global ledStatus
ledStatus = not ledStatus
if ledStatus:
GPIO.output(8, GPIO.HIGH)
else:
GPIO.output(8, GPIO.LOW)
定義觸發事件,bouncetime是防止消除按鍵抖動,不必在意
GPIO.add_event_detect(12,GPIO.RISING, callback = my_callback, bouncetime = 200)
主程序,如果不按下按鈕,主程序就什么都不做。
try:
while True:
print("I'm working")
time.sleep(5)
except KeyboardInterrupt:
pass
GPIO.cleanup()