LCDディスプレイへの各種情報の表示
かなり前にも書きましたが、I2C接続の2行表示のディスプレイに、手持ちのセンサーなどから取得した情報を表示してみます
表示する情報は以下の内容
- 現在の日付、時間
- CPU使用率と温度、メモリの使用量と全量
- ホスト名
- IPアドレスと、それを保持するインターフェース名
- 温度と大気圧
- 温度と湿度
使用した機器です(本体、Raspberry Pi は除く)
LCDディスプレイ
いろいろと似たようなものがありますが、手持ちのものと同じものです
- 価格: 1880 円
- 楽天で詳細を見る
温度・湿度センサー
手持ちのものと同じものが見つかりませんでしたが、I2C接続できる「SHT3X」という型番で探しました。たぶん、大丈夫
温度・大気圧センサー
上の温度センサーの値と、この温度センサーの値が、ちょっと異なるんですよね。1℃くらい。
情報を1秒ごとに表示します
以前の内容から、少し変えています
from time import sleep import smbus class i2c: ''' i2cクラス ''' # i2c オブジェクト i2c = None # i2c アドレス ADR = None def __init__(self, adr, bus = 1) -> None: ''' コンストラクタ ''' self.ADR = adr self.i2c = smbus.SMBus(bus) def readS8(self, register): ''' 符号あり8ビット読込 ''' result = self.i2c.read_byte_data(self.ADR, register) if result > 127: # 符号算出 result -= 256 return result def readS16(self, register): ''' 符号あり16ビット読込(アドレス値は指定8ビット と 指定8ビット + 1) ''' hi = self.readS8(register) lo = self.readU8(register+1) return (hi << 8) + lo def readU8(self, register): ''' 符号なし8ビット読込 ''' result = self.i2c.read_byte_data(self.ADR, register) return result def readU16(self, register): ''' 符号なし16ビット読込(アドレス値は指定8ビット と 指定8ビット + 1) ''' hi = self.readU8(register) lo = self.readU8(register+1) return (hi << 8) + lo def readBlockData(self, register, blocks): ''' 指定ブロック読込 ''' block = self.i2c.read_i2c_block_data(self.ADR, register, blocks) return block def write8(self, register, value): ''' 8ビット書込 ''' self.i2c.write_byte_data(self.ADR, register, value) def writeByte(self, value): ''' 8ビット書込 ''' self.i2c.write_byte(self.ADR, value) class SHT3X: ''' 温度・湿度センサー ''' SHT3X_FREQ_MSB = 0x23 SHT3X_FREQ_LSB = 0x34 SHT3X_READ_MSB = 0xe0 SHT3X_READ_LSB = 0x00 SHT3X_READ_ADR = 0x00 I2C_ADR = 0x44 i2c = None def __init__(self) -> None: ''' コンストラクタ ''' # i2cオブジェクト self.i2c = i2c(self.I2C_ADR) def calcTemperatureHumidity(self): ''' 温度と湿度を算出 ''' # 測定頻度の設定 self.i2c.write8(self.SHT3X_FREQ_MSB, self.SHT3X_FREQ_LSB) sleep(0.5) # 測定値の読出し self.i2c.write8(self.SHT3X_READ_MSB, self.SHT3X_READ_LSB) sleep(0.5) # 6バイト取得 d = self.i2c.readBlockData(self.SHT3X_READ_ADR, 6) # 0~1バイトが温度 # 測定データ(生データ)を取得 t = ((d[0]) << 8) | (d[1]) # 換算する t = -45 + (175 * t / 65535) # 3~4バイトが湿度 # 測定データ(生データ)を取得 h = ((d[3]) << 8) | (d[4]) # 換算する h = 100 * h / 65535 # 結果を返却 return t, h class BMP085: ''' 温度・大気圧センサー ''' BMP085_CAL_AC1 = 0xAA BMP085_CAL_AC2 = 0xAC BMP085_CAL_AC3 = 0xAE BMP085_CAL_AC4 = 0xB0 BMP085_CAL_AC5 = 0xB2 BMP085_CAL_AC6 = 0xB4 BMP085_CAL_B1 = 0xB6 BMP085_CAL_B2 = 0xB8 BMP085_CAL_MB = 0xBA BMP085_CAL_MC = 0xBC BMP085_CAL_MD = 0xBE BMP085_CONTROL = 0xF4 BMP085_TEMPDATA = 0xF6 BMP085_PRESSUREDATA = 0xF6 BMP085_READTEMPCMD = 0x2E BMP085_READPRESSURECMD = 0x34 MODE = 3 WAIT_TIME = [0.005, 0.014, 0.008, 0.026] I2C_ADR = 0x77 i2c = None def __init__(self) -> None: ''' コンストラクタ ''' # i2cオブジェクト self.i2c = i2c(self.I2C_ADR) def calibration(self): ''' キャリブレーション ''' # キャリブレーションデータ読込 self.cal_AC1 = self.i2c.readS16(self.BMP085_CAL_AC1) self.cal_AC2 = self.i2c.readS16(self.BMP085_CAL_AC2) self.cal_AC3 = self.i2c.readS16(self.BMP085_CAL_AC3) self.cal_AC4 = self.i2c.readU16(self.BMP085_CAL_AC4) self.cal_AC5 = self.i2c.readU16(self.BMP085_CAL_AC5) self.cal_AC6 = self.i2c.readU16(self.BMP085_CAL_AC6) self.cal_B1 = self.i2c.readS16(self.BMP085_CAL_B1) self.cal_B2 = self.i2c.readS16(self.BMP085_CAL_B2) self.cal_MB = self.i2c.readS16(self.BMP085_CAL_MB) self.cal_MC = self.i2c.readS16(self.BMP085_CAL_MC) self.cal_MD = self.i2c.readS16(self.BMP085_CAL_MD) def readUncpmpensatedTemp(self): ''' センサーから温度を取得 ''' self.i2c.write8(self.BMP085_CONTROL, self.BMP085_READTEMPCMD) sleep(0.026) raw = self.i2c.readU16(self.BMP085_TEMPDATA) return raw def readUncpmpensatedPressure(self): ''' センサーから気圧を取得 ''' self.i2c.write8(self.BMP085_CONTROL, self.BMP085_READPRESSURECMD + (self.MODE << 6)) sleep(self.WAIT_TIME[self.MODE]) msb = self.i2c.readU8(self.BMP085_PRESSUREDATA) lsb = self.i2c.readU8(self.BMP085_PRESSUREDATA+1) xlsb = self.i2c.readU8(self.BMP085_PRESSUREDATA+2) raw = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - self.MODE) return raw def calcTemperaturePressure(self): ''' 温度と気圧を算出 ''' UT = self.readUncpmpensatedTemp() UP = self.readUncpmpensatedPressure() X1 = ((UT - self.cal_AC6) * self.cal_AC5) / 32768 X2 = (self.cal_MC * 2048) / (X1 + self.cal_MD) B5 = X1 + X2 B6 = B5 - 4000 X1 = (self.cal_B2 * (B6 * B6) / 4096) / 2048 X2 = (self.cal_AC2 * B6) / 2048 X3 = X1 + X2 # 温度を算出しておく temp = (B5 + 8) / 16 / 10 B3 = (((self.cal_AC1 * 4 + X3) * ( 2 ** self.MODE)) + 2) / 4 X1 = (self.cal_AC3 * B6) / 8192 X2 = (self.cal_B1 * ((B6 * B6) / 4096)) / 65536 X3 = ((X1 + X2) + 2) / 4 B4 = (self.cal_AC4 * (X3 + 32768)) / 32768 B7 = (UP - B3) * (50000 >> self.MODE) if (B7 < 0x80000000): press = int((B7 * 2) / B4) else: press = int((B7 / B4) * 2) X1 = (press / 256 ) * (press / 256) X1 = (X1 * 3038) / 65536 X2 = (-7357 * press) / 65536 press = press + ((X1 + X2 + 3791) / 16) return temp, press class LCD1602: ''' LCD ''' LCD_LINES = [0x80, 0xC0] # LCDの1行目のアドレス LCD_LINE_1 = 0x80 # LCDの2行目のアドレス LCD_LINE_2 = 0xC0 # 1行あたりの文字数 LCD_WIDTH = 16 # バックライトのON/OFF(ON:0X08, OFF:0X00を指定) LCD_BACKLIGHT = 0X08 LCD_CHR = 1 LCD_CMD = 0 ENABLE = 0b00000100 E_PULSE = 0.0005 E_DELAY = 0.0005 I2C_ADR = 0x27 i2c = None def __init__(self) -> None: ''' コンストラクタ ''' # i2cオブジェクト self.i2c = i2c(self.I2C_ADR) def calibration(self): ''' キャリブレーション ''' self.writeByte(0x33, self.LCD_CMD) self.writeByte(0x32, self.LCD_CMD) self.writeByte(0x06, self.LCD_CMD) self.writeByte(0x0C, self.LCD_CMD) self.writeByte(0x28, self.LCD_CMD) self.writeByte(0x01, self.LCD_CMD) sleep(self.E_DELAY) def writeByte(self, bits, mode): ''' LCDへの書き込み ''' bits_high = mode | (bits & 0xF0) | self.LCD_BACKLIGHT bits_low = mode | ((bits << 4) & 0xF0) | self.LCD_BACKLIGHT self.i2c.writeByte(bits_high) self.writeByteSub(bits_high) self.i2c.writeByte(bits_low) self.writeByteSub(bits_low) def writeByteSub(self, bits): ''' LCDへの書き込み(サブ) ''' sleep(self.E_DELAY) self.i2c.writeByte(bits | self.ENABLE) sleep(self.E_DELAY) self.i2c.writeByte(bits & ~self.ENABLE) sleep(self.E_DELAY) def dispString(self, message: str, dispLine): ''' LCDへの文字の表示(半角文字列のみ) ''' # 表示対象行の初期化 self.writeByte(self.LCD_LINES[dispLine], self.LCD_CMD) # 文字列を1行あたりの文字数に調整 message = message.ljust(self.LCD_WIDTH) # 表示処理 for dispIndex in range(self.LCD_WIDTH): self.writeByte(ord(message[dispIndex]), self.LCD_CHR) import socket import psutil import datetime class RaspiInfo: ''' RaspberryPi情報 ''' @staticmethod def getMemoryInfo(): ''' メモリ情報(使用量[MB]、総量[MB])の取得 ''' mem = psutil.virtual_memory() mem_used = round(mem.used / 1024 / 1024) mem_total = round(mem.total / 1024 / 1024) return mem_used, mem_total @staticmethod def getCpuTemp(): ''' CPU温度の取得 ''' f = open("/sys/class/thermal/thermal_zone0/temp","r") cpu_temp = 0 for t in f: cpu_temp = t[:2] # 小数点以下2桁まで表示する場合 # cpu_temp = t[:2]+"."+t[2:3] f.close() return cpu_temp @staticmethod def getCpupercent(): ''' CPU使用率の取得 ''' cpu_percent = psutil.cpu_percent(interval=0) return round(cpu_percent) @staticmethod def getHostName(): ''' ホスト名の取得 ''' host_name = socket.gethostname() return host_name @staticmethod def getIP(): ''' IPアドレスとインターフェース名を取得 ''' for interface, snics in psutil.net_if_addrs().items(): for snic in snics: if snic.address != '127.0.0.1' and snic.family == socket.AF_INET: return snic.address, interface return "none", "none" # メイン処理 # LCDの初期化 lcd = LCD1602() lcd.calibration() # インスタンス生成 bmp = BMP085() sht3x = SHT3X() # 初期化 bmp.calibration() while True: # 現在日時 now = datetime.datetime.now() lcd.dispString(f'date: {now.strftime("%Y/%m/%d")}', 0) lcd.dispString(f'time: {now.strftime("%H:%M:%S")}', 1) sleep(1) # 「CPU温度」「CPU使用率」と「メモリ情報」 mem_info = RaspiInfo.getMemoryInfo() lcd.dispString(f'cpu : {RaspiInfo.getCpuTemp()}\337C {RaspiInfo.getCpupercent()}%', 0) lcd.dispString(f'mem : {mem_info[0]}/{mem_info[1]}MB', 1) sleep(1) # ホスト名 hostName = RaspiInfo.getHostName() lcd.dispString(f'host:', 0) lcd.dispString(f' {hostName}', 1) sleep(1) # IPアドレス ip = RaspiInfo.getIP() lcd.dispString(f'ip :', 0) lcd.dispString(f'{str(ip[1])}:', 0) lcd.dispString(f' {ip[0]}', 1) sleep(1) # 温度と大気圧(次の取得処理中でスリープしているので、ここでの表示後のスリープはしない) tempPress = bmp.calcTemperaturePressure() lcd.dispString(f'temp: {str(tempPress[0])[:5]}\337C', 0) lcd.dispString(f'prss: {str(tempPress[1] / 100.0 )[:6]} hPa', 1) # 温度と湿度 ht = sht3x.calcTemperatureHumidity() lcd.dispString(f'temp: {str(ht[0])[:5]}\337C', 0) lcd.dispString(f'humi: {str(ht[1])[:5]}%', 1) sleep(1)