1. 程式人生 > >樹莓派筆記12:通過SPI操作OLED顯示屏

樹莓派筆記12:通過SPI操作OLED顯示屏

樹莓派自帶SPI和I2C介面,因此可以方便地控制帶SPI的控制晶片的OLED顯示屏。要想成功實現樹莓派與oled的通訊,最好是買一個以SSD1306為主控晶片的oled,因為關於這個晶片的驅動庫是最容易搜到的,當然如果有能力自己寫驅動程式的話就無所謂了。這是我買的128X64,SPI介面的OLED模組,不到20塊。
這裡寫圖片描述
網上對樹莓派SPI操作OLED的大多數文章我猜應該是參考了這個連結裡的教程https://learn.adafruit.com/ssd1306-oled-displays-with-raspberry-pi-and-beaglebone-black?view=all,這是Adafruit公司專門為配合SSD1306的驅動庫寫的教程,按照該教程很快就能調通了。

1 關於SPI

SPI是序列外設介面(Serial Peripheral Interface)的簡寫,其實就是一種匯流排通訊協議,該匯流排以主從方式工作,通常是一個主裝置和一個或多個從裝置,一般需要4根線來進行資料通訊,即SDI(資料輸入)、SDO(資料輸出)、SCLK(時鐘)、CS(片選),相應的,有一套時序邏輯規定了通訊過程。一般使用SPI的裝置都配備了現成的SPI模組,只需要對相應的暫存器寫入指令就可以進行通訊了,如果沒有SPI介面,也可以軟體實現,就是根據時序圖手動操作GPIO來實現通訊,這就比較費勁了。

樹莓派已經帶了SPI介面,不過預設是關閉的。執行sudo raspi-config

進入配置頁,開啟SPI介面。
這裡寫圖片描述
然後有的教程裡說要把/etc/modprobe.d/raspi-blacklist.conf檔案裡的”blacklist spi-bcm2708”註釋掉,但是我的這個檔案是空的。重啟後,可以執行lsmod 檢視是否有spi模組存在;同時,在/dev下是否存在spidev0.0和spidev0.1兩個檔案,這兩個檔案代表了樹莓派SPI模組可以使能兩個SPI從裝置,也對應了GPIO上的CE0和CE1腳。

2 接線

把模組的引腳接到樹莓派的GPIO上, 需要注意這裡要分清GPIO引腳號是BCM編號還是實際編號。GND腳和樹莓派的GND連線;VCC接到3.3V腳;D0接到樹莓派的SCLK腳(第23號腳),即BCM.11腳;D1接到MOSI腳(第19號腳),即BCM.10;RES接到BCM.17腳,即第11號腳;DC接到BCM.22腳,即第15號腳;CS接到CE0腳(第24號腳)。總之,除了RES和DC是可以任意指定GPIO口,其他引腳是必須和樹莓派上的指定腳連線的。
這裡寫圖片描述

3 安裝相關庫

執行下面的更新核心並安裝基本環境,這個不是必須的,一般都已經裝好了:

sudo apt-get update
sudo apt-get install build-essential python-dev python-pip
sudo pip install RPi.GPIO

接著安裝python-imaging和python-smbus庫, Python Imaging Library庫包含了很多影象或圖形操作,它是Adafruit_Python_SSD1306驅動庫的所需要的基本模組;python-smbus不太清楚是什麼庫,網上搜索似乎是和I2C有關。

sudo apt-get install python-imaging python-smbus

最後,從Github上拷貝Adafruit_Python_SSD1306程式碼檔案,並安裝Adafruit_Python_SSD1306庫。

sudo apt-get install git
git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git
cd Adafruit_Python_SSD1306
sudo python setup.py install

下載原始檔的時候,可能會連不上GitHub,如果這樣就在自己電腦上到該網址下載zip檔案,用WinSCP複製到樹莓派,再用unzip命令解壓縮。

4 程式編寫

接下來就可以編寫Python程式來測試了。可以通過瀏覽上面連結裡的教程或者Adafruit_Python_SSD1306目錄下的examples熟悉操作oled的方法。大致的操作方法可以按下面的步驟:首先建立display物件,它代表了我們的oled模組;接著新建image物件,可以把它看成是一個畫板,與它相關聯的drawing物件則代表了具體的繪製情況,我們就是調動drawing的方法來構建要顯示的內容;然後讓display物件接收image物件,即把我們設定的繪圖資訊傳遞給oled;最後呼叫display()方法讓oled顯示出來。下面是我寫的測試程式:

import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
import Image
import ImageDraw
import ImageFont

# 引腳配置,按照上面的接線來配置
RST=17
DC=22
# 因為連的是CE0,這裡的PORT和DEVICE也設定為0
SPI_PORT=0
SPI_DEVICE=0

#根據自己的oled型號進行初始化,我的是128X64、SPI的oled,使用SSD1306_128_64初始化
disp=Adafruit_SSD1306.SSD1306_128_64(rst=RST,dc=DC,spi=SPI.SpiDev(SPI_PORT,SPI_DEVICE,max_speed_hz=8000000))

disp.begin()
disp.clear()
disp.display() #清屏

#image 1,繪製了幾個圖形
width=disp.width
height=disp.height
image1=Image.new('1',(width,height)) #新建一個128X64的二值影象物件
draw1=ImageDraw.Draw(image1) #獲取image1的draw物件

padding=1
shape_width=50
left=padding
top=padding
right=width-padding
bottom=height-padding
x=padding

draw1.rectangle((left,top,right,bottom),outline=1,fill=0) #畫矩形
draw1.ellipse((left+10,top+10,left+10+shape_width,top+10+shape_width),outline=1,fill=0) #畫橢圓
draw1.polygon([(right-20,top+10),(width/2+5,bottom-10),(right-5,bottom-10)],outline=1,fill=0) #畫三角

# image 2,載入一副圖片
image2=Image.open('testImage.jpg').resize((128,64)).convert('1')

# image 3,顯示一些文字
image3=Image.new('1',(width,height))
draw3=ImageDraw.Draw(image3)
font1=ImageFont.load_default()
font2=ImageFont.truetype('04B_30__.TTF',15)
font3=ImageFont.truetype('baby blocks.ttf',18)
draw3.text((0,0),'Hello',font=font1,fill=1)
draw3.text((0,15),'World!',font=font2,fill=1)
draw3.text((0,35),'Enjoy it!',font=font3,fill=1)

try:
    index=1
    while True: #迴圈顯示
        if index==1:
            disp.image(image1)
            index+=1
        elif index==2:
            disp.image(image2)
            index+=1
        else:
            disp.image(image3)
            index=1
        disp.display()
        time.sleep(2)
except:
    disp.clear()
    disp.display()

在上面的程式中,建立了3個image物件進行迴圈顯示。image1是呼叫了一些繪圖方法進行圖形繪製,例如rectangle方法,指定其左上角和右下角的座標,並指定邊框(outline)和內部(fill)顏色,因為oled模組只有兩種顏色(滅和亮),所以指定其顏色時也只需要指定1和0,大於1的值都是表示“1”的狀態。

image2是載入了一副圖片:
這裡寫圖片描述
圖片的格式無所謂,因為python-imaging庫能解析各種常用影象格式;大小也無所謂,因為在程式中可以用resize()方法調整到128X64;同時應使用convert()方法將原圖轉成二值圖(傳入”1”)。當然,選用的圖片不能複雜,否則在oled上只能顯示一堆零散的點。

image3顯示一些文字,這個呼叫text方法就可以了。如果想要一些特別的字型,可以去http://www.dafont.com/bitmap.php下載ttf檔案,放在程式檔案目錄下,使用ImageFont.truetype方法載入字型檔案,最後在text方法中指定字型。

5 測試結果

image1:
這裡寫圖片描述

image2:
這裡寫圖片描述

image3:
這裡寫圖片描述
我的oled有黃藍兩種顏色,是因為我買的oled上下兩部分本來顏色就不同。