[玩轉(zhuǎn)樹莓派] 0x05 GPIO GPIO

[TOC]

[玩轉(zhuǎn)樹莓派] GPIO GPIO

GPIO:General Purpose Input/Output pins on the Raspberry Pi

General purpose input/output; in this specific case the pins on the Raspberry Pi and what you can do with them. So called because you can use them for all sorts of purposes; most can be used as either inputs or outputs, depending on your program.

0x00 GPIO

有些事情堅持了,就做出來了,不堅持,就放棄了,就這么簡單。之前想寫個樹莓派的入門文章,一下子寫了幾篇之后,就停下來了。可能最近確是比較忙,或者,承認沒有嚴格要求自己,好吧,拖了這么久,今天,再寫一篇。

不管你信不信,樹莓派最吸引我的就是它的GPIO口。即使是現(xiàn)在,想到GPIO還是非常的興奮呢。為什么呢?對于通用計算機,我們能操作的基本都是USB、串口等一些接口。與這些接口相比,GPIO口有明顯的不同,我們可以直接操作一個IO口的狀態(tài):是高電平還是低電平。根據(jù)這個特性,我們就可以完成首次接觸單片機完成的小實驗:控制我們的LED燈,制作跑馬燈,模擬交通燈等等有趣的實驗。如果你想通過其他設(shè)備來完成這些操作,可能需要掌握其他對初學者來說比較困難的技術(shù)。另外,大學時期有玩過 89C51,對IO口還是戀戀不舍,曾經(jīng)想通過其產(chǎn)生PWM信號控制舵機,很遺憾沒實現(xiàn),現(xiàn)在正好可以完成這個心愿。

0x01 從一個LED說開去

這是一篇很基礎(chǔ)的文章,所以會比較通俗。首先我們通過LED的Demo來了解下什么是GPIO。先看一張原理圖:

LED Demo

這是一個非常簡單的電路:一個發(fā)光二極管、一個電阻(300Ω左右,忘記怎么算的了)、一個Rapsberry Pi。由于Rapsberry Pi GPIO口輸出電壓是3V3,所以我們串一個電阻來保護我們的LED。當我們通過代碼控制鏈接電阻的那個GPIO口狀態(tài)時,就可以使LED在亮和滅之間切換。

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

led = 23
GPIO.setup(led, GPIO.OUT)

try:
    while(True):
        GPIO.output(led, 1)
        time.sleep(1)
        GPIO.output(led, 0)
        time.sleep(1)
except Exception as e:
    print(e)
finally:
    GPIO.cleanup()

運行上面的代碼,我們就可以看到LED兩秒一個循環(huán)的亮滅。哈哈,是不是特有成就感,傳說中的點亮小燈泡終于實現(xiàn)了~~ 然并卵,這并沒有什么實際的用處。下面再介紹一個屌屌的demo,通過HC-SR501人體紅外傳感器檢測控制LED的亮滅,實際的例子的就是很多自動門,站在門下面的時候門會自動打開。 HC-SR501 它是長這個樣子滴:

hcsr501 1
hcsr501 2

(PS:以上圖片來自兩個淘寶賣家)

三個針腳:VCC、OUT、GND,另外還有一個是否連續(xù)監(jiān)測的針腳,連續(xù)時是H,不連續(xù)時是L,默認是H,看你買的具體設(shè)計了。另外還有兩個調(diào)節(jié)旋鈕,如上圖。其實這個傳感器特簡單,供電電壓5到20V,輸出0或者3V3兩個狀態(tài),不用與 Raspiberry Pi 連接,也可以直接當作開關(guān)使用。另外我還接了一個自鎖開關(guān),控制整個電路的開關(guān)。如下圖:

hcsr501 switcher

接著上源碼:

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

led = 25
GPIO.setup(led, GPIO.OUT)
swtich = 22
GPIO.setup(swtich, GPIO.IN, GPIO.PUD_UP)
hcsr501 = 23
GPIO.setup(hcsr501, GPIO.IN, GPIO.PUD_UP)

try:
    GPIO.output(led, 0)
    while(True):
        print(str(GPIO.input(swtich)) + '||' + str(GPIO.input(hcsr501)))
        if GPIO.input(swtich) == True:
            if GPIO.input(hcsr501) == True:
                GPIO.output(led, 1)
            else:
                GPIO.output(led, 0)
        else:
            GPIO.output(led, 0)

        time.sleep(1)
except Exception as e:
    print(e)
finally:
    GPIO.cleanup()

當我們把開關(guān)打開,經(jīng)過人體紅外傳感器的時候LED(這個地方我用的是3V3的高亮LED,所以沒有接電阻)就會亮。把這個東西放在房間里,晚上下班開門就可以自動開燈了。如果你有興趣,還可以把里面的開關(guān)換成一個光線傳感器,那樣就更完美了~~

運行上面的代碼,我們需要安裝 RPi.GPIO 庫,Raspbian 默認是安裝好了。簡單的瀏覽上面的代碼,我們可以發(fā)現(xiàn),首先設(shè)置 GPIO mode,這里設(shè)置為BCM;然后定義GPIO的狀態(tài),GPIO口我們可以定義兩種狀態(tài),GPIO.IN 和 GPIO.OUT,分別對應輸入和輸出;最后就是操作我們的GPIO口了。由于RPi.GPIO 庫已經(jīng)給我們封裝復雜的操作,所以我們用起來特別簡便。更多可 RPi.GPIO 信息可參考這里

0x02 Raspberry Pi的GPIO針腳

根據(jù)上面的demo程序,我們再來詳細的介紹下GPIO。

  • GPIO.setmode()

    指定針腳的編號方式,這里有兩種選擇:

    1. GPIO.BOARD

      使用針腳的物理順序來編號

    2. GPIO.BCM

      Broadcom SoC 的編碼方式

    具體的可參考下面這張圖,其中 Pin 列代表的是 GPIO.BOARD 方式的編碼, 而 NAME 列代表的是GPIO.BCM 方式的編碼。

      ![GPIO Pi3](http://upload-images.jianshu.io/upload_images/1801981-de0f86b2b6be0658.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  
    

    不同版本的 Raspberry Pi 會有不同的針腳分布,除查閱相關(guān)資料外,可以執(zhí)行下面命令查看:
    pi@raspberrypi:~ $ gpio readall

  • GPIO.setwarnings(True or False)

    當我們有多個腳本在操作同一個GPIO口時可能會出現(xiàn)警告,通過這個設(shè)置來選擇是否忽略

  • GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)

    設(shè)置GPIO口的狀態(tài),參數(shù)分別為:針腳序號、輸入還是輸出、初始狀態(tài)高電平還是低電平。

  • GPIO.input(channel)

    獲取指定GPIO口的狀態(tài)

  • GPIO.output(channel, GPIO.HIGH)

    操作GPIO口的輸出狀態(tài)

  • GPIO.cleanup()

    清除當前操作的所有GPIO口的狀態(tài),恢復為輸入狀態(tài)。好的做法是每次使用完都清除一下。

這就是一個簡單完整的使用 python 操作 GPIO的流程。雖然看到的現(xiàn)象,看到的代碼,但是你還會問:GPIO到底是個啥樣的東西,我們設(shè)置不同的狀態(tài)時它的電壓時怎樣的?它的驅(qū)動能力如何?什么樣的操作可能導致燒毀GPIO?

Raspberry Pi 2 Model B 使用了 BCM2836芯片,Raspberry Pi Model A, B, B+, Compute Module and Raspberry Pi Zero使用了BCM2835芯片,這里我們以BCM2835為例(作為一般使用者,可以不關(guān)心這個)。BCM2835有3個GPIO bank,這個3個bank都有自己的VDD,并且由3V3電壓提供支持。如果我們的輸入電壓超過3V3,就有可能燒毀SoC上的GPIO bank。由于我也是業(yè)余的,說的再專業(yè)我也聽不懂,因此簡單的來說,使用外部傳感器,它的輸入信號電壓是3V3的就沒問題。當然,傳感器的驅(qū)動電壓可以不是3V3。比如上面使用的 HC-SR501 它的驅(qū)動電壓是5V,輸入信號電壓是3V3,這樣接在外面的 Raspberry Pi 就完全沒問題,而且不需要額外電源為其供電,因為 Raspberry Pi 2 Model B 有兩個5V的針腳(就是右上角的兩個,2和4)。

更多的關(guān)于GPIO的上拉下拉懸浮等狀態(tài),可以參考這里的介紹。

0x03 GPIO進階

對于控制簡單的設(shè)備,比如LED,使用 RPi.GPIO 已經(jīng)夠用了。但是當我們進一步研究之后會發(fā)現(xiàn)RPi.GPIO并不是那么完美,在它的官方文檔上有這么兩段話:

Note that this module is unsuitable for real-time or timing critical applications. This is because you can not predict when Python will be busy garbage collecting. It also runs under the Linux kernel which is not suitable for real time applications - it is multitasking O/S and another process may be given priority over the CPU, causing jitter in your program. If you are after true real-time performance and predictability, buy yourself an Arduino http://www.arduino.cc !
Note that the current release does not support SPI, I2C, hardware PWM or serial functionality on the RPi yet. This is planned for the near future - watch this space! One-wire functionality is also planned.

從上面我們可以了解到 RPi.GPIO 并不適合實時性要求高的應用,也不適合周期計數(shù)的應用。python本身性能就不是非常理想,比如當我們嘗試用python去操作DHT11(溫濕度傳感器)就非常的困難,因為很難和它的時序保持同步。而且linux并不是實時操作系統(tǒng),運行在linux內(nèi)核之上,無法避免被其他進程搶占CPU。目前版本的 RPi.GPIO 并不支持SPI、I2C、硬件PWM、串口等。如果你希望使用這些接口,那就需要考慮換一個庫或者換一種語言了。具體的是用,在以后的文章中會做介紹。

Create by ttdevs
Create by ttdevs

參考:

https://github.com/raspberrypi/documentation
https://zh.scribd.com/doc/101830961/GPIO-Pads-Control2
https://pypi.python.org/pypi/RPi.GPIO
http://dreamcolor.net/archives/rpi-gpio-module-pwm.html

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

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