在上一篇博客中,咱們介紹了在樹莓派中使用模數轉換芯片的基本方法,若是你對上一篇博文中介紹的內容已經有了深刻的理解,那後面的應用試驗對你來講將很是容易。若是不是,那麼我建議你先將以前介紹的內容在研究一下:python
https://blog.51cto.com/u_11643026/3180290canvas
如今,若是你決定繼續本篇博客的學習,那麼我認爲你已經瞭解了PCF8591芯片的基本用法,明白了PCF8591的接線方式,I2C總線的基本工做原理以及PCF8591的設置命令的意義和讀數據的方法。markdown
在本系列博客的上一篇文章中,咱們經過讀取PCF8591實驗模塊自帶的可調節電壓輸出、光敏傳感器和熱敏傳感器實現了對當前環境信息的的讀取,除了能夠讀取當前設置的輸出電壓外,咱們還能夠得到當前的環境的溫度和亮度。PCF8591實驗模塊自帶的傳感器可讓咱們很方便的進行實驗,其實在實際應用中,更多時候咱們須要從AIN0到AIN3引腳來獲取外接傳感器的模擬信號。如今,咱們嘗試下經過AIN0和AIN1兩個輸入引腳來獲取外接光敏和熱敏傳感器的數據。ide
咱們這裏的小實驗將使用光敏和熱敏傳感器。函數
光敏傳感器可以感應光纖的明暗變化,其實現此功能的核心在於光敏電阻,只作光敏電阻的經常使用材料有硫化鎘、硫化鋁等。這些材料在特定波長的光波照射下,其阻值會產生明顯的變化。本次實驗,咱們使用的光敏傳感器模塊以下圖所示:oop
能夠看到,此模塊的核心是一個光敏電阻,提供了可調節靈敏度的功能單元和兩個LED指示燈,其中一個LED是電源指示燈,接通電源後會亮,另外一個LED燈是電平指示燈,當光亮達到閾值時,輸出引腳輸出低電平,此LED燈亮,當光亮度較暗時,輸出引腳輸出高電平,此LED燈不亮。咱們再看此模塊的4個引腳:學習
VCC:電源引腳編碼
GND:接地引腳3d
DO:數字信號輸出引腳(高低電平)code
AO:模擬信號輸出引腳
本次實驗咱們使用的熱敏模塊的功能與上面將的光敏模塊相似,以下圖所示:
此熱敏模塊一樣包含兩個LED指示燈、靈敏度調節單元和4個引腳,引腳以下:
VCC:電源引腳
GND:接地引腳
DO:數字信號輸出引腳(高低電平)
AO:模擬信號輸出引腳
本次實驗,咱們使用PCF8591讀取光敏和熱敏傳感器的模擬信號,將其轉換成數字信號被樹莓派程序處理,同時,咱們使用樹莓派的GPIO端口來讀取傳感器自己輸出的數字信號,首先,咱們先肯定要使用的PCF8591的輸入引腳和要使用的樹莓派GPIO引腳。
PCF8591輸入引腳使用:AINO和AIN1,其中AINO讀取光敏模擬信號,AIN1讀取熱敏模擬信號。
GPIO輸入引腳使用:GPIO17和GPIO18(BCM編碼方式),其中17引腳讀取光敏數字信號,18引腳讀取熱敏數字信號。
PCF8591 | 樹莓派功能引腳 |
---|---|
SCL | SCL |
SDA | SDA |
GND | GND |
VCC | 5V |
光敏傳感器 | 樹莓派/PCF8591 |
---|---|
VCC | 樹莓派3.3V |
GND | 樹莓派GND |
DO | 樹莓派GPIO11(物理引腳) |
AO | PCF8591 AIN0 |
熱敏傳感器 | 樹莓派/PCF8591 |
---|---|
VCC | 樹莓派3.3V |
--- | --- |
GND | 樹莓派GND |
--- | --- |
DO | 樹莓派GPIO12(物理引腳) |
--- | --- |
AO | PCF8591 AIN1 |
--- | --- |
連線最終以下圖所示:
和以前相比,咱們此次直接在樹莓派上鍊接了3個元件,連線也複雜了不少,只要按照上面的表格,注意引腳的正確便可。
步入正題,先上代碼:
#coding:utf-8 #SMBus (System Management Bus,系統管理總線) import smbus #在程序中導入「smbus」模塊 import RPi.GPIO as GPIO import time bus = smbus.SMBus(1) #建立一個smbus實例 # 經過PCF8591讀取模擬信號 # 數據亮度的模擬數據 def readLight(): #發送一個控制字節到設備 表示要讀取AIN0通道的數據 bus.write_byte(0x48,0x40) bus.read_byte(0x48) # 空讀一次,消費掉無效數據 return bus.read_byte(0x48) # 返回某通道輸入的模擬值A/D轉換後的數字值 def readTemperature(): #發送一個控制字節到設備 表示要讀取AIN1通道的數據 bus.write_byte(0x48,0x41) bus.read_byte(0x48) # 空讀一次,消費掉無效數據 return bus.read_byte(0x48) # 返回某通道輸入的模擬值A/D轉換後的數字值 # 經過GPIO讀取數字信號 # 設置使用的引腳編碼模式 GPIO.setmode(GPIO.BOARD) # 光敏模塊的數字輸出引腳 BCM 17 LP = 11 # 熱敏模塊的數字輸出引腳 BCM 18 TP = 12 # 引腳初始化 GPIO.setup(LP, GPIO.IN) GPIO.setup(TP, GPIO.IN) while True: print('--------分割線----------') print('亮度數字信號:', GPIO.input(LP)) print('亮度模擬信號:', readLight()) print('溫度數字信號:', GPIO.input(TP)) print('溫度模擬信號:', readTemperature()) time.sleep(2)
上面的代碼有着比較詳盡的註釋,這裏咱們無需多說,在樹莓派上運行此代碼,便可觀察到控制檯的數據輸出。
若是你順利完成了上面的實驗,先別急着慶祝,你會發現,和本系列前面幾篇博客的內容較比,到目前爲止咱們並無介紹新的知識,同時也沒有作什麼新穎的事情。的確如此,可是經過上面實驗的練習,能夠幫助你更深刻的理解數模/模數轉換的應用場景,而且讓你可以更加靈活的對I2C總線與通用GPIO串口結合進行使用。下面咱們要來作一些好玩的事情了,不知道你小時候是否有玩過「大把機」,這是一種搖桿遊戲機,搖桿能夠朝上下左右4個方向轉動,也能夠從中間按下。一般,上下左右用來控制遊戲人物的行動方向,按下用來進行人物跳躍。如今,咱們要來作一個簡單的遊戲,爲樹莓派鏈接操縱桿,控制遊戲程序頁面上圓球的行爲,其中方向控制圓球的移動,按下操縱桿則使圓球變色。
此實驗所使用的操縱桿以下圖所示:
能夠看到,此元件有5個引腳:
GND:接地引腳
+5V:5V電源引腳
VRX:橫向座標模擬信號輸出引腳
VRY:縱向座標模擬信號輸出引腳
SW:按鈕數字信號輸出引腳
操做杆內部實際上封裝了雙向的電阻器,其阻值會根據搖桿的方向變更產生變化,從而影響引腳信號的產生變化。
我相信,如今連線對你來講應該是最簡單的工做了。操縱桿有模擬信號輸出同時也有數字信號輸出,咱們依然須要結合PCF8591與樹莓派GPIO一塊兒使用。關於PCF8591的接線上面有介紹,這裏再也不重複。操做杆的接線方式以下:
操縱桿 | 樹莓派/PCF8591 |
---|---|
GND | 樹莓派GND |
+5V | 樹莓派5.5V |
VRX | PCF8591 AIN0 |
VRY | PCF8591 AIN1 |
SW | 樹莓派GPIO 11(物理引腳) |
對於本實驗來講,有涉及到UI開發,咱們依然採用Python自帶的Tkinter庫,其有很好的移植性,而且其提供了Canvas畫布,咱們能夠靈活的渲染所須要的圖形。示例代碼以下:
#coding:utf-8 # 導入UI模塊 import tkinter as Tkinter #SMBus (System Management Bus,系統管理總線) import smbus #在程序中導入「smbus」模塊 import RPi.GPIO as GPIO # 導入樹莓派GPIO模塊 import time # 導入定時器模塊 import threading # 主頁面設置 top = Tkinter.Tk() top.geometry('500x300') top.title("操縱桿控制圓球") # 當前圓球的座標 currentX = 0 currentY = 0 # 當前圓球的顏色是否紅色 currentColor = True # 進行窗口的初始化 canvas = Tkinter.Canvas(top, width=500, height=300, borderwidth=0, highlightthickness=0) canvas.grid() # 進化畫布的初始化 circle = canvas.create_oval(currentX, currentY, 100, 100, fill="red", outline="") # 定義移動圓球的方法 def moveCircle(c, x, y): global currentX, currentY moveX = x moveY = y if x >= 0: if x + currentX > 400: moveX = 400 - currentX currentX = 400 else: currentX += x else: if x + currentX < 0: moveX = -currentX currentX = 0 else: currentX += x if y >= 0: if y + currentY > 200: moveY = 200 - currentY currentY = 200 else: currentY += y else: if y + currentY < 0: moveY = -currentY currentY = 0 else: currentY += y canvas.move(c, moveX, moveY) # 定義改變圓球顏色的方法 def changeColor(c): global currentColor canvas.itemconfig(c, fill= 'red' if currentColor else 'blue') currentColor = not currentColor bus = smbus.SMBus(1) #建立一個smbus實例 # 經過PCF8591讀取模擬信號 # 搖桿X引腳的模擬數據 def readX(): #發送一個控制字節到設備 表示要讀取AIN0通道的數據 bus.write_byte(0x48,0x40) bus.read_byte(0x48) # 空讀一次,消費掉無效數據 return bus.read_byte(0x48) # 返回某通道輸入的模擬值A/D轉換後的數字值 # 搖桿Y引腳的模擬數據 def readY(): #發送一個控制字節到設備 表示要讀取AIN1通道的數據 bus.write_byte(0x48,0x41) bus.read_byte(0x48) # 空讀一次,消費掉無效數據 return bus.read_byte(0x48) # 返回某通道輸入的模擬值A/D轉換後的數字值 # 經過GPIO讀取數字信號 # 設置使用的引腳編碼模式 GPIO.setmode(GPIO.BOARD) # 按鍵使用引腳 BCM 17 BTN = 11 # 引腳初始化 設置下拉高電平 GPIO.setup(BTN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # 建立定時器函數,用來檢查搖桿動做 def fun_timer(): global timer x = readX() y = readY() press = GPIO.input(BTN) print('X:', x) print('Y:', y) print('按鈕:', press) if x <= 10: moveCircle(circle, -10, 0) if x >= 245: moveCircle(circle, 10, 0) if y <= 10: moveCircle(circle, 0, -10) if y >= 245: moveCircle(circle, 0, 10) timer = threading.Timer(0.2, fun_timer) timer.start() timer = threading.Timer(0.2, fun_timer) timer.start() # 定義GPIO輸入端口的回調 def btnCallback(channel): if not GPIO.input(channel): changeColor(circle) # 添加輸入引腳電平變化的回調函數 GPIO.add_event_detect(BTN, GPIO.FALLING, callback=btnCallback, bouncetime=200) top.mainloop()
上面的代碼有些長,可是有詳盡的註釋,關於UI開發方面的內容不是咱們本系列博客的重點,這裏咱們不作過多介紹。moveCircle函數是核心的圓球移動函數,內部經過邊界斷定邏輯能夠確保圓球不會移動到視圖界面外。changeColor方法用來修改圓球的顏色,這裏咱們讓每次按鍵後在紅綠顏色間進行切換。readX和readY函數咱們無需作過多介紹了,其經過PCF8591的AIN0和AIN1來傳輸搖桿的橫縱座標信號。GPIO的相關操做咱們也很是熟悉了,咱們經過註冊回調函數來監聽操做杆按鈕按下的行爲。
在樹莓派上運行上面的代碼,嘗試操做下,感覺下使用操縱桿控制頁面元素的喜悅吧。
觀察上面的示例代碼,你會發現,咱們使用了一些臨界值來做爲觸發方向動做的閾值,例如10,245這種,這是由於PCF8591是8位的數模轉換模塊,即其轉換出的數字量在0-255之間(包括0和255),對於本實驗來講,咱們並無讓搖桿元件傳輸的模擬量發揮正真的做用,想一下,你是否可以根據操做杆的旋轉程度來調整圓球移動的速度呢?動手試試吧!
專一技術,懂的熱愛,願意分享,作個朋友
QQ:316045346