秋月電子で購入した RP2040マイコンボード を使って、I2C接続のキャラクタLCD を動かしてみました。
なおこのマイコンボードは純正の Raspberry Pi Pico ではありませんが、同様に扱えるのでラズピコと呼ぶことにします。
使用した LCD はこちらも秋月電子で購入した AQM1602Y-RN-GBW です。
開発には MicroPython を用いましたが、以前に書いた以下の PICマイコン用の C言語のプログラムを移植する形になりました。
MicroPython の I2C ライブラリ
まずは MicroPython の I2C ライブラリについて調べてみると、公式リファレンスの Raspberry Pi Pico-series Python SDK に以下のような項目がありました。
Example usage:
1234567891011 from machine import Pin, I2Ci2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=100000)i2c.scan()i2c.writeto(76, b'123')i2c.readfrom(76, 4)i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=100000)i2c.scan()i2c.writeto_mem(76, 6, b'456')i2c.readfrom_mem(76, 6, 4)Default I2C pins
Function Default I2C Frequency 400,000 I2C0 SCL Pin 9 I2C0 SDA Pin 8 I2C1 SCL Pin 7 I2C1 SDA Pin 6
RP2040 には I2Cモジュールが2つあるようです。今回はI2C0の方を利用してピンはデフォルトのピンを使うことにしました。
I2Cライブラリは machine モジュールを import することで使えるようになります。
詳細は公式ドキュメントを参照してほしいのですが、今回使用した関数だけ軽く紹介します。
I2C.scan()
この関数は接続された I2Cデバイスのアドレスの一覧を表示します。
様々なアドレスに対して送信を行い、応答があるかどうかを調べているようです。開発中にデバイスが生きているかどうかを確認できるので便利です。
I2C.writeto(addr, buf)
I2Cデバイスに対して送信を行う関数です。buf には bytes型 または bytearray型 のオブジェクトを渡します。
bytes型のオブジェクトは以下の方法で作成できます。
- bytesリテラル
文字列リテラルの前に b をつけると bytesリテラルになります。ASCIIコード以外を含めたいときはエスケープシーケンスを使います。
例:b'abc\xff'
- リスト等から変換
例:bytes([1, 2, 3])
- strから変換
Python の通常の文字列を bytes に変換するには str.encode() を使用します。逆に bytes.decode() で bytes から str に変換することもできます。
例:'hello'.encode()
試しにi2c.writeto(0x3e, b'123')
を実行してみたときの波形はこのようになってました。
最初にアドレス 0x3E と書き込みを表す 0、続く3バイトに指定した ‘123’ の文字を表すASCIIコードが並んでいます。
なお、最初のアドレスを送信した段階で応答がない場合は、後続のデータは送信しないで終了するようです。
LCD制御プログラム
LCDに関するプログラムをクラスにまとめました。
LCDのコマンドや初期化の方法については、【PIC】I2CでLCDに文字を表示する をご覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
from machine import I2C, Pin from time import sleep_ms, sleep_us class Lcd_I2c(): def __init__(self, addr=0x3e, contrast=0, id=0, scl=Pin(9), sda=Pin(8), freq=400000): self._i2c = I2C(id, scl=scl, sda=sda, freq=freq) self._addr = addr self._contrast = contrast self.DDRAM_HEAD = [0x00, 0x40, 0x14, 0x54] def send_inst(self, command): self._i2c.writeto(self._addr, bytes([0x00, command])) sleep_us(30) def send_data(self, data): self._i2c.writeto(self._addr, bytes([0x40, data])) sleep_us(30) def init(self): sleep_ms(40) self.send_inst(0x38); #Function Set self.send_inst(0x39); #Function Set self.send_inst(0x14); #Internal OSC Frequency self.send_inst(0x70 + (self._contrast & 0x0f)); #Contrast Set self.send_inst(0x54 + ((self._contrast & 0xf0)>>4)); #Power/ICON/Contrast control self.send_inst(0x6c); #Follower control sleep_ms(200) self.send_inst(0x38); #Function Set self.send_inst(0x0c); #Display ON/OFF control self.send_inst(0x01); #Clear Display sleep_ms(2) def set_cursor(self, row, col): ddram_addr = self.DDRAM_HEAD[row] + col self.send_inst(0x80 + ddram_addr) def print(self, text): for c in text: self.send_data(c) |
テストプログラム
作成した Lcd_I2cクラスを用いて実際に LCD にテキストを表示させるプログラムを作りました。
MicroPython だと f-string といった Python の機能が使えてとても便利だと思いました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from time import sleep_ms from lcd_i2c import Lcd_I2c lcd = Lcd_I2c(contrast=38) lcd.init() lcd.print(b'Hello, RP2040') count = 0 while True: lcd.set_cursor(1, 0) text = f'Counter: {count:3}'.encode() lcd.print(text) count = count + 1 sleep_ms(1000) |
接続方法
LCD とラズピコを I2C で接続するだけなので非常にシンプルです。
SDA と SCL にプルアップ抵抗をつけるのを忘れないようにだけ注意しましょう。
結果
きちんと表示されました。カウンターの値が1秒ごとに更新されるのもちゃんと動いています。