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 上に出力します)
# i2c_address_scan.py
#
# I2C バスをスキャンして接続されているデバイスのアドレスを表示する
# ───────────────────────────────────────────
from machine import I2C, Pin
# I²C1 (SDA=GP14, SCL=GP15, 100 kHz) を使用
i2c = I2C(1, sda=Pin(14), scl=Pin(15), freq=100_000)
# スキャン実行
devices = i2c.scan()
# 結果を表示
if devices:
print("検出した I²C デバイスのアドレス:")
for addr in devices:
print(" •", hex(addr))
else:
print("I²C デバイスが見つかりません。配線やプルアップ抵抗を確認してください。")
>>> %Run -c $EDITOR_CONTENT
MPY: soft reboot
検出した I²C デバイスのアドレス:
• 0x27
>>>
LCDに表示するコード
from machine import I2C, Pin
from utime import sleep
# ── I²C 設定(I2C1, SDA=GP14, SCL=GP15)──────────────
i2c = I2C(1, sda=Pin(14), scl=Pin(15), freq=100_000)
# ── LCD/PCF8574A 関連定数 ──────────────────────────
LCD_ADDR = 0x27 # モジュールの I²C アドレス(基板により 0x3F の場合も)
LCD_EN = 0x04 # Enable ビット
LCD_BL = 0x08 # バックライト ON
CMD = 0x00 # コマンドモード
CHR = 0x01 # 文字モード
LINE1 = 0x80 # 1 行目の先頭アドレス
LINE2 = 0xC0 # 2 行目の先頭アドレス
buf = bytearray(2) # I²C 送信用バッファ(2 バイト)
# ── 4 ビット・データ送信関数 ────────────────────────
def lcd_write(bits, mode):
# 上位 4 ビット
data = (bits & 0xF0) | mode
buf[0] = data | LCD_EN | LCD_BL # EN=1
buf[1] = data | LCD_BL # EN=0
i2c.writeto(LCD_ADDR, buf)
sleep(0.0001)
# 下位 4 ビット
data = ((bits << 4) & 0xF0) | mode
buf[0] = data | LCD_EN | LCD_BL
buf[1] = data | LCD_BL
i2c.writeto(LCD_ADDR, buf)
sleep(0.0001)
# ── LCD 初期化 ─────────────────────────────────────
def lcd_init():
lcd_write(0x33, CMD) # 初期化シーケンス 1
lcd_write(0x32, CMD) # 初期化シーケンス 2
lcd_write(0x06, CMD) # エントリーモード設定
lcd_write(0x0C, CMD) # 表示 ON, カーソル/ブリンク OFF
lcd_write(0x28, CMD) # 2 行, 5×7 ドット
lcd_write(0x01, CMD) # 画面クリア
sleep(0.002) # クリア後は 1.52 ms 以上待機
# ── 文字列表示 ─────────────────────────────────────
def lcd_print(text):
for ch in text:
lcd_write(ord(ch), CHR)
# ── メイン処理 ─────────────────────────────────────
lcd_init() # LCD を初期化
lcd_write(LINE1, CMD) # 1 行目の先頭にカーソル移動
lcd_print("Hello World!") # 「Hello World!」を表示
lcd_write(LINE2, CMD) # 1 行目の先頭にカーソル移動
lcd_print("RaspberryPiPicoW") # 「Hello World!」を表示
# 以上で完了。以降コードが続かない限り、表示はそのまま残ります。

アドレスを自動検出して表示するコード
# Raspberry Pi Pico W + MicroPython
# I²C 接続 1602 LCD(HD44780 + PCF8574A)
# 「Hello World!」を 1 行目に表示するだけの最小サンプル
#
# ──────────────────────────────────────────────
from machine import I2C, Pin
from utime import sleep_ms, sleep_us
# ── I²C 設定(I2C1 を GP14/GP15 で使用) ─────────
i2c = I2C(1, sda=Pin(14), scl=Pin(15), freq=100_000)
# ── PCF8574(A) のアドレスを自動検出 ─────────────
_PCF_ADDRS = list(range(0x20, 0x28)) + list(range(0x38, 0x40))
found = [a for a in i2c.scan() if a in _PCF_ADDRS]
if not found:
raise OSError("PCF8574(A) が見つかりません。配線とプルアップ抵抗を確認してください。")
LCD_ADDR = found[0] # 見つかった最初のデバイスを採用
# ── LCD / PCF8574A ビット定義 ───────────────────
LCD_EN = 0x04 # Enable
LCD_BL = 0x08 # Back‑Light 常時 ON
CMD = 0x00 # コマンドモード
CHR = 0x01 # 文字モード
LINE1 = 0x80 # 1 行目アドレス
LINE2 = 0xC0 # 2 行目アドレス
_buf = bytearray(2) # 2 バイトバッファ(EN=1 → EN=0)
# ── 4 ビットデータ送信 ──────────────────────────
def _lcd_write(nibble, mode):
# 上位 4 ビット
data = (nibble & 0xF0) | mode | LCD_BL
_buf[0] = data | LCD_EN # EN = 1
_buf[1] = data # EN = 0
i2c.writeto(LCD_ADDR, _buf)
sleep_us(50)
# 下位 4 ビット
data = ((nibble << 4) & 0xF0) | mode | LCD_BL
_buf[0] = data | LCD_EN
_buf[1] = data
i2c.writeto(LCD_ADDR, _buf)
sleep_us(50)
# ── LCD 用ラッパ ────────────────────────────────
def _cmd(value): _lcd_write(value, CMD)
def _char(value): _lcd_write(value, CHR)
# ── 初期化シーケンス ────────────────────────────
def lcd_init():
sleep_ms(50) # 電源 ON 待ち
_cmd(0x33) # 8‑bit → 8‑bit
_cmd(0x32) # 8‑bit → 4‑bit
_cmd(0x06) # エントリーモード:左→右、自動インクリメント
_cmd(0x0C) # 表示 ON, カーソル OFF, ブリンク OFF
_cmd(0x28) # 2 行, 5×7 ドット
_cmd(0x01) # ディスプレイクリア
sleep_ms(2)
# ── 文字列表示(行番号は 0 or 1) ────────────────
def lcd_print(text, line=0, pos=0):
addr = (LINE1 if line == 0 else 0xC0) + pos
_cmd(addr)
for ch in text:
_char(ord(ch))
# ──────────────────────────────────────────────
# メイン
lcd_init()
lcd_print("Hello World!", line=0, pos=0)
lcd_print("RaspberryPiPicoW", line=2, pos=0)
# ここで終了。LCD の内容は電源を切るまで保持されます。
処理の流れ
🔌 I²C バスをセットアップ
🔍 PCF8574A のアドレスをスキャン
🪛 LCD 制御用ビット定義を準備
LCD_EN
, LCD_BL
, CMD
, CHR
, LINE1
, LINE2
などの定数を用意。
2 バイトの送信用バッファ _buf
を確保。
✉️ 4 ビットデータ送信関数 _lcd_write()
を実装
🛠️ コマンド/データ送信ラッパを定義
⚙️ LCD 初期化 lcd_init()
を実行
🖊️ 文字列表示 lcd_print()
を定義
🚀 メイン処理
lcd_init()
で LCD を初期化。
lcd_print("Hello World!", 0, 0)
で 1 行目に「Hello World!」。
lcd_print("RaspberryPiPicoW", 1, 0)
で 2 行目に「RaspberryPiPicoW」。
💤 スクリプト終了後も表示は保持
0 件のコメント:
コメントを投稿