RaspberryPiでBME280を使って20x4 LCDに表示する

* 準備 [#maac11d6]
- raspi-configでI2Cを有効にする
- Pythonにライブラリを追加する~
$ sudo pip install subus2~
$ sudo pip install Adafruit_CharLCD

* LCDの接続(LCDは3.3V用を使う) [#i4108e5a]
lcd_d0= n.c~
lcd_d1= n.c~
lcd_d2= n.c~
lcd_d3= n.c~
lcd_d4= GP-5(29ピン)~
lcd_d5= GP-6(31ピン)~
lcd_d6= GP-13(33ピン)~
lcd_d7= GP-19(35ピン)~
lcd_rs= GP-20(38ピン)~
lcd_en= GP-21(40ピン)~
lcd_rw= GND~
lcd_d0= n.c~
lcd_d1= n.c~
lcd_d2= n.c~
lcd_d3= n.c~

LCDのR/WピンをLow固定にして書き込み固定モードであれば、5V電源LCDを3.3V信号で駆動することも可能。~
パラレルではなくI2Cの場合は双方向になるので無理。~


* MBE280の接続~ [#ia675285]
BME_SDA= 3ピン~
BME_SCL= 5ピン

* VCC/GNDの接続 [#hac0fe3e]
VCC= 1ピン(3.3V)~
GND= 6ピン

* ソースコード [#x0148071]
 pi@pi3b2:~/bme280$ cat bme280_lcd.py
 #coding: utf-8
 
 from smbus2 import SMBus
 import time
 
 import Adafruit_CharLCD as LCD
 from datetime import datetime
 
 import os
 import commands
 
 bus_number  = 1
 i2c_address = 0x77
 
 bus = SMBus(bus_number)
 
 digT = []
 digP = []
 digH = []
 
 t_fine = 0.0
 
 # GND Pin: 6 9 14 30 25 30 34 39
 # LCD pin assign(GPIO Num)
 lcd_rs= 20      # 38pin
 lcd_en= 21      # 40pin
 lcd_d4= 5       # 29pin
 lcd_d5= 6       # 31pin
 lcd_d6= 13      # 33pin
 lcd_d7= 19      # 35pin
 lcd_backlight = 4
 
 # Define LCD column and row size.
 lcd_columns= 20
 lcd_rows= 4
 
 # Initialize the LCD using the pins above.
 lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7,lcd_columns, lcd_rows, lcd_backlight)
 
 lcd.clear()
 
 
 
 
 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)
 
 def compensate_P(adc_P):
         global  t_fine,p
         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 "%7.2f hPa" % (pressure/100)
         p = "%4.0f" % (pressure/100)
 
 def compensate_T(adc_T):
         global t_fine,t
         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 "  %-6.2f℃" % (temperature)
         t = "%-4.1f" % (temperature)
 
 def compensate_H(adc_H):
         global t_fine,h
         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 " %6.2f %" % (var_h)
         h = "%2.0f" % (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:
                 time.sleep(1)
                 lcd.clear()
                 while True:
                         readData()
 
                         cpu_temp = commands.getoutput("vcgencmd measure_temp").split('=')
                         #cpu_volt=commands.getoutput("vcgencmd measure_volts").split('=')
                         cpu_mem=commands.getoutput("vcgencmd get_mem arm").split('=')
                         cpu_gpu=commands.getoutput("vcgencmd get_mem gpu").split('=')
 
                         dt_now = datetime.now()
                         week_num = dt_now.strftime("%w")
                         if week_num == "0":
                                 week_text = 'Sun'
                         if week_num == "1":
                                 week_text = 'Mon'
                         if week_num == "2":
                                 week_text = 'Tue'
                         if week_num == "3":
                                 week_text = 'Wed'
                         if week_num == "4":
                                 week_text = 'Thu'
                         if week_num == "5":
                                 week_text = 'Fri'
                         if week_num == "6":
                                 week_text = 'Sat'
 
                         lcd.blink(False)
                         #message_text = dt_now.strftime("%Y/%m/%d ")
                         message_text = dt_now.strftime("%m/%d") + "(" + week_text + ")  " + dt_now.strftime("%H:%M:%S")
                         lcd.message(message_text)
                         lcd.set_cursor(0,2)
                         message_text = "CPU:" + cpu_temp[1] + " " + cpu_mem[1] + " " + cpu_gpu[1]
                         lcd.message(message_text)
                         lcd.set_cursor(0,3)
                         message_text = "Ext:" + p + "hP " + t + "C " + h + "%" + ""
                         lcd.message(message_text)
 
                         time.sleep(0.2)
                         lcd.home()
 
         except KeyboardInterrupt:
                 lcd.clear()
                 time.sleep(1.0)

* 付録(10分おきにファイルに記録) [#if7d6d68]

** 準備 [#k38a417d]
ソースコードは全て/home/pi/bme280に置いておく~
データの保存先は/home/pi/bme280/dataにする~
その他必要なファイルも置いておく

** ソースコード [#v9acd243]
 pi@pi3b2:~/bme280$ cat bme280_csv.py
 #coding: utf-8
 
 import bme280_custom
 import bme280_temp
 import bme280_pres
 import bme280_humid
 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')
 date = now.strftime('%Y/%m/%d %H:%M')
 csv = bme280_custom.readData()
 csv_t = bme280_temp.readData()
 csv_p = bme280_pres.readData()
 csv_h = bme280_humid.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("'"+date+"',"+csv+"\n")
 f.close()
 
 f = open('/home/pi/bme280/data/'+filename+'_t.csv','a')
 f.write("'"+date+"',"+csv_t+"\n")
 f.close()
 f = open('/home/pi/bme280/data/'+filename+'_p.csv','a')
 f.write("'"+date+"',"+csv_p+"\n")
 f.close()
 
 f = open('/home/pi/bme280/data/'+filename+'_h.csv','a')
 f.write("'"+date+"',"+csv_h+"\n")
 f.close()

** crontabで10分おきに実行する [#l7769ddf]
 @reboot python ~/bme280/bme280_lcd.py
 0,10,20,30,40,50 * * * * python ~/bme280/bme280_csv.py

* モジュールの種類 [#ldda7212]

** 3.3V専用(秋月でも売ってるタイプ) [#w4e6448b]
アドレス:0x77
&ref(BME-Blue.jpg);

** 3.3V/5V兼用 [#k8a25113]
アドレス:0x76
&ref(BME-Purple.jpg);

** BMEとBMPの見分け方 [#h67f7b03]
BMPは湿度が測れない(そのかわり安い)
&ref(BME280_U.jpg);

- 穴が上下方向のセンターにある(BMPは穴が角に近い)
- モジュールが正方形(BMPは長方形)
~
~
~
&ref(BMP280.jpg);
BMP280

** BME280 Rasbee製(3.3V専用) [#i46586f8]
,SDO,CSB,SDA,SCL,GND,VCC
,PD,PU,PU,PU, ,
CSBがPUされているのでI2Cモード~
SDOがPDされているので、I2C Addressは0x76~
→SDOをVDDに繋ぐと0x77

&ref(BME280_Rasbee.jpg);

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS