一焕议、介紹
??本系統(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)原理
??我們可以在編程時(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 |
??第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é)果示例: