樹莓派綜合項(xiàng)目1:智能溫度測量系統(tǒng)實(shí)驗(yàn)

一焕议、介紹

??本系統(tǒng)中,將使用常見的幾種模塊來構(gòu)建一個(gè)簡單的智能溫度測量系統(tǒng)邪驮。

二候味、組件

★Raspberry Pi 3主板*1

★樹莓派電源*1

★40P軟排線*1

★有源蜂鳴器模塊*1

★RGB LED 模塊*1

★DS18B20 溫度傳感器模塊*1

★PCF8591 AD/DA轉(zhuǎn)換模塊*1

★PS2 操作手柄模塊*1

★面包板*1

★跳線若干

三、實(shí)驗(yàn)原理

RGB LED模塊
有源蜂鳴器模塊
PCF8591數(shù)模轉(zhuǎn)換模塊
PS2操縱桿
DS18B20溫度傳感器

??我們可以在編程時(shí)通過操縱桿PS2調(diào)整下限和上限值洪灯。操縱桿PS2有五個(gè)操作方向:向上坎缭、向下、向左签钩、向右和向下按壓掏呼。在這個(gè)項(xiàng)目中,我們將使用左右方向來控制上限值铅檩,上下方向來控制下限值憎夷。如果按一下操縱桿,系統(tǒng)將退出柠并。

??當(dāng)實(shí)際溫度值在下限和上限值之間時(shí)岭接,LED燈顯綠色,蜂鳴器無響聲臼予;當(dāng)實(shí)際溫度值超下限時(shí)鸣戴,LED燈顯藍(lán)色,蜂鳴器蜂鳴3次粘拾,每次0.5秒窄锅;當(dāng)實(shí)際溫度值超上限時(shí),LED燈顯紅色缰雇,蜂鳴器蜂鳴3次入偷,每次0.1秒。

每個(gè)模塊的詳情資料請參考前面的文章:
樹莓派基礎(chǔ)實(shí)驗(yàn)2:RGB-LED實(shí)驗(yàn)
樹莓派基礎(chǔ)實(shí)驗(yàn)9:蜂鳴器實(shí)驗(yàn)
樹莓派基礎(chǔ)實(shí)驗(yàn)12:PCF8591模數(shù)轉(zhuǎn)換器實(shí)驗(yàn)
樹莓派基礎(chǔ)實(shí)驗(yàn)14:PS2操縱桿實(shí)驗(yàn)
樹莓派基礎(chǔ)實(shí)驗(yàn)25:DS18B20溫度傳感器實(shí)驗(yàn)

四械哟、實(shí)驗(yàn)步驟

??第1步: 連接電路疏之。

樹莓派 T型轉(zhuǎn)接板 DS18B20溫度傳感器
GPIO7 G4 SIG
5V 5V VCC
GND GND GND
樹莓派 T型轉(zhuǎn)接板 PCF8591數(shù)模轉(zhuǎn)換模塊
SDA SDA SDA
SCL SCL SCL
5V 5V VCC
GND GND GND
PS2操縱桿 T型轉(zhuǎn)接板 PCF8591數(shù)模轉(zhuǎn)換模塊
Y * AIN0
X * AIN1
SW(按鈕) * AIN2
VCC 5V *
GND GND *
樹莓派 T型轉(zhuǎn)接板 RGB LED模塊
GPIO0 G17 R
GPIO1 G18 G
GPIO2 G27 B
GND GND GND
樹莓派 T型轉(zhuǎn)接板 有源蜂鳴器模塊
GPIO3 G22 SIG
3.3V 3.3V VCC
GND GND GND
智能溫度測量系統(tǒng)電路圖
智能溫度測量系統(tǒng)實(shí)物接線圖

??第2步: RGB LED模塊程序。

#!/usr/bin/env python   #告訴Linux本文件是一個(gè)Python程序
import RPi.GPIO as GPIO    #導(dǎo)入控制GPIO的模塊暇咆,RPi.GPIO
import time     #導(dǎo)入時(shí)間模塊锋爪,提供延時(shí)、時(shí)鐘和其它時(shí)間函數(shù)

colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF] #顏色列表
R = 11        #定義物理針腳號(hào)
G = 12
B = 13

def setup(Rpin, Gpin, Bpin):
    global pins   #在函數(shù)內(nèi)部聲明被其修飾的變量是全局變量
    global p_R, p_G, p_B
    pins = {'pin_R': Rpin, 'pin_G': Gpin, 'pin_B': Bpin}
    GPIO.setmode(GPIO.BOARD)      #設(shè)置引腳編號(hào)模式為板載模式爸业,即樹莓派上的物理位置編號(hào)
    for i in pins:
        GPIO.setup(pins[i], GPIO.OUT)    # 設(shè)置針腳模式為輸出(或者輸入GPIO.IN)
        GPIO.output(pins[i], GPIO.LOW) # Set pins to low(0 V) to off led
    
    p_R = GPIO.PWM(pins['pin_R'], 2000)  # set Frequece to 2KHz
    p_G = GPIO.PWM(pins['pin_G'], 1999)
    p_B = GPIO.PWM(pins['pin_B'], 5000)
    
    p_R.start(0)      # Initial duty Cycle = 0(leds off)
    p_G.start(0)
    p_B.start(0)

def map(x, in_min, in_max, out_min, out_max): #將顏色的刺激量轉(zhuǎn)換為占空比對(duì)應(yīng)的值其骄。
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def off():
    for i in pins:
        GPIO.output(pins[i], GPIO.LOW)    # Turn off all leds

def setColor(col):   # For example : col = 0x112233
    R_val = (col & 0xff0000) >> 16   #先“與”運(yùn)算只保留自己顏色所在位的值有效
    G_val = (col & 0x00ff00) >> 8    #再“右移”運(yùn)算將自己顏色所在位的值提取出來
    B_val = (col & 0x0000ff) >> 0

    R_val = map(R_val, 0, 255, 0, 100)  #將顏色的刺激量轉(zhuǎn)換為占空比對(duì)應(yīng)的值
    G_val = map(G_val, 0, 255, 0, 100)
    B_val = map(B_val, 0, 255, 0, 100)
    
    p_R.ChangeDutyCycle(R_val)     # 更改占空比,調(diào)整該顏色的亮度
    p_G.ChangeDutyCycle(G_val)
    p_B.ChangeDutyCycle(B_val)

def loop():
    while True:
        for col in colors:
            setColor(col)
            time.sleep(1)

def destroy():
    p_R.stop()      #Turn off PWM
    p_G.stop()
    p_B.stop()
    off()              # Turn off all leds
    GPIO.cleanup()     #重置GPIO狀態(tài)

if __name__ == "__main__":
    try:                       #用try-except代碼塊來處理可能引發(fā)的異常
        setup(R, G, B)      #調(diào)用初始化設(shè)置LED燈的函數(shù)
        loop()                     #調(diào)用循環(huán)函數(shù)
    except KeyboardInterrupt:      #如果遇用戶中斷(control+C)扯旷,則執(zhí)行destroy()函數(shù)
        destroy()             #調(diào)用清除LED狀態(tài)的函數(shù)

??第3步: 有源蜂鳴器模塊程序拯爽。

#!/usr/bin/env python
import RPi.GPIO as GPIO
import time

Buzzer = 11    # pin11

def setup(pin):
    global BuzzerPin
    BuzzerPin = pin
    GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
    GPIO.setup(BuzzerPin, GPIO.OUT)
    GPIO.output(BuzzerPin, GPIO.HIGH)

def on():
    GPIO.output(BuzzerPin, GPIO.LOW)    
    #低電平是響
def off():
    GPIO.output(BuzzerPin, GPIO.HIGH)
    #高電平是停止響
def beep(x):    #響3秒后停止3秒
    on()
    time.sleep(x)
    off()
    time.sleep(x)

def loop():
    while True:
        beep(3)

def destroy():
    GPIO.output(BuzzerPin, GPIO.HIGH)
    GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
    setup(Buzzer)
    try:
        loop()
    except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
        destroy()

??第4步: PCF8591數(shù)模轉(zhuǎn)換模塊程序。

#!/usr/bin/env python
#------------------------------------------------------
#
#       您可以使用下面語句將此腳本導(dǎo)入另一個(gè)腳本:
#           “import PCF8591 as ADC”                
#   
#   ADC.Setup(Address)  # 查詢PCF8591的地址:“sudo i2cdetect -y 1”
# i2cdetect  is  a  userspace  program to scan an I2C bus for devices.
# It outputs a table with the list of detected devices on the specified bus.
#   ADC.read(channal)   # Channal范圍從0到3 
#   ADC.write(Value)    # Value范圍從0到255
#
#------------------------------------------------------
#SMBus (System Management Bus,系統(tǒng)管理總線) 
import smbus   #在程序中導(dǎo)入“smbus”模塊
import time

# for RPI version 1, use "bus = smbus.SMBus(1)"
# 0 代表 /dev/i2c-0钧忽, 1 代表 /dev/i2c-1 ,具體看使用的樹莓派那個(gè)I2C來決定
bus = smbus.SMBus(1)         #創(chuàng)建一個(gè)smbus實(shí)例

#在樹莓派上查詢PCF8591的地址:“sudo i2cdetect -y 1”
def setup(Addr):
    global address
    address = Addr

def read(chn): #channel
    if chn == 0:
        bus.write_byte(address,0x40)   #發(fā)送一個(gè)控制字節(jié)到設(shè)備
    if chn == 1:
        bus.write_byte(address,0x41)
    if chn == 2:
        bus.write_byte(address,0x42)
    if chn == 3:
        bus.write_byte(address,0x43)
    bus.read_byte(address)         # 從設(shè)備讀取單個(gè)字節(jié)毯炮,而不指定設(shè)備寄存器逼肯。
    return bus.read_byte(address)  #返回某通道輸入的模擬值A(chǔ)/D轉(zhuǎn)換后的數(shù)字值

def write(val):
    temp = val  # 將字符串值移動(dòng)到temp
    temp = int(temp) # 將字符串改為整數(shù)類型
    # print temp to see on terminal else comment out
    bus.write_byte_data(address, 0x40, temp) 
    #寫入字節(jié)數(shù)據(jù),將數(shù)字值轉(zhuǎn)化成模擬值從AOUT輸出

if __name__ == "__main__":
    setup(0x48) 
 #在樹莓派終端上使用命令“sudo i2cdetect -y 1”否副,查詢出PCF8591的地址為0x48
    while True:
        print '電位計(jì)   AIN0 = ', read(0)   #電位計(jì)模擬信號(hào)轉(zhuǎn)化的數(shù)字值
        print '光敏電阻 AIN1 = ', read(1)   #光敏電阻模擬信號(hào)轉(zhuǎn)化的數(shù)字
        print '熱敏電阻 AIN2 = ', read(2)   #熱敏電阻模擬信號(hào)轉(zhuǎn)化的數(shù)字值
        tmp = read(0)
        tmp = tmp*(255-125)/255+125 
# 125以下LED不會(huì)亮汉矿,所以將“0-255”轉(zhuǎn)換為“125-255”,調(diào)節(jié)亮度時(shí)燈不會(huì)熄滅
        write(tmp)
        time.sleep(2)

??第5步: PS2操縱桿程序备禀。

#!/usr/bin/env python
import PCF8591 as ADC 
import time

def setup():
    ADC.setup(0x48)                 # Setup PCF8591
    global state

def direction():    #獲取操縱桿方向結(jié)果
    state = ['home', 'up', 'down', 'left', 'right', 'Button pressed']
    i = 0

    if ADC.read(0) <= 5:
        i = 1       #up
    if ADC.read(0) >= 250:
        i = 2       #down

    if ADC.read(1) <= 5:
        i = 3       #left
    if ADC.read(1) >= 250:
        i = 4       #right


    if ADC.read(1) >= 6 \  #由于未知原因洲拇,向左搖操縱桿會(huì)自動(dòng)觸發(fā)按鍵按下信號(hào)
    and ADC.read(2) == 0:  #所以加上ADC.read(1) >= 6這個(gè)限制,
        i = 5       # Button pressed

    if  ADC.read(0) - 125 < 15   \
    and ADC.read(0) - 125 > -15  \
    and ADC.read(1) - 125 < 15   \
    and ADC.read(1) - 125 > -15  \
    and ADC.read(2) == 255:
        i = 0         #home
    
    return state[i]

def loop():
    status = ''
    while True:
        tmp = direction()
        if tmp != None and tmp != status:
            print tmp     #不為空和tmp值變化時(shí)打印
            status = tmp

def destroy():
    pass      #pass語句就是空語句

if __name__ == '__main__':      # Program start from here
    setup()
    try:
        loop()
    except KeyboardInterrupt:   # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
        destroy()

??第6步: DS18B20溫度傳感器模塊程序曲尸。

#!/usr/bin/env python
#----------------------------------------------------------------
#   Note:
#       ds18b20's data pin must be connected to pin7.
#       replace the 28-XXXXXXXXX as yours.
#----------------------------------------------------------------
import os  #導(dǎo)入操作系統(tǒng)的庫os

ds18b20 = ''

def setup():
    global ds18b20
    for i in os.listdir('/sys/bus/w1/devices'):
    #os.listdir(path) 返回path指定的文件夾包含的文件或文件夾的名字的列表
    
        if i != 'w1_bus_master1':
    #里面除了文件'w1_bus_master1'赋续,另外一個(gè)就是溫度數(shù)據(jù)文件所在的文件夾
    
            ds18b20 = i   
    #將溫度數(shù)據(jù)文件所在的文件夾名賦值給全局變量ds18b20

def read():

    location = '/sys/bus/w1/devices/' + ds18b20 + '/w1_slave'
    #location是溫度數(shù)據(jù)文件的地址
    
    tfile = open(location)  
    #os.open(file, flags[, mode])打開一個(gè)文件
    text = tfile.read()     
    #  os.read(fd, n)從文件描述符 fd 中讀取最多 n 個(gè)字節(jié),返回包含
    #  讀取字節(jié)的字符串另患,文件描述符 fd對(duì)應(yīng)文件已達(dá)到結(jié)尾, 返回一個(gè)空字符串纽乱。
    
    tfile.close()
    #os.close(fd)關(guān)閉文件描述符 fd
    
    secondline = text.split("\n")[1]
    #   string.split(str="", num=string.count(str))
    #   以 str 為分隔符切片 string,如果 num 有指定值昆箕,則僅分隔 num+ 個(gè)子字符串
    #計(jì)算機(jī)里序號(hào)是從0開始計(jì)算鸦列,取1即是第二行
    
    temperaturedata = secondline.split(" ")[9]
    #以空格為分隔符,取序號(hào)為9的字符段鹏倘,如:t=17375
    
    temperature = float(temperaturedata[2:])
    #取字符串(如:t=17375)第2位及以后部分薯嗤,即數(shù)字部分17375
    
    temperature = temperature / 1000
    return temperature
    
def loop():
    while True:
        if read() != None:
            print "Current temperature : %0.3f C" % read()
           #以單精度浮點(diǎn)小數(shù)的形式輸出,保留三位小數(shù)
def destroy():
    pass

if __name__ == '__main__':
    try:
        setup()
        loop()
    except KeyboardInterrupt:
        destroy()


??第7步: 智能溫度測量系統(tǒng)總控制程序纤泵。當(dāng)實(shí)際溫度值在下限和上限值之間時(shí)骆姐,LED燈顯綠色,蜂鳴器無響聲捏题;當(dāng)實(shí)際溫度值超下限時(shí)玻褪,LED燈顯藍(lán)色,蜂鳴器蜂鳴3次公荧,每次0.5秒带射;當(dāng)實(shí)際溫度值超上限時(shí),LED燈顯紅色循狰,蜂鳴器蜂鳴3次庸诱,每次0.1秒。

#!/usr/bin/env python
import RPi.GPIO as  GPIO
import importlib #動(dòng)態(tài)加載某個(gè)模塊
import time
import sys

# 重新定義部分針腳位置
LedR    =   11
LedG    =   12
LedB    =   13
Buzz    =   15

#ds18b20 = '28-031467805fff'
#location = '/sys/bus/w1/devices/' + ds18b20 + '/w1_slave'

#導(dǎo)入模塊
joystick    =   importlib.import_module('15_joystick_PS2')
ds18b20     =   importlib.import_module('26_ds18b20')
beep        =   importlib.import_module('10_active_buzzer')
rgb         =   importlib.import_module('02_rgb_led')

#調(diào)用各個(gè)模塊中的初始化函數(shù)
joystick.setup()
ds18b20.setup()
beep.setup(Buzz)
rgb.setup(LedR, LedG, LedB)

color = {'Red':0xFF0000, 'Green':0x00FF00, 'Blue':0x0000FF}

def setup():
"""初始化下限和上限值"""
    global lowl, highl
    lowl = 29
    highl = 31

def edge():
"""根據(jù)搖桿方向的值設(shè)置上下限的值及退出"""
    global lowl, highl
    temp = joystick.direction()
    if temp == 'Button pressed': #當(dāng)按下?lián)u桿時(shí)晤揣,程序退出
        destroy()
        quit()
    if temp == 'up' and highl <= 125: #上限值不超過125
        highl += 1
    if temp == 'down' and lowl < highl-1: #保證上限值不能<=下限值
        highl -= 1
    if temp == 'right' and lowl < highl-1: #保證上限值不能<=下限值
        lowl += 1
    if temp == 'left' and lowl >= -5: #下限值不低于-5
        lowl -= 1

def loop():
    while True:
        edge()
        temp = ds18b20.read()
        print 'The lower limit of temperature : ', lowl
        print 'The upper limit of temperature : ', highl
        print 'Current temperature : ', temp
        print ''
        if float(temp) < float(lowl):
            rgb.setColor(color['Blue']) #溫度超下限時(shí)LED燈顯藍(lán)色
            for i in range(0, 3):
                beep.beep(0.5) #蜂鳴3次,每次0.5秒
        if temp >= float(lowl) and temp < float(highl):
            rgb.setColor(color['Green']) #溫度不超限時(shí)LED燈顯綠色
        if temp >= float(highl):
            rgb.setColor(color['Red']) #溫度超上限時(shí)LED燈顯紅色
            for i in range(0, 3):
                beep.beep(0.1) #蜂鳴3次朱灿,每次0.1秒

def destroy():
    beep.destroy()
    joystick.destroy()
    ds18b20.destroy()
    rgb.destroy()
    GPIO.cleanup()

if __name__ == "__main__":
    try:
        setup()
        loop()
    except KeyboardInterrupt:
        destroy()

??實(shí)驗(yàn)結(jié)果示例:


實(shí)驗(yàn)結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昧识,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盗扒,更是在濱河造成了極大的恐慌跪楞,老刑警劉巖缀去,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異甸祭,居然都是意外死亡缕碎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門池户,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咏雌,“玉大人,你說我怎么就攤上這事校焦∩薅叮” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵寨典,是天一觀的道長氛雪。 經(jīng)常有香客問我,道長耸成,這世上最難降的妖魔是什么报亩? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮井氢,結(jié)果婚禮上弦追,老公的妹妹穿的比我還像新娘。我一直安慰自己毙沾,他們只是感情好骗卜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著左胞,像睡著了一般寇仓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烤宙,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天遍烦,我揣著相機(jī)與錄音,去河邊找鬼躺枕。 笑死服猪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拐云。 我是一名探鬼主播罢猪,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼叉瘩!你這毒婦竟也來了膳帕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤薇缅,失蹤者是張志新(化名)和其女友劉穎危彩,沒想到半個(gè)月后攒磨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汤徽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年娩缰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谒府。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拼坎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狱掂,到底是詐尸還是另有隱情演痒,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布趋惨,位于F島的核電站鸟顺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏器虾。R本人自食惡果不足惜讯嫂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兆沙。 院中可真熱鬧欧芽,春花似錦、人聲如沸葛圃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽库正。三九已至曲楚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間褥符,已是汗流浹背龙誊。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喷楣,地道東北人趟大。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像铣焊,于是被迫代替她去往敵國和親逊朽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354