今回は LCD1602(16 文字 × 2 行の液晶ディスプレイ)に文字を表示します。前回(#07)の 7セグメント LED は数字 1 文字を出すのに 8 本のピン が必要でしたが、LCD なら I2C 通信 を使って VCC・GND・SDA・SCL の 4 本だけ で繋がります。しかも 文字列 が表示できるので、センサー値・メッセージ・カウンタなどを直接読めるディスプレイになります。
- I2C 通信の仕組み(SDA・SCL の 2 本で複数デバイスと通信)
- LCD1602 の配線(VCC・GND・SDA・SCL の 4 本だけ)
pico_lcd_init・pico_lcd_print・pico_lcd_clearの使い方- Hello World、2 行表示、カウンタ、スプラッシュメッセージなどの応用
PycoBlocks(MicroPythonモード) を開き、左カテゴリ「Pico 電子工作 / 表示」の「LCD初期化」「LCDに表示」「LCDをクリア」 ブロックが今回の主役です。I2C アドレスは 0x27(ELEGOO 互換 LCD のデフォルト)を前提に話を進めます。

I2C 通信の仕組み:2 本の信号線で何台ものデバイスと通信
I2C(Inter-Integrated Circuit、アイ・スクエア・シー)は、Philips(現 NXP)が開発したシリアル通信 規格です。1 対 1 ではなく 1 台のマスター(Pico)と複数のスレーブ(LCD・温湿度センサー・加速度センサーなど)が 同じ 2 本の線(SDA・SCL)を共有して通信できるのが最大の特徴です。
| 信号線 | 正式名称 | 役割 | Pico 側 |
|---|---|---|---|
| SDA | Serial DAta | データ本体(読み書き) | GP0(I2C0)・GP2(I2C1)など |
| SCL | Serial CLock | マスターが叩くクロック信号 | GP1(I2C0)・GP3(I2C1)など |
| VCC | — | 電源(3.3V または 5V) | 3V3 ピン(または VBUS) |
| GND | — | 共通グランド | GND ピン |
下の図のように、LCD と Pico は VCC・GND・SDA・SCL の 4 本だけ でつながります。7セグメント LED が a〜g+コモンで 8 本必要だったのと比べると、配線が一気にスッキリします。

📝 I2C アドレスとは
0x27 さん、こんにちは」とアドレス指定で呼びかけ、その時だけ該当デバイスが応答する仕組み。LCD1602 の I2C バックパックは 0x27 または 0x3F が標準(基板上のジャンパで切替可能)。7セグメント LED との比較:前回の 7セグでは a〜g の 7 本+コモン 1 本=合計 8 本 もの配線が必要でした。LCD(パラレル接続なら 8 本+電源で 10 本以上)を I2C なら 4 本だけで繋げます。残りの GPIO がそっくり空く ので、ボタン・センサー・サーボなどを同時に使う設計の自由度が一気に上がります。
ステップ1:LCD に「Hello, Pico!」を表示しよう
まずは LCD の 1 行目に 「Hello, Pico!」 を表示してみましょう。ブロックは 「LCD初期化」(SDA・SCL ピンと使う変数名を指定)と 「LCDに表示」(行と文字列を指定)の 2 つだけで動きます。


from machine import Pin, I2C
from lcd1602 import LCD1602
_i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = LCD1602(_i2c, 0x27)
lcd.move_to(0, 0)
lcd.putstr((str("Hello, Pico!") + " " * 16)[:16])
コードのポイント:I2C(0, sda=Pin(0), scl=Pin(1)) で I2C0 バス を初期化(Pico には I2C0・I2C1 の 2 系統あります)。LCD1602(_i2c, 0x27) でアドレス 0x27 の LCD を制御するオブジェクトを作り、move_to(列, 行) でカーソル移動 → putstr で文字列を書き込みます。+ " " * 16 と [:16] は 16 文字に揃える(短い文字列には空白を足し、長い文字列は切り捨て)ためのおまじないで、ブロック側が自動でやってくれます。パソコンの Python なら ljust(16) と書けますが、MicroPython の文字列に ljust はありません(実行すると AttributeError で止まります)。そのため空白を足してから切る形になっています。
lcd1602.py について:MicroPython 標準ライブラリには LCD1602 のドライバが含まれていないので、事前に lcd1602.py を Pico にコピー しておく必要があります。Thonny の「ファイル」ペインから Pico の / ルートに保存すれば、from lcd1602 import LCD1602 が使えるようになります。ドライバは RPi-PICO-I2C-LCD や micropython-lcd1602 で検索すれば GitHub に多数公開されています。
ステップ2:2 行をフル活用して情報を増やそう
LCD1602 の「1602」は 16 文字 × 2 行 を意味します。1 行目だけでなく 2 行目 も使えば、「タイトル+値」「センサー名+計測値」のような 2 段組レイアウト が可能です。

from machine import Pin, I2C
from lcd1602 import LCD1602
_i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = LCD1602(_i2c, 0x27)
lcd.move_to(0, 0)
lcd.putstr((str("Hello, Pico!") + " " * 16)[:16])
lcd.move_to(0, 1)
lcd.putstr((str("I2C is amazing") + " " * 16)[:16])
行の指定:ブロックの「行」プルダウンは 「1行目」「2行目」 と日本語ですが、内部的には move_to(0, 0)(1 行目)/move_to(0, 1)(2 行目)と 0 始まり です。コンピューターの世界では「最初」は 1 ではなく 0(リストの先頭インデックスも 0)。これは Python の流儀です。
16 文字を超える場合:I2C is amazing は 14 文字なのでギリギリ収まりますが、I2C communication is great のような 16 文字を超える文字列は 後ろが切り捨て られます。長い文を表示したいときは スクロール表示 を自作するか、2 行に分割 して工夫します。
ステップ3(コラム):I2C アドレスとセンサー連携への発展
I2C は 同じ 2 本の線 に 複数のデバイス をぶら下げられるのが最大の魅力です。LCD1602 だけでなく、気圧センサー(BMP280)・加速度センサー(MPU6050)・RTC(DS3231)・OLED(SSD1306)・ADC 拡張(ADS1115) など、Pico の GPIO を使い切ったあと でも I2C なら追加デバイスをぶら下げ続けられます。
💡 LCD が反応しないとき:I2C アドレスを確認しよう
0x27 でない 可能性がある。下のコードを Thonny で実行 すると、I2C バスに繋がっているデバイスのアドレスを 一覧表示 できる。from machine import Pin, I2C
_i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
devices = _i2c.scan()
print('Found I2C devices:', [hex(d) for d in devices])
# 例:Found I2C devices: ['0x27']
i2c.scan() は 0x08〜0x77 のすべてのアドレスに「いる?」と呼びかけ、応答したデバイスのアドレスをリストで返します。結果が ['0x3F'] なら、コードの 0x27 を 0x3F に書き換えてください。
⚠️ I2C バスの注意点
- プルアップ抵抗:SDA・SCL は オープンドレイン信号なので、本来はプルアップ抵抗が必要です。ただし I2C バックパック付き LCD や Pico の内蔵プルアップでほぼ動くため、本記事では省略しています。
- 電圧レベル:Pico は 3.3V ロジックですが、LCD1602 のバックパックは 5V 推奨 のものもあります。VCC を VBUS(5V) に繋ぐ場合は SDA・SCL のロジックが 5V↔3.3V のミスマッチになる可能性があります。多くの I2C バックパックには レベル変換 が入っているので動きますが、心配なら 3V3 接続を選ぶのが安心です。
- I2C0 と I2C1 の使い分け:Pico には I2C0(GP0/GP1) と I2C1(GP2/GP3) の 2 系統あります。「センサーは I2C0、LCD は I2C1」のように バスを分けて 衝突を避ける設計もできます。
カスタム文字:LCD1602 には 8 個の自作キャラクター を登録できる機能があり、ハート♥・温度計🌡・スマイル☺ などのオリジナル絵文字を表示できます。lcd.custom_char(位置, パターン配列) のようなドライバ拡張で対応可能。発展編で扱います。
演習課題
課題3-8-1:I2C 通信の長所と短所を整理しよう
I2C 通信を使う メリット と デメリット を、前回までで学んだ パラレル通信(GPIO 個別出力で 7セグや LED を制御するやり方) と比較しながら、それぞれ 2 つずつ 挙げてみよう。
ヒント:配線本数・速度・対応デバイス数・複雑さ・ノイズ耐性・コストなど、色々な観点があります。
▶ 模範解答と解説を見る
# I2C のメリット
# 1. 配線が少ない(SDA + SCL の 2 本だけで何台でも繋げる)
# 2. デバイスのアドレス指定で個別制御できる(衝突しない)
# (他にも:標準化されているので互換デバイスが豊富、配線がシンプルでミスが少ない)
# I2C のデメリット
# 1. パラレル通信より遅い(標準モード 100kHz、高速モード 400kHz)
# 2. プルアップ抵抗が必要、長距離配線は苦手(ノイズに弱い)
# (他にも:同一バスにアドレス重複のデバイスは繋げない、初期化が複雑)
# 使い分けの目安:
# - リアルタイム性・速度重視 → パラレル (LED 直接駆動など)
# - 複数デバイス・配線節約 → I2C (LCD、センサー類)
# - 中距離・高速通信 → SPI (SD カード、TFT 液晶)
解説: 解説:I2C の最大の魅力は 「ピンを節約できる」 こと。Pico の GPIO は 26 本 しかないので、センサーを 5 種類使うだけでパラレル接続だと GPIO が枯渇しますが、I2C なら 2 本+電源 2 本 で 5 種類全部繋がります。速度の比較:
- パラレル GPIO 直接駆動:CPU クロック近く(数 MHz)
- I2C 標準モード:100 kHz(≒ 1 ピン 100k 回/秒)
- I2C 高速モード:400 kHz
- SPI(次回以降):数十 MHz まで可能
課題3-8-2:LCD で自己紹介しよう(カウンタ表示)
1 行目に「Count:」と固定表示し、2 行目に 0 から 9 まで 0.5 秒ごとに数字をカウントアップ しよう。ブロックの「LCD に表示」の 値スロット には 変数ブロック もそのまま入れられます(内部で str() 変換される)。「N 回繰り返す」ブロックを使うとシンプルに書けます。
▶ 模範解答と解説を見る
ブロックの組み合わせ例:

from machine import Pin, I2C
from lcd1602 import LCD1602
import utime
_i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = LCD1602(_i2c, 0x27)
lcd.move_to(0, 0)
lcd.putstr((str("Count:") + " " * 16)[:16])
for i in range(10):
lcd.move_to(0, 1)
lcd.putstr((str(i) + " " * 16)[:16])
utime.sleep(0.5)
解説: Python の工夫:(str(i) + " " * 16)[:16] で 整数 i を文字列に変換 してから 16 文字に揃えます。この空白埋めをしないと、前回表示した 「9」の右側に残っていた文字 が消えず、「Count:9」の後に「Count:10」を表示したいときに 「9」の右隣に「0」 が残ってしまうので注意。発展:
- 10 → 20 のカウントアップ:
range(10, 20)に変えるだけ。 - カウンタを 100 まで増やす:
range(100)・間隔を0.1秒に短縮するとデジタル時計の秒表示風になる。 - 可変抵抗(#05)でカウントの速度を変える:
val = pot.read_u16()を読み取り、utime.sleep(val / 65535 * 2)のように待ち時間を計算する。
課題3-8-3:起動メッセージ → 本表示への切替を作ろう
ゲーム機やデジタル機器によくある 「スプラッシュ画面」 風の演出を作ってみよう。1.5 秒間「Welcome! / PycoBlocks」と表示 したあと、画面をクリアして 「Pico is ready! / Press RESET...」 を 2 秒表示し、ずっとループ させよう。「LCDをクリア」 ブロックの使い方がポイント。
▶ 模範解答と解説を見る
ブロックの組み合わせ例:

from machine import Pin, I2C
from lcd1602 import LCD1602
import utime
_i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = LCD1602(_i2c, 0x27)
while True:
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr((str(" Welcome!") + " " * 16)[:16])
lcd.move_to(0, 1)
lcd.putstr((str(" PycoBlocks") + " " * 16)[:16])
utime.sleep(1.5)
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr((str("Pico is ready!") + " " * 16)[:16])
lcd.move_to(0, 1)
lcd.putstr((str("Press RESET...") + " " * 16)[:16])
utime.sleep(2)
解説: レイアウトのコツ:1 行目 ' Welcome!' と 2 行目 ' PycoBlocks' の 先頭に空白を入れる ことで、16 文字中央に文字が来るように調整しています。LCD はモノスペース(等幅)なので、空白を数えれば狙った位置に文字を置けます。clear() の役割:lcd.clear() は 画面全体を空白で埋める 関数で、前回表示の残りカスを消すために使います。発展:
- 3 画面以上のスライドショー:「画面1 → 待機 → 画面2 → 待機 → 画面3 → 待機」のように切替メッセージを増やせば、デジタルサイネージ風の演出ができる。
- ボタン(#03)で切替:
btn.value() == 0で押下を検出して画面を進めれば、説明スライドのリモコンができる。 - センサー値表示:可変抵抗(#05)や温度センサー(#10 で扱う DHT11)の値を LCD に表示すれば、本格的なモニタ装置に。
まとめ
- I2C 通信は SDA・SCL の 2 本+電源 2 本= 4 本だけで複数デバイスと通信できる省ピン規格。
- LCD1602 の I2C アドレスは
0x27または0x3Fが標準。i2c.scan()で確認できる。 pico_lcd_init(変数作成)→pico_lcd_print(行と文字を指定)の順で書く。pico_lcd_clearで全消去。- 表示は 16 文字 × 2 行。ブロック側で自動的に
+ " " * 16→[:16]の 16 文字揃えが入るので残カス対策済み。 - Pico は I2C0(GP0/GP1)と I2C1(GP2/GP3)の 2 系統 あり、バスを分けて衝突回避もできる。
次の記事は #09「超音波で距離を測ろう」。HC-SR04 超音波センサーで距離を測り、今回学んだ LCD と組み合わせて距離計 を作ってみます。電圧レベル(5V → 3.3V 変換)の話も登場します。