樹莓派GPIO最入門教程:先從控制一個LED小燈開始

樹莓派GPIO最入門教程:先從控制一個LED小燈開始

玩轉(zhuǎn)樹莓派2017-07-09 00:00

點亮LED

概述

本教程目的是用程序?qū)?LED 燈點亮,3秒鐘后燈自動熄滅。在所有軟件編程語言中,第一個程序都叫hello world,而今天的點燈教程其實就是硬件編程的 hello world,例子非常簡單。

通過本節(jié)課,我們能學(xué)習(xí)到:

硬件編程初體驗

面包板的使用

LED 原理

通過GPIO來控制硬件

所需硬件

樹莓派 x1

面包板 x1

杜邦線 x2

LED燈 x1

名稱解釋

下面對本實驗中要涉及到的一些電子元件和專業(yè)名稱做簡單介紹:

面包板

面包板是專為電子電路的無焊接實驗設(shè)計制造的,板子上有很多小插孔,由于各種電子元器件可根據(jù)需要隨意插入或拔出,免去了焊接,節(jié)省了電路的組裝時間,而且元件可以重復(fù)使用,所以非常適合電子電路的組裝、調(diào)試和訓(xùn)練。

由于最上一行和最下一行往往都是相通的,所以這兩行往往用于連接電路的電源線和地線,而元器件之間的連接往往采用中的各列。中間部分每五列柵格為一組,這一組五個柵格是導(dǎo)通的,在最中間的位置有一條凹槽,用于隔斷左右兩部分。

LED 燈

LED 是英文 Light Emitting Diode(發(fā)光二極管)的縮寫。它有2個腳,長腳是正極,短腳是負極。當(dāng)有電流流過時,LED 就會亮起。

GPIO

GPIO(General Purpose I/O Ports)意思為通用輸入/輸出端口,通俗地說,就是一些引腳,可以通過它們輸出高低電平或者通過它們讀入引腳的狀態(tài)-是高電平或是低電平。GPIO是個比較重要的概念,用戶可以通過GPIO口和硬件進行數(shù)據(jù)交互(如UART),控制硬件工作(如LED、蜂鳴器等),讀取硬件的工作狀態(tài)信號(如中斷信號)等。GPIO口的使用非常廣泛,掌握了GPIO,差不多相當(dāng)于掌握了操作硬件的能力。

現(xiàn)在,我們先看看樹莓派上的GPIO是怎么樣的,這是樹莓派的正面圖:

上面有40根排針,這就是樹莓派用于控制外部傳感器的接口,稱之為GPIO。40根引腳如何進行編號呢?如果按照物理位置來編號,只要掌握一個規(guī)則就容易記住: 最靠近角上的那一根引腳為2號引腳。旁邊的就是1號引腳,具體請看上圖示意圖。

那么這40根引腳具體的用途和定義是什么呢,請看下面的圖:

(這張圖以后經(jīng)常要用到,建議保存下來,方便以后使用)

這個圖是一個比較全面的一個定義,主要是因為對于這40根引腳有不同的編號規(guī)則來定義 雖然不同的規(guī)則叫的名字不一樣,但實際的用途是一致的 這里只學(xué)習(xí)一種編號規(guī)則,也就是物理位置編號,這樣更容易進行物理連接。

比如:1號引腳,是輸出1個3.3伏的電壓,也就是如果用數(shù)字萬用表去測量這根引腳的電壓,會一直測出來是3.3伏。

比如:2號引腳,是輸出1個5伏的電壓,也就是如果用數(shù)字萬用表去測量這根引腳的電壓,會一直測出來是5伏。

比如:6號引腳,是一個GND,也就是接地,如果測量電壓的話,就是0伏。

比如:11號引腳,是綠色圖標(biāo),旁邊寫著GPIO17,其實這個接口就是普通的接口,可以輸入也可以輸出。如果設(shè)置為輸出,則可以輸出高電壓或者低電壓。輸出高電壓就是3.3伏,輸出低電壓就是0伏。可以通過程序來控制。GPIO17是另外一種編號方式而已,這里我們可以忽略。

假如需要一個恒定的電壓輸出到某個電路,則可以選擇3.3v或者5v的相應(yīng)接口。

假如需要一個變化的電壓輸出到某個電路,則可以選擇綠色的GPIO接口,例如11號、12號、13號、15號等。

python GPIO

該庫更確切的名稱為raspberry-gpio-python,樹莓派官方資料中推薦且容易上手。python GPIO是一個小型的python庫,可以幫助用戶完成raspberry相關(guān)IO口操作。但是python GPIO庫還沒有支持SPI、I2C或者1-wire等總線接口。除了python GPIO之外,還有眾多的python擴展庫(例如webiopi),毫無疑問的說python非常適合樹莓派,樹莓派也非常適合python。

rpio

這是一個 JavaScript 語言操作 GPIO 的庫,方法名和參數(shù)和 python GPIO 非常接近,更多信息請瀏覽官方網(wǎng)站

連線圖

在開始連接硬件電路之前,首先要做的事是將樹莓派電腦關(guān)機,并斷開電源。因為如果樹莓派主板帶電的時候,進行插接電路可能會導(dǎo)致電子元器件的燒毀,所以一定要記住:

連接電路的時候主板必須斷電。

圖片使用 Fritzing 繪制,更多示例圖片請到 Fritzing官網(wǎng) 瀏覽。

電路原理圖

示例代碼

連好線后,接下來的工作就是寫代碼。想用 python 來控制 GPIO,最便捷的辦法就是使用一些 python 類庫,比如樹莓派系統(tǒng)本身集成的

RPi.GPIO

本文詳細介紹如何使用

RPi.GPIO

來控制 GPIO,當(dāng)然,你可以用任何喜歡的語言來控制 GPIO。

導(dǎo)入RPi.GPIO模塊

可以用下面的代碼導(dǎo)入

RPi.GPIO

模塊。

import RPi.GPIO as GPIO

引入之后,就可以使用 GPIO 模塊的函數(shù)了。如果你想檢查模塊是否引入成功,也可以這樣寫:

try: import RPi.GPIO as GPIOexcept RuntimeError: print("引入錯誤")

針腳編號

在 RPi.GPIO 中,同時支持樹莓派上的兩種 GPIO 引腳編號。

第一種編號是

BOARD編號

,這和樹莓派電路板上的物理引腳編號相對應(yīng)。使用這種編號的好處是,你的硬件將是一直可以使用的,不用擔(dān)心樹莓派的版本問題。因此,在電路板升級后,你不需要重寫連接器或代碼。

第二種編號是

BCM規(guī)則

,是更底層的工作方式,它和Broadcom的片上系統(tǒng)中信道編號相對應(yīng)。在使用一個引腳時,你需要查找信道號和物理引腳編號之間的對應(yīng)規(guī)則。對于不同的樹莓派版本,編寫的腳本文件也可能是無法通用的。

你可以使用下列代碼(強制的)指定一種編號規(guī)則:

GPIO.setmode(GPIO.BOARD) # orGPIO.setmode(GPIO.BCM)

下面代碼將返回被設(shè)置的編號規(guī)則

mode = GPIO.getmode()

警告

如果

RPi.GRIO

檢測到一個引腳已經(jīng)被設(shè)置成了非默認值,那么你將看到一個警告信息。你可以通過下列代碼禁用警告:

GPIO.setwarnings(False)

引腳設(shè)置

在使用一個引腳前,你需要設(shè)置這些引腳作為輸入還是輸出。配置一個引腳的代碼如下:

# 將引腳設(shè)置為輸入模式GPIO.setup(channel, GPIO.IN)# 將引腳設(shè)置為輸出模式GPIO.setup(channel, GPIO.OUT)# 為輸出的引腳設(shè)置默認值GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)

釋放

一般來說,程序到達最后都需要釋放資源,這個好習(xí)慣可以避免偶然損壞樹莓派。釋放腳本中使用的引腳:

GPIO.cleanup()

注意,GPIO.cleanup()只會釋放掉腳本中使用的GPIO引腳,并會清除設(shè)置的引腳編號規(guī)則。

輸出

要想點亮一個 LED 燈或者驅(qū)動某個設(shè)備,都需要給它們電流和電壓,這個步驟也很簡單,設(shè)置引腳的輸出狀態(tài)就可以了,代碼如下:

GPIO.output(channel, state)

狀態(tài)可以設(shè)置為0 / GPIO.LOW / False / 1 / GPIO.HIGH / True。如果編碼規(guī)則為,GPIO.BOARD,那么channel就是對應(yīng)引腳的數(shù)字。

如果想一次性設(shè)置多個引腳,可使用下面的代碼:

chan_list = [11,12]GPIO.output(chan_list, GPIO.LOW)GPIO.output(chan_list, (GPIO.HIGH, GPIO.LOW))

你還可以使用Input()函數(shù)讀取一個輸出引腳的狀態(tài)并將其作為輸出值,例如:

GPIO.output(12, not GPIO.input(12))

讀取

我們也常常需要讀取引腳的輸入狀態(tài),獲取引腳輸入狀態(tài)如下代碼:

GPIO.input(channel)

低電平返回

0 / GPIO.LOW / False

,高電平返回

1 / GPIO.HIGH / True

如果輸入引腳處于懸空狀態(tài),引腳的值將是漂動的。換句話說,讀取到的值是未知的,因為它并沒有被連接到任何的信號上,直到按下一個按鈕或開關(guān)。由于干擾的影響,輸入的值可能會反復(fù)的變化。 使用如下代碼可以解決問題:

GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP) # orGPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

需要注意的是,上面的讀取代碼只是獲取當(dāng)前一瞬間的引腳輸入信號。

如果需要實時監(jiān)控引腳的狀態(tài)變化,可以有兩種辦法。最簡單原始的方式是每隔一段時間檢查輸入的信號值,這種方式被稱為輪詢。如果你的程序讀取的時機錯誤,則很可能會丟失輸入信號。輪詢是在循環(huán)中執(zhí)行的,這種方式比較占用處理器資源。另一種響應(yīng)GPIO輸入的方式是使用中斷(邊緣檢測),這里的邊緣是指信號從高到低的變換(下降沿)或從低到高的變換(上升沿)。

輪詢方式

while GPIO.input(channel) == GPIO.LOW:

邊緣檢測

邊緣是指信號狀態(tài)的改變,從低到高(上升沿)或從高到低(下降沿)。通常情況下,我們更關(guān)心于輸入狀態(tài)的該邊而不是輸入信號的值。這種狀態(tài)的該邊被稱為事件。 先介紹兩個函數(shù):

wait_for_edge() 函數(shù) wait_for_edge()被用于阻止程序的繼續(xù)執(zhí)行,直到檢測到一個邊沿。也就是說,上文中等待按鈕按下的實例可以改寫為:

channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)if channel is None: print('Timeout occurred')else: print('Edge detected on channel', channel)

add_event_detect() 函數(shù) 該函數(shù)對一個引腳進行監(jiān)聽,一旦引腳輸入狀態(tài)發(fā)生了改變,調(diào)用event_detected()函數(shù)會返回true,如下代碼:

GPIO.add_event_detect(channel, GPIO.RISING) # add rising edge detection on a channeldo_something()# 下面的代碼放在一個線程循環(huán)執(zhí)行。if GPIO.event_detected(channel): print('Button pressed')

上面的代碼需要自己新建一個線程去循環(huán)檢測event_detected()的值,還算是比較麻煩的。

不過可采用另一種辦法輕松檢測狀態(tài),這種方式是直接傳入一個回調(diào)函數(shù):

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)

如果你想設(shè)置多個回調(diào)函數(shù),可以這樣:

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)

注意:回調(diào)觸發(fā)時,并不會同時執(zhí)行回調(diào)函數(shù),而是根據(jù)設(shè)置的順序調(diào)用它們。

好了,上面說明了一大堆函數(shù)庫的用法,那么現(xiàn)在就應(yīng)該來個簡單的實驗了

#!/usr/bin/env python# encoding: utf-8# 導(dǎo)入模塊RPI.GPIO,命名為別名為GPIOimport RPi.GPIO as GPIO# 導(dǎo)入time模塊import time# 聲明 GPIO 使用物理編號方式,也就是11號口就是物理編號11號口GPIO.setmode(GPIO.BOARD)# 聲明11號口是用于輸出模式GPIO.setup(11, GPIO.OUT)# 設(shè)置11號口為高電壓,也就是11號口變?yōu)?.3伏# 這行代碼執(zhí)行之后,11號口變?yōu)楦唠妷海? 那么根據(jù)電路原理,led燈就會亮起來GPIO.output(11, GPIO.HIGH)# 程序休眠3秒鐘,程序休眠期間,led燈會一直亮著time.sleep(3)# 設(shè)置11號口為低電壓,也就是11號口變?yōu)?伏,和GND一樣# 這行代碼執(zhí)行之后,11號口變?yōu)榈碗妷海敲锤鶕?jù)電路原理,led燈就會熄滅GPIO.output(11, GPIO.LOW)# 將所有的GPIO口狀態(tài)恢復(fù)為初始化,一般代碼結(jié)束都執(zhí)行此代碼,這是一個好習(xí)慣GPIO.cleanup()

保存文件為

led.py

,并運行之,看看 LED 燈是否亮3秒后熄滅。

sudo python led.py

最終效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容