rcmdnk's blog

20220618_lcd5_200_200

Raspberry Pi Zeroを使って室温や湿度、二酸化炭素濃度などを測定していますが、 取った記録はBlinkというアプリを使ってみるかGoogle Sheetsに記録したものを何らの方法で見る感じになっています。

やはり直接見れたらうれしい、ということでディスプレイを付けてみました。

Raspberry Pi Zeroで測っているもの

BME280とMH-Z19Cという素子を使って室温と湿度、気圧、二酸化炭素濃度を測っています。

とった記録はBlynkというアプリでスマホで見れるようになっています。

もしくはGoogle Sheetsにも書き込んでいるので、データポータルとかでグラフを見ることも出来ます。

とはいえ、普通温度計とかはそれ自身が測った値を表示してくれるものがほとんどなのでそれを実現してみます。

LCD

今回買ってみたのはこれ。

横20文字、縦4文字が表示できる液晶ディスプレイ(LCD, Liquid Crystal Display)です。

また、I2Cシリアルインターフェースモジュールがあらかじめはんだ付けされているものになっています。

個のセットで1,000円ほど。

サイズ的には横16文字、縦2文字の1602 LCDもよく売られています。

実際に買ってみたのがこれですが、

20220618_lcd0.jpg

裏のモジュールの付け方がなんか斜めになっている。。。

20220618_lcd1.jpg

はんだ付け直そうかと一瞬思うくらいでしたが、現状では箱に詰めたりするわけでもないので一旦このままいきます。

Raspberry Piとの接続

I2Cのモジュールがついているので、Raspberry Piとの接続は

LCD側 Raspberry Pi GPIO
GND PIN 20 (Ground)
VCC PIN 1 (3.3V)
SDA PIN 3 (SDA)
SCL PIN 5 (SCL)

GPIO and the 40-pin Header

といった感じで4本つなぐだけでOK。

20220618_lcd2.jpg

この右側のとこに線が出ているので、ジャンパーケーブルとかで適当につないであげます。

すでにBME280が3.3VのPIN1, PIN17、及びSDA/SCLのPIN 3/5とつながっていますが、 1, 3, 5に関しては同じところにつなぎます。

I2Cでは通信に使うための認識のアドレスがあって、複数つないでも違うアドレスを使えば同時に使えるとのこと。

いろいろ基盤にはんだ付けしてつないだのでそこにつなぎます。

こんな感じに。

20220618_lcd3.jpg

なんかもうちょっと最初からやりなおしたいところですが、面倒なので後付工事で。

上の画像だと実は出力が弱い状態で、I2Cのモジュールについている青い部分にドライバで回せる部分があって、 これを右に回していくと出力が強くなります。

20220618_lcd4.jpg

こんな感じでつないだ直後は1段目と3段目に白い四角が見えるような状態になっています。

実際につないでI2Cの状態を見てみると

title lang:
1
2
3
4
5
6
7
8
9
10
$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --

こんな感じで接続しているものが見られ、0x76のものがBME280、0x27がLCDです。

For PCF8574T chip, I2C address format: 0 0 1 0 0 A2 A1 A0. The default address is: 0x27
For PCF8574 chip, I2C address format: 0 0 1 1 1 A2 A1 A0. The default address is: 0x3F
If you want to modify the default address, just need connect pinA0, A1, A2 to GND respectively.
For PCF8574T chip, I2C address range: 0x20-0x27
For PCF8574 chip, I2C address range: 0x38-0x3F
If you are not sure, you can use the above code to scan the changed address.

ということで、今回買ったものは上の写真の真ん中に乗ってる素子を見てもらうと分かる通りPCF8574Tで、 0x27がdefault addressになっています。

最初が00100111(=39=0x27)な状態で、下位3bitがA2, A1, A0に対応して、右下にある対応する部分を はんだ付けして短絡するとその部分が0になります。 例えば、A0とA1をそれぞれ短絡させると00100100(=36=0x24)になります。

従って全部で8種類のアドレスを使えます。

PCF8574も含めれば全部で16種類になり、16個のLCDを1つのRaspberry Piで操作することも可能です。

ただ、この素子の型は上のAmazonのものだと選べないので16個フルに使おうと思うとちょっと素子を直接仕入れる必要があるかも知れません。

LCDへの表示

上の参照ページに PCF8574の データシート が公開されていますが、ここから色々読み取るのは結構大変そう。

C++用のライブラリ も公開されてるので、この辺を見てコマンドのアドレスとかを調べたほうがわかりやすいかも。

今回はPythonで使ってみたいわけですが、 探してみるといい感じのライブラリが色々あるので使わせてもらいます。

rpi-lcd · PyPI

これを使わせてもらいました。

1
2
3
4
5
6
from rpi_lcd import LCD
from time import sleep


lcd = LCD()
lcd.text('Hello World!', 1)

で一行目にHello World!が表示されます。簡単。

デフォルトの値として、I2Cのアドレスが0x27になっているので、もし違うアドレスであればLCD(address=0x24)とかで 初期化する必要があります。

1602でも使うことが出来て、その場合は LCD(width=16, rows=2)と変更します。

測定値の表示

測定値をファイルに書き出しておいて、一定時間ごとにそれを読み取って表示させる、という方法にしました。

BME280の測定は毎分以下のスクリプトを動かしてGoogle Sheetsに入力しています。

raspi_setup/bme280 at main · rcmdnk/raspi_setup

ここで、 tsd2gspread というGoogle Sheetsに書き込むための自作モジュールを使っていて、 その中で値をローカルのファイルにも書き込むようにしました。

で、以下のスクリプトで書き出した記録を拾ってまとめて表示させています。

raspi_setup/clock at main · rcmdnk/raspi_setup

ちょっとしたtipsとして、一定間隔ごとにループを回したいとき、 ループの最後でsleep(1)とかするとちょっとずつずれてしまうので、 ループの最初で、

1
2
3
4
5
6
7
8
9
    clock = datetime.now().replace(second=0).replace(microsecond=0)
    while True:
        clock = clock + timedelta(minutes=1)
        now = datetime.now()
        if now > clock:
            clock = now.replace(second=0).replace(microsecond=0)
        else:
            sleep((clock - datetime.now()).total_seconds())
        ...

みたいな感じで必要な分だけ待つようにすると良い感じになります。

python - How to make a proper server tick? - Stack Overflow

このスクリプトは systemdで管理 して起動していますが、 1分おきであればBME280とかでやってるように毎回終了させてtimerで動かしたほうが良いかも。

raspi_setup/bme280.service at main · rcmdnk/raspi_setup raspi_setup/bme280.timer at main · rcmdnk/raspi_setup

最初時計部分だけ秒で変えていこうと思ってたので上のようなスクリプトになっている、ということもあったりします。

現状の表示

現状こんな感じで表示されています。

20220618_lcd5.jpg

  • 1段目: 時計
  • 2段目: アメダスによる外気温の測定値(毎時更新)
  • 3段目: BME280の測定値(室温、湿度)
  • 4段目: MH-Z19の測定値(二酸化炭素濃度)

かなりいい感じにできました。

を表示させたかったんですが、この文字が入ってないみたいなのでCで代用しています。

測定値自体に関しては、以前もちょっと調べましたが、やはりBME280の湿度は10%位低すぎる感じです。 温度はほかと比べて+/-1,2度で、これは低いときもあるので校正が難しい。。。

二酸化炭素は500ppmを下回るとMH-Z19Cは下がりづらい傾向がありますが、500~1000ppmくらいだと 左にあるPTH-8とだいたい同じ(+/-20ppm程度)にはなっています。

やはり湿度は調整しようか考え中。

LCD表示を行ごとに変更することに関して

最初、BME280とかの測定を行っているスクリプトの中で直接必要な部分だけを変更しようとしていました。

rpi-lcdIだと、コンストラクタの中で、 self.write(CLEAR_DISPLAY)と一旦全部消してしまうので、 以下みたいなラッパークラスを作って

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from time import sleep
from rpi_lcd import LCD


class LCDNoInitClear(LCD):

    def __init__(self, address=0x27, bus=1, width=20, rows=4, backlight=True):
        self.address = address
        self.bus = SMBus(bus)
        self.delay = 0.0005
        self.rows = rows
        self.width = width
        self.backlight_status = backlight

        self.write(0x33)
        self.write(0x32)
        self.write(0x06)
        self.write(0x0C)
        self.write(0x28)
        self.write(CLEAR_DISPLAY)
        sleep(self.delay)

以下のように必要な行を書き換えるみたいなことをしていました。

1
2
    lcd = LCDNoInitClear()
    lcd.text('...', 2)

ただ、なにかconflictがあるのか、最初にclearしないと良くないのか、 表示が乱れてしまうことがありやめました。

ほんとは時計も秒をつけて1秒ごとに動かしたかったんですが、 1秒ごとに全部書き換えると表示がくずれることもあり、 一旦1分ごとに時計も測定値も更新するようにしています。

まとめ

測定値を表示させたいとはずっと思っていたもののなかなか取り組めなかったですが、 やってみたらかなり簡単にできました。

LCDもこれで1,000円位なので次にRaspberry Piとかでなにか作るときにもとりあえず付けて 色々表示できるようにしておけば良いんじゃないかと思ってます。

せっかくなのでちゃんとケースに収まるようにしたいなとも思ってますが、 自分で欲しい物をと思ったら、3Dプリンタとかで作りたい。。。 (でも3Dプリンタを他にそこまで使いこなせる自信がない。。。)

Sponsored Links
Sponsored Links

« SwitchBotカーテン第二世代の進化 気象庁アメダスの情報をRaspberry Piで取得して表示する »