Raspberry Pi Python I2C LCD1602表示テスト
2017.6.13 JH7UBC


 今回表示テストをしたのは、I2C専用のLCD1602ではなく、一般的なLCD1602(コントローラーにHITACHIのHD44780または互換のICが使用されている)に、シリアルパラレルインターフェースを付加してI2Cで使用できるようにしているものです。
 LCD1602は、Amazonで購入したSODIAL LCD1602、I2C・8ビットパラレルインターフェースもAmazonで購入したEasy Word Mallのものです。
 それぞれをドッキングさせて使用します。下の写真は、LCD1602本体にインターフェースを取り付けた様子です。

 このインターフェースモジュールには、PHILIPSのPCF8574が使われていて、回路は、下図のとおりです。(私が調べて描きました。メーカーが保証しているものではありませんのでご注意ください。)

まず、I2C・パラレルインターフェースのI2Cアドレスを調べます。
Raspberry PiでI2C通信を可能にして(メニュー→設定→Raspberry Piの設定→インターフェースと進み、I2Cを有効にします。)
Raspberry Piのコマンドモードで、sudo i2cdetect -y 1を入力します。

このインターフェースのI2Cアドレスが、0x27であることが分かります。
回路図のA0,A1,A2のジャンパーで、0x20〜0x27までのアドレスが設定可能です。
今回は、デフォルトの0x27で使用します。

Raspberry Pi Pythonで、I2Cを利用するためには、まずsmbusをimportしてから
smbus.SMBus(busnumber)でコネクションオブジェクトを取得します。

このsmbusライブラリで、I2Cにデータを送出する関数は、いくつかありますが、
今回は、1バイトの単独書き込み関数 write_byte_data(アドレス,コマンド,データ)を使います。
どのような信号がI2Cに送出されるのか観察するために
bus.write_byte_data(0x27,0x00,ox12)を連続的に実行して、出力をpicoscopeで見てみました。
アドレス(アドレス+書き込みなら0)、コマンド、データの順にMSBファーストでシリアルに送出されることが分かります。

コマンドとデータは、ACKでシフトレジスタからラッチされPCF8574のI/Oポートに出力されます。

回路図のようにLCD1602は、4ビットモードで使用することにして、
PCF8574のI/OポートのP4〜P7は、LCDのDB4〜DB7に接続されています。
また、I/Oポートの下位4ビットは、それぞれ
P0=RS(Register Select)
P1=R/W(Read/Wriye)
P2=E(Enable)
P3=BL(Back Light)
に接続されています。

LCD1602の書き込みタイミングをマニュアルで見るとデータが有効になった後、Enableが1から0になる立下りで
LCDにデータが書き込まれます。

そこで、1バイトのデータを書き込むために、RS=0,R/W=0,BL=1として、
コマンド書き込みのタイミングで、E=1とし、データ書き込みのタイミングで、E=0とします。
例えば、8ビットモードを与えるコマンド0X30を書き込む場合は、
LCD_addr=0x27
LCD_EN=0b00000100
LCD_BL=0b00001000
data=0x30として

bus.write_byte_data(LCD_addr,(data | LCD_EN | LCD_BL),(data |LCD_BL))でデータを送ると
上位4ビットデータにEnableとBackLightのデータが加えられ、LCD1602にデータが書き込まれ、バックライトが点灯します。
(実際には、4ビットモードで上位4ビット、下位4ビットの書き込みを行っています。)

次に、Raspberry PiとI2Cモジュール付きLCDの接続について説明します。
Raspberry PiからのI2C信号は、3.3Vですが、モジュール付のLCD1602は、LCDコントロールIC HD44780の供給電圧が
5Vのため、レベル変換モジュールを間に入れることにしました。
使ったのは、秋月電子のFXMA2102モジュールを使用しました。
このモジュールには、プルアップ抵抗がついていません。Rspberry PiのI2CポートとI2Cシリアルパラレルモジュールには、
それぞれプルアップ抵抗が内蔵されていますので、プルアップ抵抗なしのモジュールを選択しました。

実験回路の回路図です。

テストに使用したスクリプトです。

 """
I2C LCD1602 test
use PCF8574 I2C pararel interface
2017.6.12
JH7UBC Keiji Hata
"""

# -*- coding:utf-8 -*-

from time import sleep
import smbus

#PCF8574 LCD1602 connection
#P0 = LCD RS
#P1 = LCD R/W
#P2 = LCD E
#P3 = LCD BackLight
#P4 = LCD DB4
#P5 = LCD DB5
#P6 = LCD DB6
#P7 = LCD DB7

bus = smbus.SMBus(1)
LCD_addr = 0x27
LCD_EN = 0b0000100#LCD Enable
LCD_BL = 0b0001000#LCD BackLight

LCD_CMD = 0x00#command mode
LCD_CHR = 0x01#character mode
LCD_CHARS = 16
LCD_LINE1 = 0x80#Line1 top address
LCD_LINE2 = 0xC0#Line2 top address



def LCD_write(bits,mode):
  #High 4bits
  data = (bits & 0xF0) | mode
  bus.write_byte_data(LCD_addr,(data | LCD_EN | LCD_BL),(data | LCD_BL))
  sleep(0.0001)#wait 100us
  #Low 4bits
  data = ((bits << 4) & 0xF0) | mode
  bus.write_byte_data(LCD_addr,(data | LCD_EN | LCD_BL),(data | LCD_BL))
  sleep(0.0001)#wait 100us

def LCD_init():
  LCD_write(0x33,LCD_CMD)
  LCD_write(0x32,LCD_CMD)
  LCD_write(0x06,LCD_CMD)
  LCD_write(0x0C,LCD_CMD)
  LCD_write(0x28,LCD_CMD)
  LCD_write(0x01,LCD_CMD)
  sleep(0.001)

def LCD_text(message,line):
  message = message.ljust(LCD_CHARS," ")
  LCD_write(line,LCD_CMD)
  for i in range(LCD_CHARS):
    LCD_write(ord(message[i]),LCD_CHR)

def main():
  while True:
    LCD_text("Hello World!",LCD_LINE1)
    LCD_text("JH7UBC",LCD_LINE2)
    sleep(3)
    LCD_text("ABCDEFGHIJKLMNOP",LCD_LINE1)
    LCD_text("1234567890123456",LCD_LINE2)
    sleep(3)

try:
  LCD_init()
  main()

except KeyboardInterrupt:
  pass

実験の様子です。Hello World! JH7UBCとABCDEFGHIJKLMNOP 1234567890123456が3秒ごとに交互に表示されます。

inserted by FC2 system