Site cover image

Site icon image電子工作 ~ 50歳の手習い

本職はソフトウェアエンジニア。最近組み込みの仕事がよくあるので勉強がてら楽しんでます。

Raspberry Pi Picoに接続したLCDディスプレイに文字列を表示(MicroPython)【その2】

こんにちは、「MAKO」と言います。

今回の記事は、Raspberry Pi Pico にLCDディスプレイ(LCD1602) を接続し、MicroPythonを用いて文字列を表示する記事の続きを書いてみたいと思います。

前回の記事は、前準備ということでLCD1602のI2Cアドレスを調べるプログラムまででした。

そちらの記事はこちらをご覧ください。

📄Arrow icon of a page linkRaspberry Pi Picoに接続したLCDディスプレイに文字列を表示(MicroPython)【その1】

また、本記事で書いたLCD1602の制御部分をライブラリとして整理した記事については以下をご覧ください。

📄Arrow icon of a page linkRaspberry Pi Picoに接続したLCDディスプレイに文字列を表示(MicroPython)【LCD1602クラス公開】

それでは、実際にLCDに文字列を表示するプログラムを作ってきたいと思います。

最終的にはこちらの画像のように、1行目に「Hello」、2行目に「World」を表示したいと思います。

Image in a image block

今回のプログラムを作成するにあたって、LCD1602の初期化や文字列を表示するためのコマンドを調べるにあたり、本来であればデバイスのデータを読み込むべきところですが、非常に参考にあるサイトがありましたので、こちらを参考にさせていただきました。

注意点としては、LCD1602のデータポートのうち、DB0~DB3は接続されていないことから、このモジュールは常に4ビットモードで使用する必要があるという点でしょうか。

また、初期化の時に4ビットモードに変更するのですが、その際のおまじないとして、

「適切な待機時間を挟んで4ビットで0x3を3回書き込んだ後に0x2を書き込むことで4ビットモードに設定される。」

という点も注意が必要です。

で実際のプログラムですが、とりあえず動いたもので整理も行っていないものになります。

また後日、整理してライブラリかなんかしたものを作ってみようと思います。。。

# 必要なライブラリをインポート
from machine import Pin, I2C
from time import sleep_us

# I2C ピンを定義(自身のセットアップに合わせて変更してください)
i2c_sda_pin = 18
i2c_scl_pin = 19

# LCD1602 の I2C アドレスを定義
lcd_address = 0x3F

# I2CアクセスのWiat時間(基本): 10us
WAIT_BASE = 10

# I2C を初期化
i2c = I2C(1, sda=Pin(i2c_sda_pin), scl=Pin(i2c_scl_pin), freq=100000)

# Write 4bits
def write_4bits(bits):
    buf = bits << 4
    # 0xC: BL=1, E=1, R/W=0, RS=0
    i2c.writeto(lcd_address, bytes([buf | 0x0C]))
    sleep_us(WAIT_BASE)
    # 0xFB: 1011 -> only E=0
    i2c.writeto(lcd_address, bytes([buf & 0xFB]))
 
 # Write one byte command by dividing higher and lower 4bits
def write_command(command):
    # Write higher bits
    # 0xC: BL=1, E=1, R/W=0, RS=0
    buf = command & 0xF0 | 0x0C
    i2c.writeto(lcd_address, bytes([buf]))
    sleep_us(WAIT_BASE)
    # 0xFB: 1011 -> only E=0
    i2c.writeto(lcd_address, bytes([buf & 0xFB]))
    # Write lower bits    
    # 0xC: BL=1, E=1, R/W=0, RS=0
    buf = ((command << 4) & 0xF0) | 0x0C
    i2c.writeto(lcd_address, bytes([buf]))
    sleep_us(WAIT_BASE)
    # 0xFB: 1011 -> only E=0
    i2c.writeto(lcd_address, bytes([buf & 0xFB]))

def write_char(char):
    # Write higher bits
    # 0xD: BL=1, E=1, R/W=0, RS=1
    buf = char & 0xF0 | 0x0D
    i2c.writeto(lcd_address, bytes([buf]))
    sleep_us(WAIT_BASE)
    # 0xFB: 1011 -> only E=0
    i2c.writeto(lcd_address, bytes([buf & 0xFB]))
    # Write lower bits    
    # 0xD: BL=1, E=1, R/W=0, RS=1
    buf = ((char << 4) & 0xF0) | 0x0D
    i2c.writeto(lcd_address, bytes([buf]))
    sleep_us(WAIT_BASE)
    # 0xFB: 1011 -> only E=0
    i2c.writeto(lcd_address, bytes([buf & 0xFB]))

# LCD1602 の初期化
def lcd_init():
    sleep_us(WAIT_BASE*50)
    # Set 8bit mode initially
    write_4bits(0x03)
    sleep_us(WAIT_BASE*5)
    write_4bits(0x03)
    sleep_us(WAIT_BASE*1)
    write_4bits(0x03)
    sleep_us(WAIT_BASE*1)
    # Set 4bit mode
    write_4bits(0x02)
    sleep_us(WAIT_BASE*1)

    # Commands
    # Function set: 001(DL)|NFxx
    # DL=0(4bit mode)
    # N=1(2 lines)
    # F=0(5x8 font)
    write_command(0x28)
    sleep_us(WAIT_BASE*2)
    # Commands
    # Display ON\OFF: 0000|1DCB
    # DL=0(Display OFF)
    # C=0(Cursor OFF)
    # B=0(Blink OFF)
    write_command(0x08)
    sleep_us(WAIT_BASE*1)
    # Commands
    # Clear Display: 0000|0001
    write_command(0x01)
    sleep_us(WAIT_BASE*2)
    # Commands
    # Entry mode: 0000|01(I/D)S
    # I/D=1(Cursor Right move)
    # S=0(Data Shift OFF)
    write_command(0x06)
    sleep_us(WAIT_BASE*1)
    # Display ON\OFF: 0000|1DCB
    # DL=1(Display ON)
    # C=0(Cursor OFF)
    # B=0(Blink OFF)
    write_command(0x0C)
    sleep_us(WAIT_BASE*1)

# LCD にデータを送信
def lcd_data(data):
    i2c.writeto(lcd_address, bytes([0x40, data]))
    sleep_us(WAIT_BASE*1)

# LCD 画面をクリア
def lcd_clear():
    write_command(0x01)
    sleep_us(WAIT_BASE*150)

# カーソル位置を設定
def lcd_set_cursor(row, col):
    pos = col + (0x40 * row)
    write_command(0x80 | pos)

# LCD の初期化
lcd_init()

# LCD に "Hello" を表示
lcd_clear()
write_char(ord('H'))
write_char(ord('e'))
write_char(ord('l'))
write_char(ord('l'))
write_char(ord('o'))

# カーソルを 2 行目に移動
lcd_set_cursor(1, 0)

# 2 行目に "World" を表示
write_char(ord('W'))
write_char(ord('o'))
write_char(ord('r'))
write_char(ord('l'))
write_char(ord('d'))