树莓派综合项目1:智能温度测量系统实验
一、介绍
本系统中,将使用常见的几种模块来构建一个简单的智能温度测量系统。
二、组件
★Raspberry Pi 3主板*1
★树莓派电源*1
★40P软排线*1
★有源蜂鸣器模块*1
★RGB LED 模块*1
★DS18B20 温度传感器模块*1
★PCF8591 AD/DA转换模块*1
★PS2 操作手柄模块*1
★面包板*1
★跳线若干
三、实验原理
RGB LED模块
有源蜂鸣器模块
PCF8591数模转换模块
PS2操纵杆
DS18B20温度传感器
我们可以在编程时通过操纵杆PS2调整下限和上限值。操纵杆PS2有五个操作方向:向上、向下、向左、向右和向下按压。在这个项目中,我们将使用左右方向来控制上限值,上下方向来控制下限值。如果按一下操纵杆,系统将退出。
当实际温度值在下限和上限值之间时,LED灯显绿色,蜂鸣器无响声;当实际温度值超下限时,LED灯显蓝色,蜂鸣器蜂鸣3次,每次0.5秒;当实际温度值超上限时,LED灯显红色,蜂鸣器蜂鸣3次,每次0.1秒。
每个模块的详情资料请参考前面的文章: 树莓派基础实验2:RGB-LED实验 树莓派基础实验9:蜂鸣器实验 树莓派基础实验12:PCF8591模数转换器实验 树莓派基础实验14:PS2操纵杆实验 树莓派基础实验25:DS18B20温度传感器实验
四、实验步骤
第1步: 连接电路。
树莓派 |
T型转接板 |
DS18B20温度传感器 |
---|---|---|
GPIO7 |
G4 |
SIG |
5V |
5V |
VCC |
GND |
GND |
GND |
树莓派 |
T型转接板 |
PCF8591数模转换模块 |
---|---|---|
SDA |
SDA |
SDA |
SCL |
SCL |
SCL |
5V |
5V |
VCC |
GND |
GND |
GND |
PS2操纵杆 |
T型转接板 |
PCF8591数模转换模块 |
---|---|---|
Y |
* |
AIN0 |
X |
* |
AIN1 |
SW(按钮) |
* |
AIN2 |
VCC |
5V |
* |
GND |
GND |
* |
树莓派 |
T型转接板 |
RGB LED模块 |
---|---|---|
GPIO0 |
G17 |
R |
GPIO1 |
G18 |
G |
GPIO2 |
G27 |
B |
GND |
GND |
GND |
树莓派 |
T型转接板 |
有源蜂鸣器模块 |
---|---|---|
GPIO3 |
G22 |
SIG |
3.3V |
3.3V |
VCC |
GND |
GND |
GND |
智能温度测量系统电路图
智能温度测量系统实物接线图
第2步: RGB LED模块程序。
#!/usr/bin/env python #告诉Linux本文件是一个Python程序
import RPi.GPIO as GPIO #导入控制GPIO的模块,RPi.GPIO
import time #导入时间模块,提供延时、时钟和其它时间函数
colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF] #颜色列表
R = 11 #定义物理针脚号
G = 12
B = 13
def setup(Rpin, Gpin, Bpin):
global pins #在函数内部声明被其修饰的变量是全局变量
global p_R, p_G, p_B
pins = {'pin_R': Rpin, 'pin_G': Gpin, 'pin_B': Bpin}
GPIO.setmode(GPIO.BOARD) #设置引脚编号模式为板载模式,即树莓派上的物理位置编号
for i in pins:
GPIO.setup(pins[i], GPIO.OUT) # 设置针脚模式为输出(或者输入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): #将颜色的刺激量转换为占空比对应的值。
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 #先“与”运算只保留自己颜色所在位的值有效
G_val = (col & 0x00ff00) >> 8 #再“右移”运算将自己颜色所在位的值提取出来
B_val = (col & 0x0000ff) >> 0
R_val = map(R_val, 0, 255, 0, 100) #将颜色的刺激量转换为占空比对应的值
G_val = map(G_val, 0, 255, 0, 100)
B_val = map(B_val, 0, 255, 0, 100)
p_R.ChangeDutyCycle(R_val) # 更改占空比,调整该颜色的亮度
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状态
if __name__ == "__main__":
try: #用try-except代码块来处理可能引发的异常
setup(R, G, B) #调用初始化设置LED灯的函数
loop() #调用循环函数
except KeyboardInterrupt: #如果遇用户中断(control+C),则执行destroy()函数
destroy() #调用清除LED状态的函数
第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数模转换模块程序。
#!/usr/bin/env python
#------------------------------------------------------
#
# 您可以使用下面语句将此脚本导入另一个脚本:
# “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,系统管理总线)
import smbus #在程序中导入“smbus”模块
import time
# for RPI version 1, use "bus = smbus.SMBus(1)"
# 0 代表 /dev/i2c-0, 1 代表 /dev/i2c-1 ,具体看使用的树莓派那个I2C来决定
bus = smbus.SMBus(1) #创建一个smbus实例
#在树莓派上查询PCF8591的地址:“sudo i2cdetect -y 1”
def setup(Addr):
global address
address = Addr
def read(chn): #channel
if chn == 0:
bus.write_byte(address,0x40) #发送一个控制字节到设备
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) # 从设备读取单个字节,而不指定设备寄存器。
return bus.read_byte(address) #返回某通道输入的模拟值A/D转换后的数字值
def write(val):
temp = val # 将字符串值移动到temp
temp = int(temp) # 将字符串改为整数类型
# print temp to see on terminal else comment out
bus.write_byte_data(address, 0x40, temp)
#写入字节数据,将数字值转化成模拟值从AOUT输出
if __name__ == "__main__":
setup(0x48)
#在树莓派终端上使用命令“sudo i2cdetect -y 1”,查询出PCF8591的地址为0x48
while True:
print '电位计 AIN0 = ', read(0) #电位计模拟信号转化的数字值
print '光敏电阻 AIN1 = ', read(1) #光敏电阻模拟信号转化的数字
print '热敏电阻 AIN2 = ', read(2) #热敏电阻模拟信号转化的数字值
tmp = read(0)
tmp = tmp*(255-125)/255+125
# 125以下LED不会亮,所以将“0-255”转换为“125-255”,调节亮度时灯不会熄灭
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(): #获取操纵杆方向结果
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 #由于未知原因,向左摇操纵杆会自动触发按键按下信号
and ADC.read(2) == 0: #所以加上ADC.read(1) >= 6这个限制,
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值变化时打印
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 #导入操作系统的库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',另外一个就是温度数据文件所在的文件夹
ds18b20 = i
#将温度数据文件所在的文件夹名赋值给全局变量ds18b20
def read():
location = '/sys/bus/w1/devices/' + ds18b20 + '/w1_slave'
#location是温度数据文件的地址
tfile = open(location)
#os.open(file, flags[, mode])打开一个文件
text = tfile.read()
# os.read(fd, n)从文件描述符 fd 中读取最多 n 个字节,返回包含
# 读取字节的字符串,文件描述符 fd对应文件已达到结尾, 返回一个空字符串。
tfile.close()
#os.close(fd)关闭文件描述符 fd
secondline = text.split("n")[1]
# string.split(str="", num=string.count(str))
# 以 str 为分隔符切片 string,如果 num 有指定值,则仅分隔 num+ 个子字符串
#计算机里序号是从0开始计算,取1即是第二行
temperaturedata = secondline.split(" ")[9]
#以空格为分隔符,取序号为9的字符段,如:t=17375
temperature = float(temperaturedata[2:])
#取字符串(如:t=17375)第2位及以后部分,即数字部分17375
temperature = temperature / 1000
return temperature
def loop():
while True:
if read() != None:
print "Current temperature : %0.3f C" % read()
#以单精度浮点小数的形式输出,保留三位小数
def destroy():
pass
if __name__ == '__main__':
try:
setup()
loop()
except KeyboardInterrupt:
destroy()
第7步: 智能温度测量系统总控制程序。当实际温度值在下限和上限值之间时,LED灯显绿色,蜂鸣器无响声;当实际温度值超下限时,LED灯显蓝色,蜂鸣器蜂鸣3次,每次0.5秒;当实际温度值超上限时,LED灯显红色,蜂鸣器蜂鸣3次,每次0.1秒。
#!/usr/bin/env python
import RPi.GPIO as GPIO
import importlib #动态加载某个模块
import time
import sys
# 重新定义部分针脚位置
LedR = 11
LedG = 12
LedB = 13
Buzz = 15
#ds18b20 = '28-031467805fff'
#location = '/sys/bus/w1/devices/' + ds18b20 + '/w1_slave'
#导入模块
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')
#调用各个模块中的初始化函数
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():
"""根据摇杆方向的值设置上下限的值及退出"""
global lowl, highl
temp = joystick.direction()
if temp == 'Button pressed': #当按下摇杆时,程序退出
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']) #温度超下限时LED灯显蓝色
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']) #温度不超限时LED灯显绿色
if temp >= float(highl):
rgb.setColor(color['Red']) #温度超上限时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()
实验结果示例:
实验结果
- Silverlight/aspx/ajax/mvc的UI自动化测试
- Office Open XML学习(1)-创建excel文档,并向单元格中插入字符串
- PyMC3和Theano代码构建贝叶斯深度网络,61页PPT探索贝叶斯深度学习以及实现
- 男程序员是不是都不会和女生表达交流?程序员的回答歪了
- Silverlight Telerik控件学习:主题Theme切换
- Silverlight自定义类库实现应用程序缓存
- Silverlight Telerik控件学习:TreeView数据绑定并初始化选中状态、PanelBar的Accordion效果、TabPanel、Frame基本使用
- 这或许是对小白最友好的python入门了吧——4,列表
- 每个人都应该知道的十个机器学习常识
- 重新带你了解React.js
- WebService又一个不爽的地方
- 劲爆!小程序又增新功能!为落地微信智慧零售方案做铺垫!
- 5G光传送网技术
- 突破封闭 Web 系统的技巧之正面冲锋
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 项目实战|缓存处理
- 前端构建 DevOps - 搭建 DevOps 基础平台(上)
- 线剪裁算法简介
- 使用OpenCV和Python生成电影条形码
- 前端构建 DevOps - 搭建 DevOps 基础平台(中)
- 从 0 到 1 node 项目管理系统:搭建基础平台(下)
- Fiddler是个问题少女,又作又可招人爱
- devOps:构建篇-Jenkins
- H5 基础脚手架:极速构建项目
- 从 0 到 1 的项目管理系统:脚手架篇 - H5 基础脚手架
- Codeforces Round #612 (Div. 2) A. Angry Students
- 项目实战-埋点系统初探
- POJ1611 (并查集)
- 费解的开关
- UVA1368