這篇博文是我Coursera學(xué)習(xí)筆記整理所得,入門(mén)操作基本都在這里了穷缤。閑話不多說(shuō)惠拭,直接進(jìn)入正題。
1.樹(shù)莓派的GPIO##
GPIO是General Purpose Input Output (通用輸入/輸出)的縮寫(xiě)亏娜,一般譯為總線擴(kuò)展器,人們利用工業(yè)標(biāo)準(zhǔn)I2C蹬挺、SMBus或SPI接口簡(jiǎn)化了I/O口的擴(kuò)展维贺。當(dāng)微控制器或芯片組沒(méi)有足夠的I/O端口,或當(dāng)系統(tǒng)需要采用遠(yuǎn)端串行通信或控制時(shí)巴帮,GPIO產(chǎn)品能夠提供額外的控制和監(jiān)視功能溯泣。摘自百度百科
除了Raspberry Zero之外,其他版本的樹(shù)莓派GPIO都帶標(biāo)準(zhǔn)的GPIO榕茧,而且都是公頭(與Arduino Uno正好相反)垃沦。Raspberry Zero比較奇葩。它是專(zhuān)門(mén)為制作嵌入式系統(tǒng)設(shè)計(jì)的用押,為了減小體積和成本(主要是體積)肢簿,它的GPIO不帶頭。對(duì)于需要使用GPIO的研發(fā)人員只恨,需要自己動(dòng)手焊上去译仗。
因?yàn)楦鱾€(gè)版本的樹(shù)莓派GPIO的數(shù)量不一樣,所以官觅,可想而知纵菌,各個(gè)版本樹(shù)莓派的GPIO布局也是不一樣的。這在開(kāi)發(fā)的時(shí)候有些小麻煩休涤。本文以樹(shù)莓派3代為例咱圆,不過(guò),先給出各版本樹(shù)莓派GPIO的布局以供參考:
-
樹(shù)莓派A型和B型###
![Raspberry Pi A & B功氨,按GPIO號(hào)顯示](https://www.raspberrypi.org/documentation/usage/gpio/images/a-and-b-gpio-numbers.png)
![Raspberry Pi A & B,按物理位置顯示](https://www.raspberrypi.org/documentation/usage/gpio/images/a-and-b-physical-pin-numbers.png)
-
樹(shù)莓派A+型忱详、B+型和2代###
![Raspberry A+, B+, 2,按GPIO號(hào)顯示](https://www.raspberrypi.org/documentation/usage/gpio-plus-and-raspi2/images/gpio-numbers-pi2.png)
![Raspberry A+, B+, 2匈睁,按物理位置顯示](https://www.raspberrypi.org/documentation/usage/gpio-plus-and-raspi2/images/physical-pin-numbers.png)
-
樹(shù)莓派3代###
以上我們可以看到一個(gè)GPIO針頭既有GPIO號(hào)標(biāo)識(shí),也可以用物理物質(zhì)標(biāo)識(shí)航唆,編程時(shí)你需要說(shuō)明你用何種方式標(biāo)識(shí)胀蛮,后文還會(huì)提到。
2.樹(shù)莓派編程基礎(chǔ)##
樹(shù)莓派基本都預(yù)裝好了Python的GPIO庫(kù)糯钙,通常在文件開(kāi)頭使用import RPi.GPIO as GPIO
導(dǎo)入粪狼。
-
設(shè)置模式——GPIO.setmode###
GPIO.setmode(mode)
,mode參數(shù)有兩個(gè)值任岸,GPIO.BOARD和GPIO.BCM再榄,注意全是大寫(xiě)。前者是告訴程序按物理位置找GPIO頭(或者叫channel)演闭,后者按GPIO號(hào)不跟。兩種模式各有各的好處,前者方便找米碰,后者方便程序在不同的樹(shù)莓派版本上跑窝革,具體區(qū)別大家自己體會(huì)。
-
設(shè)置GPIO頭的輸入和輸出——GPIO.setup###
GPIO.setup(channel,mode)
,channel就是你要用的GPIO頭吕座,mode分為輸入GPIO.IN和輸出GPIO.OUT虐译。
GPIO.output(channel, GPIO.HIGH) #輸出高電平,就是輸出信號(hào)1
GPIO.output(channel, GPIO.LOW) #輸出低電平吴趴,就是輸出信號(hào)0
- ###調(diào)制脈寬漆诽,輸出模擬信號(hào)——GPIO.PWM###
樹(shù)莓派本身既不能接受模擬信號(hào),也不能輸出模擬信號(hào)锣枝,要么輸出1厢拭,要么輸出0。不過(guò)可以通過(guò)改變數(shù)字信號(hào)的輸出占空比(就是一個(gè)周期內(nèi)撇叁,GPIO打開(kāi)時(shí)間占總時(shí)間的比例)供鸠,使輸出效果近似的模擬信號(hào)。例如陨闹,我們牽絆周期打開(kāi)GPIO輸出1楞捂,后半周期關(guān)閉GPIO,接受的設(shè)備(例如一個(gè)舵機(jī)或者一盞LED燈)沒(méi)方法反應(yīng)過(guò)來(lái)趋厉,就會(huì)輸出0.5寨闹。樹(shù)莓派3代一般使用pin12和pin24調(diào)制脈寬。
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:
- ###事件和回調(diào)函數(shù)——GPIO.add_event_detect###
熟悉交互編程的人都知道“事件”和“回調(diào)函數(shù)”繁堡。比如右擊鼠標(biāo)是個(gè)事件,程序接受到這個(gè)事件,就會(huì)調(diào)用一個(gè)函數(shù)帖蔓,這就是回調(diào)函數(shù)(個(gè)人淺薄的理解矮瘟,很可能不正確瞳脓,請(qǐng)雅正)塑娇。
GPIO.add_event_detect(channel,event, callback = functionname)
#channel就是你要用的GPIO頭,event是觸發(fā)事件劫侧,例如電平上升GPIO.RISING和電平下降GPIO.FALLING埋酬,functionname就是你要調(diào)用的函數(shù)的函數(shù)名。
##3.LED燈實(shí)驗(yàn)##
有了語(yǔ)法基礎(chǔ)我們就可以做一些小實(shí)驗(yàn)了烧栋,這里給出介紹閃爍燈写妥、呼吸燈和開(kāi)關(guān)控制燈的代碼。
- ###閃爍燈###
這段代碼的效果是:按下按鈕审姓,LED保持長(zhǎng)亮珍特;松開(kāi)按鈕,LED燈一直閃爍魔吐。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT) #設(shè)置pin8負(fù)責(zé)輸出電壓
GPIO.setup(12, GPIO.IN) #設(shè)置pin12負(fù)責(zé)讀取按鈕的信號(hào)
def blink():
#通過(guò)交替輸出高低電頻來(lái)是LED燈閃爍
GPIO.output(8,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(8,GPIO.LOW)
time.sleep(0.5)
主程序
try:
#如果pin12接受到按鈕的信號(hào)扎筒,那么使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)
啟動(dòng)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()
- ###按鈕開(kāi)關(guān)###
這段代碼的效果是:按一下按鈕酬姆,關(guān)閉燈嗜桌;再按一下,打開(kāi)燈辞色。
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT) #設(shè)置pin8負(fù)責(zé)輸出電壓
GPIO.setup(12, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #設(shè)置pin12負(fù)責(zé)讀取按鈕的信號(hào),pin12初始狀態(tài)是GND(0電勢(shì)骨宠,相當(dāng)于接地電壓)
全局變量ledStatus是一個(gè)邏輯開(kāi)關(guān),一開(kāi)始設(shè)為False
ledStatus = False
定義回調(diào)函數(shù)
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)
定義觸發(fā)事件,bouncetime是防止消除按鍵抖動(dòng)相满,不必在意
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()