一起玩轉樹莓派(8)——樹莓派模數/數模轉換實踐(2)

一起玩轉樹莓派(8)——樹莓派模數/數模轉換實踐(2)

在上一篇博客中,我們介紹了在樹莓派中使用模數轉換芯片的基本方法,如果你對上一篇博文中介紹的內容已經有了深入的理解,那後面的應用試驗對你來說將非常容易。如果不是,那麼我建議你先將之前介紹的內容在研究一下:

https://my.oschina.net/u/2340880/blog/5142788

現在,如果你決定繼續本篇博客的學習,那麼我認爲你已經瞭解了PCF8591芯片的基本用法,明白了PCF8591的接線方式,I2C總線的基本工作原理以及PCF8591的設置命令的意義和讀數據的方法。

一、讀取外部傳感器的模擬信號

在本系列博客的上一篇文章中,我們通過讀取PCF8591實驗模塊自帶的可調節電壓輸出、光敏傳感器和熱敏傳感器實現了對當前環境信息的的讀取,除了可以讀取當前設置的輸出電壓外,我們還可以獲得當前的環境的溫度和亮度。PCF8591實驗模塊自帶的傳感器可以讓我們很方便的進行實驗,其實在實際應用中,更多時候我們需要從AIN0到AIN3引腳來獲取外接傳感器的模擬信號。現在,我們嘗試下通過AIN0和AIN1兩個輸入引腳來獲取外接光敏和熱敏傳感器的數據。

1.關於實驗所使用的傳感器

我們這裏的小實驗將使用光敏和熱敏傳感器。

光敏模塊

光敏傳感器能夠感應光纖的明暗變化,其實現此功能的核心在於光敏電阻,只做光敏電阻的常用材料有硫化鎘、硫化鋁等。這些材料在特定波長的光波照射下,其阻值會產生明顯的變化。本次實驗,我們使用的光敏傳感器模塊如下圖所示:

可以看到,此模塊的核心是一個光敏電阻,提供了可調節靈敏度的功能單元和兩個LED指示燈,其中一個LED是電源指示燈,接通電源後會亮,另一個LED燈是電平指示燈,當光亮達到閾值時,輸出引腳輸出低電平,此LED燈亮,當光亮度較暗時,輸出引腳輸出高電平,此LED燈不亮。我們再看此模塊的4個引腳:

VCC:電源引腳

GND:接地引腳

DO:數字信號輸出引腳(高低電平)

AO:模擬信號輸出引腳

熱敏模塊

本次實驗我們使用的熱敏模塊的功能與上面將的光敏模塊類似,如下圖所示:

此熱敏模塊同樣包含兩個LED指示燈、靈敏度調節單元和4個引腳,引腳如下:

VCC:電源引腳

GND:接地引腳

DO:數字信號輸出引腳(高低電平)

AO:模擬信號輸出引腳

2.實驗連線

本次實驗,我們使用PCF8591讀取光敏和熱敏傳感器的模擬信號,將其轉換成數字信號被樹莓派程序處理,同時,我們使用樹莓派的GPIO端口來讀取傳感器本身輸出的數字信號,首先,我們先確定要使用的PCF8591的輸入引腳和要使用的樹莓派GPIO引腳。

PCF8591輸入引腳使用:AINO和AIN1,其中AINO讀取光敏模擬信號,AIN1讀取熱敏模擬信號。

GPIO輸入引腳使用:GPIO17和GPIO18(BCM編碼方式),其中17引腳讀取光敏數字信號,18引腳讀取熱敏數字信號。

PCF8591連線:

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個元件,連線也複雜了很多,只要按照上面的表格,注意引腳的正確即可。

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:按鈕數字信號輸出引腳

操作杆內部實際上封裝了雙向的電阻器,其阻值會根據搖桿的方向變動產生變化,從而影響引腳信號的產生變化。

1.進行連線

我相信,現在連線對你來說應該是最簡單的工作了。操縱桿有模擬信號輸出同時也有數字信號輸出,我們依然需要結合PCF8591與樹莓派GPIO一起使用。關於PCF8591的接線上面有介紹,這裏不再重複。操作杆的接線方式如下:

操縱桿 樹莓派/PCF8591
GND 樹莓派GND
+5V 樹莓派5.5V
VRX PCF8591 AIN0
VRY PCF8591 AIN1
SW 樹莓派GPIO 11(物理引腳)

 2.編寫代碼

對於本實驗來說,有涉及到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的相關操作我們也非常熟悉了,我們通過註冊回調函數來監聽操作杆按鈕按下的行爲。

在樹莓派上運行上面的代碼,嘗試操作下,感受下使用操縱桿控制頁面元素的喜悅吧。

3.一點擴展

觀察上面的示例代碼,你會發現,我們使用了一些臨界值來作爲觸發方向動作的閾值,例如10,245這種,這是因爲PCF8591是8位的數模轉換模塊,即其轉換出的數字量在0-255之間(包括0和255),對於本實驗來說,我們並沒有讓搖桿元件傳輸的模擬量發揮正真的作用,想一下,你是否能夠根據操作杆的旋轉程度來調整圓球移動的速度呢?動手試試吧!

專注技術,懂的熱愛,願意分享,做個朋友

QQ:316045346

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章