MicroPython(ESP8266)を使用して、I2Cで接続できるキャラクターLCDの表示を行ってみたいと思います。

使用したLCDは、Z8S180でも使用した「KKHMF DC 5V 1602 LCD ディスプレイモジュール 16×2キャラクタ LCDブルーブラックライト」と「EasyWordMall 1602 LCD ブラック IIC/I2C/TWI/SPI シリアル インタフェース ボード モジュール」です。(amazon等で購入)

ただ、上記キャラクターLCDは5V仕様なので、3.3V仕様のESP-WROOM-02とは直接に接続することができません。そこで今回はI2Cレベル変換モジュールPCA9306(AE-PCA9306)(秋月電子)を使用しました。

回路図は下記のとおりです。

thonnyとシリアル通信するためには、回路図には図示していませんが、IO15(6pin)を10KΩでGnd(プルダウン)に接続する必要があります。
および、IO2(7pin)、IO0(8pin)は内部でプルアップされていますが、必要であれば10KΩでVCC(3.3V)に接続してください。

EasyWordMall 1602 LCD ブラック IIC/I2C/TWI/SPI シリアル インタフェース ボード モジュールへの接続は、J1のコネクターで、シルク表示で GND、Vcc、SDA、SCLの順番になっています。
半固定ボリュームはLCDの輝度調整用で、真ん中あたりにしておきます。
LEDと表示されているジャンパーを抜くとバックライトが消えるようです。

I2Cインターフェイスモジュール のスレーブアドレスは、
   PCF8574T では、0x27
   PCF8574ATでは、0x3fとなるようです。
   アマゾンのレビューをみると2種類のデバイスが出荷されているよう
   なのでついているデバイスの確認が必要です。
  (ともに A0/A1/A2がオープンの時)
今回購入したものは、PCF8574Tで、0x27 となっていますので以下スレーブアドレスは、0x27の設定となっています。

MicroPythonのプログラムは下記のようになりました。
開発環境は前回の「MicroPython(ESP8266)に萌えたい。ESP-WROOM-02でLちか。」を参照してください。

まずは、I2Cのpinを決めます。ESP8266ではソフトウェアI2Cになっているので、任意のpinを指定できます。
ここでは、SCL=IO14(3pin)、SDA=IO12(4pin)に設定しました。
必要な、ライブラリーとI2Cの初期を行います。
LCDのI2Cアドレスは前記の通り、0x27です。

from machine import Pin, I2C

import utime

i2c=I2C(scl=Pin(14),sda=Pin(12),freq=100000)

LCD_i2c_addr= 0x27

LCD ディスプレイモジュール とI2C シリアル インタフェース ボードモジュールとは次のような接続になっています。
LCDの制御のために、RS/RW/EN/LEDの各端子のビット位置を設定します。ちなみに LCDへのデータ転送は、4BitモードになっていますのでD7~D4までの4Bitで設定します。

#   lcd 1602 port
#
#      D0 > RS
#      D1 > R/W
#      D2 > E
#      D3 > LED on/off
#      D4 > DB4
#      D5 > DB5
#      D6 > DB6
#      D7 > DB7

LCDへの書き込みは4ビットごとに書き込みします。
書き込みには、コマンドデータと表示用データの書き込みの2種類があります。
モードの切り替えは RS端子で行います。
コマンドデータ >> RS=0
表示用データ  >> RS=1

書き込みと読み出しのモード切替はRW端子で行います。
読み出し >> RW=1
書き込み >> RW=0
今回の場合は、読み出しは行わないので、RW端子は常に 0のままです。

実際の書き込みタイミングは、ENを正論理でパルスを送ります。
つまり、 EN >> 0>1>0のタイミングの1発だけのパルスを生成します。

バックライトは常にONにしています
パックライトON >> LED=1
バックライトOFF>> LED=0

コマンド用の4ビットの書き込みのユーザー関数プログラムは下記のようになります。

lcd4bitwriteの引数commandでコマンド用のデータを渡します。
commandは4bit左シフトし、D7~D4に渡します。
コマンドデータ用なので、RS=0、つまりD0=0とします。
論理和ORで必要なビットを1にし、論理積ANDで必要なビットのみ1を取ります。
lcd_command_buff[0]で作成したcommandをバッファに入れます。
i2c.writetoでI2Cアドレスとlcd_command_buffを指定して書き込みします。

    
def lcd4bitwrite(command):
    command = command << 4
    command = command | 0b00001000
    command = command & 0b11111000
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001100
    command = command & 0b11111100
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001000
    command = command & 0b11111000
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)

同様に表示用の4ビットの書き込みのプログラムは下記のようになります。
表示データ用なのでRS=1、つまりD0=1とします。

def data_lcd4bitwrite(command):
    command = command << 4
    command = command | 0b00001001
    command = command & 0b11111001
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001101
    command = command & 0b11111101
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001001
    command = command & 0b11111001
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff) 

続いて、8ビットコマンド用および8ビット表示用の関数を作成します。
8ビットなので、上位4ビット下位4ビットの分けて4ビット用のユーザー関数で書き込みします。

def lcd8bitwrite(command):
    command2 = command
    command = command >> 4
    lcd4bitwrite(command)
    lcd4bitwrite(command2)

def data_lcd8bitwrite(command):
    command2 = command
    command= command >> 4
    data_lcd4bitwrite(command)
    data_lcd4bitwrite(command2)

LCDのイニシャライズは、作成した、 lcd4bitwrite(command)とlcd8bitwrite(command)を利用して、イニシャライズを行います。

def lcd_init():
    data_set = 0x03
    lcd4bitwrite(data_set)
    utime.sleep_ms(5)
    lcd4bitwrite(data_set)
    lcd4bitwrite(data_set)
    data_set = 0x02
    lcd4bitwrite(data_set)
    data_set = 0x28
    lcd8bitwrite(data_set)
    data_set = 0x0c
    lcd8bitwrite(data_set)
    data_set = 0x01
    lcd8bitwrite(data_set)
    utime.sleep_ms(2)
    data_set = 0x06
    lcd8bitwrite(data_set)
    data_set = 0x02
    lcd8bitwrite(data_set)
    utime.sleep_ms(2)

メインのプログラムは、LCDのイニシャライズを行った後、messge1とmessge2を表示します。
messge1はUnicodeで書かれた文字を単語ごとに登録しています。UnicodeからASCIIに変換するのにord()関数が必要です。
messge2は、ASCIIコードを直接16進表記にして登録しています。

messge1=bytearray(16)
messge2=bytearray(16)
messge1=(' ','*','*','*','*','E','S','P','8','2','6','6','*','*','*',' ',)
# messge2 = Hello I2C World
messge2=(0x20,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x49,0x32,0x43,0x20,0x57,0x6f,0x72,0x6c,0x64,)

lcd_init()

for i in range(0, 16):
    data_lcd8bitwrite(ord(messge1[i]))
    
data_set = 0xc0
lcd8bitwrite(data_set)

for i in range(0, 16):
    data_lcd8bitwrite(messge2[i])

LCDには、下記のように表示されます。

 ****ESP8266***
 Hello I2C World

全体のプログラムは下記の通りです。

#  MicroPython(ESP8266) I2C LCD display(KKHMF 1602 LCD +EasyWordMall 1602 LCD i2c i/F)
#
#   SCL = IO14(3pin)
#   SDA = IO12(4pin)
#   LCD I2C address =0x27 (addr open) 
#
#   lcd 1602 port
#
#      D0 > RS
#      D1 > R/W
#      D2 > E
#      D3 > LED on/off
#      D4 > DB4
#      D5 > DB5
#      D6 > DB6
#      D7 > DB7
#
from machine import Pin, I2C

import utime

i2c=I2C(scl=Pin(14),sda=Pin(12),freq=100000)

LCD_i2c_addr= 0x27


lcd_command_buff=bytearray(1)

messge1=bytearray(16)
messge2=bytearray(16)
messge1=(' ','*','*','*','*','E','S','P','8','2','6','6','*','*','*',' ',)
# messge2 = Hello I2C World
messge2=(0x20,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x49,0x32,0x43,0x20,0x57,0x6f,0x72,0x6c,0x64,)


def lcd_init():
    data_set = 0x03
    lcd4bitwrite(data_set)
    utime.sleep_ms(5)
    lcd4bitwrite(data_set)
    lcd4bitwrite(data_set)
    data_set = 0x02
    lcd4bitwrite(data_set)
    data_set = 0x28
    lcd8bitwrite(data_set)
    data_set = 0x0c
    lcd8bitwrite(data_set)
    data_set = 0x01
    lcd8bitwrite(data_set)
    utime.sleep_ms(2)
    data_set = 0x06
    lcd8bitwrite(data_set)
    data_set = 0x02
    lcd8bitwrite(data_set)
    utime.sleep_ms(2)

    
def lcd4bitwrite(command):
    command = command << 4
    command = command | 0b00001000
    command = command & 0b11111000
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001100
    command = command & 0b11111100
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001000
    command = command & 0b11111000
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)   

def data_lcd4bitwrite(command):
    command = command << 4
    command = command | 0b00001001
    command = command & 0b11111001
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001101
    command = command & 0b11111101
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)
    command = command | 0b00001001
    command = command & 0b11111001
    lcd_command_buff[0]= command
    i2c.writeto(LCD_i2c_addr,lcd_command_buff)   

def lcd8bitwrite(command):
    command2 = command
    command = command >> 4
    lcd4bitwrite(command)
    lcd4bitwrite(command2)

def data_lcd8bitwrite(command):
    command2 = command
    command= command >> 4
    data_lcd4bitwrite(command)
    data_lcd4bitwrite(command2)


lcd_init()

for i in range(0, 16):
    data_lcd8bitwrite(ord(messge1[i]))
    
data_set = 0xc0
lcd8bitwrite(data_set)

for i in range(0, 16):
    data_lcd8bitwrite(messge2[i])

おすすめの記事