前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >树莓派综合项目1:智能温度测量系统实验

树莓派综合项目1:智能温度测量系统实验

作者头像
张国平
发布2020-09-27 10:38:38
1K0
发布2020-09-27 10:38:38
举报

一、介绍

  本系统中,将使用常见的几种模块来构建一个简单的智能温度测量系统。

二、组件

★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模块程序。

代码语言:javascript
复制
#!/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步: 有源蜂鸣器模块程序。

代码语言:javascript
复制
#!/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数模转换模块程序。

代码语言:javascript
复制
#!/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操纵杆程序。

代码语言:javascript
复制
#!/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温度传感器模块程序。

代码语言:javascript
复制
#!/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秒。

代码语言:javascript
复制
#!/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()

  实验结果示例:

实验结果

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、介绍
  • 二、组件
  • 三、实验原理
  • 四、实验步骤
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档