前回は、1602 LCD をビットパラレルモード(4ビットデータ通信)で直接制御しました。これは LCD の各制御線(RS、EN、D4〜D7など)を Raspberry Pi Pico W の GPIO に1本ずつ接続して動かす方法で、仕組みを理解するにはとても勉強になります。
しかし、この方法では接続に使うピンが多くなり、GPIOの数が限られている小型マイコンでは少し不便に感じることもあります。
そこで今回は、**PCF8574A という I/O エクスパンダ(拡張チップ)**を使って、I²C(アイ・スクエアド・シー)通信で LCD を制御する方法を紹介します。この方法を使うと、LCD の操作に必要な信号を **わずか2本の通信線(SDA と SCL)**にまとめられるため、配線がとてもスッキリし、他のセンサーやデバイスとの接続も簡単になります。
初心者の方でも、I²C の基本を学びながら、LCD 表示の実用的な使い方にステップアップできる内容になっています。マイコンの入出力ピンを節約しつつ、LCD にメッセージを表示したい方にぴったりの方法です。
PCF8574A と I²C って何?
PCF8574A
PCF8574A は NXP 製の “I/O エクスパンダ” と呼ばれる IC で、
-
8 本の GPIO を I²C でまとめて増設できる
-
各ピンは入力にも出力にも使える “擬似オープンドレイン” 方式
-
アドレスピン(A2–A0)の組み合わせで 0x38 – 0x3F の 8 通りの I²C アドレスを選択可能
今回の 1602 LCD では、PCF8574A の 8 本を下図のように割り当てるのが定番です。
PCF8574A ピン | LCD 信号 | 役割 |
---|---|---|
P0 | RS | データ/コマンド切替 |
P1 | RW | 読み書き切替(通常は GND = 書き込み専用) |
P2 | EN | イネーブルパルス |
P3 | BL | バックライト ON/OFF |
P4–P7 | D4–D7 | 4 ビットデータバス |
I²C(Inter‑Integrated Circuit)
I²C は 1980 年代に Philips(現 NXP)が開発した 2 線式のシリアル通信規格で、
-
SDA(データ線) と SCL(クロック線) だけで通信
-
7 ビットまたは 10 ビットの アドレスでデバイスを識別
-
マスター(Pico W) がクロックを生成し、スレーブ(PCF8574A など) に読み書き要求を出す
-
複数デバイスを同じ SDA/SCL に “バス” でぶら下げられる(プルアップ抵抗が必須)
初心者が最初につまずきやすいポイントは「プルアップ抵抗がないと信号が正しく High にならない」ことですが、多くの市販 I²C‑LCD モジュールには 4.7 kΩ 付近の抵抗が実装済みなので安心です。
回路図
PicoWのI2Cポートは、id=1,SDA=GP14,SCL=GP15を利用
Raspberry Pi Pico W + MicroPython で I²C バスをスキャンし、
見つかったデバイスのアドレスを 16 進数表記でターミナルに表示するだけの最小サンプルです。
(LCD には表示せず、シリアル REPL 上に出力します)
LCDに表示するコード
アドレスを自動検出して表示するコード
処理の流れ
-
🔌 I²C バスをセットアップ
-
I2C(1, sda=GP14, scl=GP15, freq=100 kHz)
で Pico W の I²C1 を初期化。
-
-
🔍 PCF8574A のアドレスをスキャン
-
i2c.scan()
でバス上の全デバイスを検索し、
0x20–0x27
または0x38–0x3F
の範囲にある最初のアドレスを LCD_ADDR として確定。
-
-
🪛 LCD 制御用ビット定義を準備
-
LCD_EN
,LCD_BL
,CMD
,CHR
,LINE1
,LINE2
などの定数を用意。 -
2 バイトの送信用バッファ
_buf
を確保。
-
-
✉️ 4 ビットデータ送信関数
_lcd_write()
を実装-
上位 4 ビット → EN パルス → 下位 4 ビット → EN パルス。
-
各トグル後に
sleep_us(50)
で 50 µs 待機。
-
-
🛠️ コマンド/データ送信ラッパを定義
-
_cmd(value)
はコマンドモード、_char(value)
は文字モードで_lcd_write()
を呼び出す。
-
-
⚙️ LCD 初期化
lcd_init()
を実行-
電源投入待ち(50 ms)。
-
8‑bit → 8‑bit → 4‑bit の初期化シーケンス。
-
表示設定(エントリー、表示 ON、2 行モード)。
-
画面クリア後、2 ms 待機。
-
-
🖊️ 文字列表示
lcd_print()
を定義-
行番号(0 or 1)と桁位置を元に DDRAM アドレスを計算し、
_cmd()
でカーソル移動。 -
文字列を 1 文字ずつ
_char()
で送信。
-
-
🚀 メイン処理
-
lcd_init()
で LCD を初期化。 -
lcd_print("Hello World!", 0, 0)
で 1 行目に「Hello World!」。 -
lcd_print("RaspberryPiPicoW", 1, 0)
で 2 行目に「RaspberryPiPicoW」。
-
-
💤 スクリプト終了後も表示は保持
-
ループを回さないためプログラムは終了するが、LCD の内容は電源を切るまでそのまま残る。
-
コメント
コメントを投稿