电源设计技术信息网站

订阅电子杂志   English   繁體中文   日本語   한국어

下载中心

TECH INFORaspberry Pi初学者指南

利用AE-BME280和Raspberry Pi读取温度、湿度和压力值

这篇文章来源于DevicePlus.com英语网站的翻译稿。

bme280

在本教程中,我们将使用一个多功能模块,协助Raspberry Pi同时测量温度、湿度和气压三种参数。

该项目需要焊接!如上图所示,该部件带有一个单独的排针,因此我们需要将其焊接到面包板上。

AE-BME280

bme280

图1:AE-BME280 / © Akizuki Denshi

使用BME280的温度/湿度/压力传感器模块套件BME280(日语)
凭借搭载Bosch Sensortec BMP280的传感器模块,您可以同时测量温度、湿度和气压。该模块还可以通过I2C或SPI与微控制器通信。

我们将在本教程中使用这款超紧凑型AE-BME280压力传感器(尺寸:16x10mm)。该模块采购于日本零件供应商Akizuki Denshi,您也可以使用具有相同芯片的Adafruit BME280模块。请注意,Adafruit的引脚布局略有不同,因此连线时请务必参考其技术规格书。

Adafruit BME280 技术规格书

BME280——一块位于元件中心的微小银芯片——承担了大部分工作。该模块表面上还有一个非常小的开口,其作用是读取数值,因此切勿遮盖这个开口。

AE-BME280板和排针本来就是分开的。连接Raspberry Pi的最简单方法就是将两者组装在一起,如图1所示。这需要焊接。我购买的排针有10个引脚,但是连接AE-BME280只需6个引脚,所以应剪掉第6个引脚后面的排针。

技术规格请参见AE-BME280的日语手册

您可以用I2C或SPI进行通信。由于我之前已经用过SPI,所以这次我将尝试使用I2C。

I2C – 维基百科
I2C(集成电路总线)是一种由Philips Semiconductor(现为NXP Semiconductors)发明的串行总线。I2C代表I-平方-C。由于纯文本环境中的字符限制,我们将其称为I2C或IIC。该协议通常用于将低速外围IC连至主板、嵌入式系统和移动电话等设备。

bme280

图2:引脚编号和功能–摘自AE-BME280技术规格书

连接I2C或SPI是不同的,所以我们必须注意引脚接法。请参阅AE-BME280 技术规格书 (日语)或Adafruit BME280 技术规格书(英语)

如图2所示,使用I2C时,我们需要焊接 J3 跳线。我们必须在此跳线处填充焊锡。请注意,这仅适用于AE-BME280芯片。Adafruit芯片不需要设置此跳线。

焊接!

bme280

图3:焊接设备

现在,是时候焊接了!首先应加热烙铁。

焊锡 – 维基百科
焊锡是一种主要由铅和锡组成的合金,与电烙铁配合使用。主要用于连接金属元件,以及将电气元件焊接到电路板上。根据其成分,焊锡会在4-10度时变成超导体。

我在这个项目中用的是这种焊锡。这种焊锡非常柔韧,容易泄漏,因此只能一点一点地送锡。我们还应准备一个吸锡器,以防万一。如果送锡过多,可以用吸锡器吸掉多余的焊锡,所以要小心!

bme280

图4:焊接J3

首先,我们应焊接图4所示的J3跳线。J3与相邻引脚靠的很近,所以要小心不要焊接在一起。送锡时要小心仔细!

 

bme280

图5:焊接排针

下一步是连接排针。我从电路板背面焊接排针。引脚之间的间隙非常小,因此很难将电烙铁塞入。电路板两端引脚的焊锡结块示例如图5所示。

焊接技巧是先用烙铁头稍稍加热引脚,然后再送锡。如果烙铁尖过热,焊锡会燃烧并形成结块。因此,我建议焊完一个引脚后,从电源插座上拔下电烙铁并冷却后再焊接下一个引脚。不必着急。小心不要将引脚焊接在一起。慢慢来!

bme280

图6:连至面包板的AE-BME280

完成!排针焊接完毕,现在电路板垂直插在面包板上。

焊接时,我不小心碰到了排针末端并稍微烫了一下,但幸运的是这并没有影响读数。

接线

现在,让我们将Raspberry Pi连接到AE-BME280。连接示意图如图7所示,因为我们使用的是I2C通信。

bme280

图7:I2C连接方法–摘自AE-BME280技术规格书

在Raspberry Pi上,“SDA”连至GPIO2(引脚3),“SCL”连到GPIO3(引脚5)。VDD连接到引脚1,这样前3个GPIO引脚按顺序排列(参见图8)。接线时容易记忆。

 

bme280

图8:接线示意图

我将AE-BME280上的引脚5(SDO)连至GND,您也可以将其连至VDD。(请注意,如果这样做,数据收集地址会发生变化)。

设置 Raspberry Pi

Raspberry Pi默认禁用I2C。启用I2C的方法与启用SPI的方法相同,请参阅上一个教程:Raspberry Pi WebIOPi物联网,模拟输入编程。在菜单中选择[Preferences] – [Raspberry Pi Configuration],然后打开“Settings ”屏幕。

bme280

点击[Interfaces]选项卡,将[I2C]设为[Enable]

必须重新启动系统该设置才能生效,因此请在弹出窗口中单击“Yes”。重启后,I2C传输已启用。

bme280

(OS: 2015年11月21日发布的Raspbian Jessie版本)

接下来,我们安装使用I2C所需的软件包。我们需要在命令行中使用[i2c-tools],在Python中使用[python-smbus]。

安装命令
sudo apt-get install i2c-tools
sudo apt-get python-smbus

如果运行命令“i2cdetect”,系统会检测通过I2C方式连接的所有设备。

sudo i2cdetect -y 1

bme280

76是十六进制数;代表0x76。

注:选择I2C地址时,如果电路板(SDO)上的引脚5连至GND,那么默认为[0x76];如果连至VDD,则默认为[0x77]。

我将SDO连接到GND,因此显示0x76,但如果连至VDD,则会显示0x77。

此外,i2Cdetect命令中的最后一个参数取决于Raspberry Pi的版本。Revision 1(2012年10月14日之前发货的Raspberry Pi Model B)使用0,而Revision 2指定使用1。我用的是Raspberry Pi 2 Model B,因此参数值为1。

我运行程序时发生了以下错误:

bme280

发生错误后,我查看了dev目录,看到有一个名为[i2c-1]而不是[i2c-0]的文件。我无法打开这个文件,但我认为该文件包含记录的测量值。

sudo i2cdump -y 1 0x76

bme280

上图是我用i2Cdump命令输出寄存器值的结果。看起来设备读取了很多数值,但是我无法分辨哪些值来自哪里以及为什么是这样子的。

我很难对这些值进行转换/计算,所以我从Switch Science库中借用了一些Python源代码:

SWITCHSCIENCE/BME280

单击右上角的“Download ZIP”链接,将Python27文件夹中的“bme_280_sample.py”文件放在Raspberry Pi的相应位置。注意:此程序需要“python-smbus”软件包才能运行。

python /home/pi/bme280_sample.py

准备工作完成后,运行程序!成功运行之后,您会看到三行输出:温度、压力和湿度。

bme280

注意:您必须具有root权限才能运行smbus软件包。和往常一样,我尝试用PHP运行,但是出现错误,所以我放弃了。bme_280_sample.py 源代码中有很多复杂的计算,虽然我Python经验很少,但是我仍然设法修改了输出部分。我的部分定制代码如下:

/home/pi/bme280_custom.py

#coding: utf-8

import smbus
import time

bus_number  = 1
i2c_address = 0x76

bus = smbus.SMBus(bus_number)

digT = []
digP = []
digH = []

t_fine = 0.0

def writeReg(reg_address, data):
    bus.write_byte_data(i2c_address,reg_address,data)

def get_calib_param():
    calib = []

    for i in range (0x88,0x88+24):
        calib.append(bus.read_byte_data(i2c_address,i))
    calib.append(bus.read_byte_data(i2c_address,0xA1))
    for i in range (0xE1,0xE1+7):
        calib.append(bus.read_byte_data(i2c_address,i))

    digT.append((calib[1] << 8) | calib[0])
    digT.append((calib[3] << 8) | calib[2])
    digT.append((calib[5] << 8) | calib[4])
    digP.append((calib[7] << 8) | calib[6])
    digP.append((calib[9] << 8) | calib[8])
    digP.append((calib[11]<< 8) | calib[10])
    digP.append((calib[13]<< 8) | calib[12])
    digP.append((calib[15]<< 8) | calib[14])
    digP.append((calib[17]<< 8) | calib[16])
    digP.append((calib[19]<< 8) | calib[18])
    digP.append((calib[21]<< 8) | calib[20])
    digP.append((calib[23]<< 8) | calib[22])
    digH.append( calib[24] )
    digH.append((calib[26]<< 8) | calib[25])
    digH.append( calib[27] )
    digH.append((calib[28]<< 4) | (0x0F & calib[29]))
    digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
    digH.append( calib[31] )

    for i in range(1,2):
        if digT[i] & 0x8000:
            digT[i] = (-digT[i] ^ 0xFFFF) + 1

    for i in range(1,8):
        if digP[i] & 0x8000:
            digP[i] = (-digP[i] ^ 0xFFFF) + 1

    for i in range(0,6):
        if digH[i] & 0x8000:
            digH[i] = (-digH[i] ^ 0xFFFF) + 1 

def readData():
    data = []
    for i in range (0xF7, 0xF7+8):
        data.append(bus.read_byte_data(i2c_address,i))
    pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
    temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
    hum_raw  = (data[6] << 8)  |  data[7]

    #compensate_T(temp_raw)
    #compensate_P(pres_raw)
    #compensate_H(hum_raw)
    t = compensate_T(temp_raw)
    p = compensate_P(pres_raw)
    h = compensate_H(hum_raw)
    return p + "," + t + "," + h

def compensate_P(adc_P):
    global  t_fine
    pressure = 0.0

    v1 = (t_fine / 2.0) - 64000.0
    v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]
    v2 = v2 + ((v1 * digP[4]) * 2.0)
    v2 = (v2 / 4.0) + (digP[3] * 65536.0)
    v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((digP[1] * v1) / 2.0)) / 262144
    v1 = ((32768 + v1) * digP[0]) / 32768

    if v1 == 0:
        return 0
    pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125
    if pressure < 0x80000000:         pressure = (pressure * 2.0) / v1     else:         pressure = (pressure / v1) * 2     v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096     v2 = ((pressure / 4.0) * digP[7]) / 8192.0     pressure = pressure + ((v1 + v2 + digP[6]) / 16.0)        #print "pressure : %7.2f hPa" % (pressure/100)     return "%7.2f" % (pressure/100)     def compensate_T(adc_T):     global t_fine     v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]     v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]     t_fine = v1 + v2     temperature = t_fine / 5120.0     #print "temp : %-6.2f ℃" % (temperature)     return "%.2f" % (temperature)   def compensate_H(adc_H):     global t_fine     var_h = t_fine - 76800.0     if var_h != 0:         var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) * (digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h)))     else:         return 0     var_h = var_h * (1.0 - digH[0] * var_h / 524288.0)     if var_h > 100.0:
        var_h = 100.0
    elif var_h < 0.0:
        var_h = 0.0
    #print "hum : %6.2f %" % (var_h)
    return "%.2f" % (var_h)

def setup():
    osrs_t = 1            #Temperature oversampling x 1
    osrs_p = 1            #Pressure oversampling x 1
    osrs_h = 1            #Humidity oversampling x 1
    mode   = 3            #Normal mode
    t_sb   = 5            #Tstandby 1000ms
    filter = 0            #Filter off
    spi3w_en = 0            #3-wire SPI Disable

    ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode
    config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en
    ctrl_hum_reg  = osrs_h

    writeReg(0xF2,ctrl_hum_reg)
    writeReg(0xF4,ctrl_meas_reg)
    writeReg(0xF5,config_reg)

setup()
get_calib_param()

if __name__ == '__main__':
    try:
        readData()
    except KeyboardInterrupt:
        pass

 

我并没有修改太多代码,只是对主要的“处理”部分进行了一些小的调整。我将“print”改为“return”并进行了相关编辑,使得程序以CSV格式返回数值(带逗号)。

/home/pi/bme280.py

#coding: utf-8

 

import bme280_custom

import datetime

import os

 

dir_path = '/home/pi/bme280-data'

 

now = datetime.datetime.now()

filename = now.strftime('%Y%m%d')

label = now.strftime('%H:%M')

csv = bme280_custom.readData()

 

if not os.path.exists('/home/pi/bme280-data'):

    os.makedirs('/home/pi/bme280-data')

f = open('/home/pi/bme280-data/'+filename+'.csv','a')

f.write("'"+label+"',"+csv+"\n")

f.close()

 

我创建了另一个py,从之前修改过的“bme280_custom.py”中调用readData()函数。这会将读取的数值保存在CSV文件中。文件的设置如下:记录一整天的数据,以日期作为文件名保存。

我用cron登记了这个程序并进行了设置,让它定期运行。现在完成了!
sudo crontab -e

0-59/10 * * * * /home/pi/bme280.py

注:我将其设置为每10分钟运行一次。

接下来,我将创建一个PHP文件来显示数据。我用 DS18B20 温度传感器制作温度计时做过类似事情。


/var/www/html/bme280.php

 

<?php

$today  = date("Ymd");

$csv_dir  = '/home/pi/bme280-data/';

$csv_file = $today.'.csv';

$grapgh   = '';

if (($handle = fopen($csv_dir.$csv_file, "r")) !== false) {

    while (($line = fgets($handle)) !== false) {

    $grapgh .= '['.rtrim($line).'],'.PHP_EOL;

    }

    fclose($handle);

}else{

    echo 'no data';

}

?>

<html>

<head>

<script type="text/javascript" src="https://www.google.com/jsapi"></script>

<script type="text/javascript">

    google.load("visualization", "1", {packages:["table"]});

    google.setOnLoadCallback(drawTable);

 

    function drawTable() {

    var data = new google.visualization.DataTable();

    data.addColumn('string', 'Time');

    data.addColumn('number', 'Pressure');

    data.addColumn('number', 'Temperature');

    data.addColumn('number', 'Humidity');

    data.addRows([

 

<?php echo $grapgh; ?>

 

    ]);

 

      var table = new google.visualization.Table(document.getElementById('table_div'));

      table.draw(data, {showRowNumber: true});

    }

</script>

</head>

<body>

 

<div id="table_div"></div>

 

</body>

</html>

 

我创建了一个简单的PHP文件,在表中显示相关数据(您必须安装“php5”软件包才能使用PHP)。

bme280

通过这种方式,我可以用浏览器——导航至 http://localhost/bme280.php ——查看CSV文件的内容。即使每隔10分钟,压力也会发生巨大变化!

Raspbian最新版本预装了一个名为“LibreOffice”的办公套件。如果您只是想查看数据,那么可以使用“LibreOffice Calc”(双击CSV文件),然后您会看到如下内容:

总结

今天,我们用AE-BME280传感器构建了一个简单模块来测量多个数值(压力、湿度和温度)。这么小的传感器可以测量多达三个不同的参数,真是太神奇了。传感器非常微小,但非常强大!

这个项目还让我提高了焊接技巧。AE-BME280上的引脚非常小,彼此非常靠近,我当时还担心可能会把多个引脚焊接在一起。最后,成品的引脚焊接得很好,我很高兴。需要焊接的项目可能比较困难,但是值得!

DevicePlus 编辑团队
DevicePlus 编辑团队

设备升级版适用于所有热爱电子和机电一体化的人。

分享到社交媒体