LoginSignup
0
0

More than 3 years have passed since last update.

RaspberryPiで16x2 I2C LCDモジュールを制御

Last updated at Posted at 2019-12-15

概要

Raspberry Piでストロベリーリナックス社製LCD(LCDコントローラはST7032i)を制御するプログラムを作成しました。LCDは16文字×2行表示ですが、コントローラ自体はDDRAMに80文字まで文字を保持できるので、16文字×4行を画面切り替えによって制御できるようにしました。たった64文字を制御するだけですが、私にとっては難しくて大変でした。

動作動画

youtubeにアップした動作概要動画へのリンクです。まずはファンクションキーに割り当てたアイコンの表示/非表示動作、次にカーソルを矢印キーで移動して画面の切り替え動作及びカーソルがZ字型に移動する動作、次にカーソルに文字を入力する動作、最後にエンターキーで1・2行目と3・4行目を2秒おきに切り替える動作でCtrl+C押下で切り替え動作から入力モードへ戻ります。

RaspberryPiでLCD制御

構成

下記のように接続します、I/FはI2Cです。

PinNo LCD RaspberryPi
1 RST 3.3V
2 SCL SCL1
3 SDA SDA1
4 VSS GND
5 VDD 3.3V

機能仕様

  1. Deleteキーでカーソル位置の文字を消去、消去後のカーソル(点滅、以下同様)は移動させない
  2. カーソルを矢印キーでリアルタイムに動かす
  3. 任意の文字キー入力でカーソル位置に文字を表示させる、入力後のカーソルは右に移動させる
  4. F1~F9キーに9種類のアイコンを割り当て押すたびに表示/非表示のトグル動作をさせる
  5. カーソルを2行目から3行目に移動させる時に画面が1・2行目表示から3・4行目表示に切り替わる
  6. エンターキーを押したら2秒おきに1・2行目と3・4行目表示を繰り返す、カーソルはOFFにする
  7. 1行目の右端で右キーを押すと2行目の左端のようにZ字型に遷移する
  8. Backspaceキーでカーソルの1つ左の文字を削除する、カーソルは左に移動ただしカーソルがはじの場合はZ字に遷移

ソース

  • getch()関数はpythonの標準入力であるinput()関数とは違い、文字入力をするとEnterキー入力なしで処理してくれる関数です。詳しくは参考ページを参照してください。Linuxディストリビューションで動作するもののようです。
  • メイン処理のwhile文でキー入力をポーリングしています。入力される文字コードはaなら97、Enterなら13などif文で条件分岐させていますが、矢印キーやファンクションキーは特殊なようで例えば左矢印なら[27,91,68]と1回のキー入力で文字コードが3回入力されたり、F1キーなら[27,91,49,49,126]が入力される等特殊になっています。また、これらの特殊なキーは環境によって同じキーボードでも入力コードがかわってしまったので注意が必要です。理由はわかりません。
  • slide_show()関数で2秒おきの画面切り替えをしていますが、sleep関数でカウントしている最中はgetch()でキー入力ができず解除処理ができないので、Ctrl+Cでキーボード割り込みを発生させて解除しています。
  • st7032iは、カーソルの位置(アドレスカウンターACに格納されているアドレス)に文字が入力されるので、基本的な制御方法としてはACに書き込みたい位置のアドレスをwrite(Set DDRAM Address Instruction)してから、文字コードを書き込み(Write Data to RAM Instruction)となります。16×4行の位置とアドレスの関係は下のほうに記載します。
LCD.py
import sys
from time import sleep
import smbus
import tty
import termios

def getch():
    fd = sys.stdin.fileno()
    old = termios.tcgetattr(fd)
    try:
        tty.setraw(fd)
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd,termios.TCSADRAIN,old)



def init():
    trials = 5
    for i in range(5):
        try:
            sleep(0.04)
            bus.write_i2c_block_data(st7032i,ctr_inst,[0x39,0x39,0x14,0x70|(contrust&0x0f),0x5c|(contrust&0x30)>>4,0x6c])
            sleep(0.2)
            bus.write_byte_data(st7032i,ctr_inst,0x0d)

        except IOError:
            if i==trials-1:
                sys.exit()


def view_icon(x):
    global icon
    global position

    bus.write_byte_data(st7032i,ctr_inst,0x39)

    if x == 0:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x40)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        else:
            bus.write_byte_data(st7032i,ctr_inst,0x40)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 1:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x42)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        else:
            bus.write_byte_data(st7032i,ctr_inst,0x42)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 2:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x44)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        else:
            bus.write_byte_data(st7032i,ctr_inst,0x44)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 3:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x46)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        else:
            bus.write_byte_data(st7032i,ctr_inst,0x46)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 4:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x47)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        elif icon[x] == 1:
            bus.write_byte_data(st7032i,ctr_inst,0x47)
            bus.write_byte_data(st7032i,ctr_data,0x08)
            icon[x] = 2
        elif icon[x] == 2:
            bus.write_byte_data(st7032i,ctr_inst,0x47)
            bus.write_byte_data(st7032i,ctr_data,0x18)
            icon[x] = 3
        elif icon[x] == 3:
            bus.write_byte_data(st7032i,ctr_inst,0x47)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 5:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x49)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        else:
            bus.write_byte_data(st7032i,ctr_inst,0x49)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 6:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x4b)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        else:
            bus.write_byte_data(st7032i,ctr_inst,0x4b)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 7:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x4d)
            bus.write_byte_data(st7032i,ctr_data,0x1e)
            icon[x] = 1
        elif icon[x] == 1:
            bus.write_byte_data(st7032i,ctr_inst,0x4d)
            bus.write_byte_data(st7032i,ctr_data,0x1a)
            icon[x] = 2
        elif icon[x] == 2:
            bus.write_byte_data(st7032i,ctr_inst,0x4d)
            bus.write_byte_data(st7032i,ctr_data,0x12)
            icon[x] = 3
        elif icon[x] == 3:
            bus.write_byte_data(st7032i,ctr_inst,0x4d)
            bus.write_byte_data(st7032i,ctr_data,0x02)
            icon[x] = 4
        elif icon[x] == 4:
            bus.write_byte_data(st7032i,ctr_inst,0x4d)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0
    elif x == 8:
        if icon[x] == 0:
            bus.write_byte_data(st7032i,ctr_inst,0x4f)
            bus.write_byte_data(st7032i,ctr_data,0x10)
            icon[x] = 1
        else:
            bus.write_byte_data(st7032i,ctr_inst,0x4f)
            bus.write_byte_data(st7032i,ctr_data,0x00)
            icon[x] = 0

    row = position/16
    col = position%16
    if row == 0:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x00|col&0x0f)
    elif row == 1:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x40|col&0x0f)
    elif row == 2:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x10|col&0x0f)
    elif row == 3:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x50|col&0x0f)


def clear_icon():
    bus.write_byte_data(st7032i,ctr_inst,0x39)
    bus.write_i2c_block_data(st7032i,0x80,[0x40,0x40,0x00, 0x80,0x42,0x40,0x00, 0x80,0x44,0x40,0x00, 0x80,0x46,0x40,0x00, 0x80,0x47,0x40,0x00])
    bus.write_i2c_block_data(st7032i,0x80,[0x49,0x40,0x00, 0x80,0x4b,0x40,0x00, 0x80,0x4d,0x40,0x00, 0x80,0x4f,0x40,0x00])


def clear():
    global position
    bus.write_byte_data(st7032i,ctr_inst,0x01)#clear Display
    sleep(0.001)
    clear_icon()
    sleep(0.001)
    return_home()


def move_left():
    global position

    if position%16 > 0 and  position%16 <= 15:
        position -= 1
        bus.write_i2c_block_data(st7032i,ctr_inst,[0x38,0x10])
        #print position
    elif position == 16:
        position -= 1
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x0f)
    elif position == 32:
        position -= 1
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x4f)

        bus.write_byte_data(st7032i,ctr_inst,0x38)
        for i in range(16):
            bus.write_byte_data(st7032i,ctr_inst,0x1c)

    elif position == 48:
        position -= 1
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x1f)
    else:
        return -1


def move_right():
    global position

    if position%16 >=0 and position%16 < 15:
        position += 1
        bus.write_i2c_block_data(st7032i,ctr_inst,[0x38,0x14])
        #print position
    elif position == 15:
        position += 1
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x40)
    elif position == 31:
        position += 1
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x10)

        bus.write_byte_data(st7032i,ctr_inst,0x38)
        for i in range(16):
            bus.write_byte_data(st7032i,ctr_inst,0x18)

    elif position == 47:
        position += 1
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x50)
    else:
        return -1


def move_up():
    global position

    if position/16 <> 0:
        position -=16
    else:
        return -1

    row = position / 16
    col = position % 16
    if row == 0:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x00|(col&0x0f))
    elif row == 1:

        bus.write_byte_data(st7032i,ctr_inst,0x38)
        for i in range(16):
            bus.write_byte_data(st7032i,ctr_inst,0x1c)

        bus.write_byte_data(st7032i,ctr_inst,0x80|0x40|(col&0x0f))
    elif row == 2:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x10|(col&0x0f))
    #print position




def move_down():
    global position

    if position/16 <> 3:
        position += 16
    else:
        return -1

    row = position / 16
    col = position % 16
    if row == 1:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x40|(col&0x0f))
    elif row == 2:

        bus.write_byte_data(st7032i,ctr_inst,0x38)
        for i in range(16):
            bus.write_byte_data(st7032i,ctr_inst,0x18)

        bus.write_byte_data(st7032i,ctr_inst,0x80|0x10|(col&0x0f))

    elif row == 3:
        bus.write_byte_data(st7032i,ctr_inst,0x80|0x50|(col&0x0f))
    #print position


def delete():
    bus.write_byte_data(st7032i,ctr_data,0x20)#write space
    bus.write_byte_data(st7032i,ctr_inst,0x38)
    bus.write_byte_data(st7032i,ctr_inst,0x10)#move cursor to left


def write_char(c):
    if c >= 0x00 and c <= 0xff:
        bus.write_byte_data(st7032i,ctr_data,c)
        bus.write_i2c_block_data(st7032i,ctr_inst,[0x38,0x10])#cursor left shift
        move_right()
    else:
        return -1


def backspace():
    move_left()
    delete()


def slide_show():
    global position
    print "Now presentation mode, Please press \"Ctrl+C\" to return edit mode."
    return_home()
    bus.write_byte_data(st7032i,ctr_inst,0x0c)#display on/off -> cursor off
    while True:
        try:
            sleep(2)
            move_down()
            move_down()
            sleep(2)
            move_up()
            move_up()
        except KeyboardInterrupt:
            print "Now edit mode"
            return_home()
            bus.write_byte_data(st7032i,ctr_inst,0x0d)#display on/off -> cursor on
            break

def write_string(s):
    for c in list(s):
        write_char(ord(c))

def return_home():
    global position
    bus.write_byte_data(st7032i,ctr_inst,0x02)
    sleep(0.001)
    position = 0


st7032i = 0x3e
ctr_inst = 0x00#(C0=0, RS=0)
ctr_data = 0x40#(C0=0, RS=1)
contrust = 36#(0-63)
bus = smbus.SMBus(1)
icon = [0,0,0,0,0,0,0,0,0]
position = 0
state = 0

clear_icon()

init()

clear()

write_string("Hello World!    This program is written by      Python. :)")
return_home()

print "ready now. Please press Ctrl+C to stop quit program."

while True:

    key = ord(getch())

    if key == 3:
        break
    elif key == 13:
        print "Enter"
        slide_show()
    elif key == 127:
        print "DEL"
        delete()
    elif key == 8:
        print "BS"
        backspace()
    elif key == 27:
        key = ord(getch())
        if key == 91:
            key = ord(getch())
            if key == 68:
                print "left"
                move_left()
            elif key == 67:
                print "right"
                move_right()
            elif key == 65:
                print "up"
                move_up()
            elif key == 66:
                print "down"
                move_down()
            elif key == 49:
                key = ord(getch())
                if key == 49:
                    key = ord(getch())
                    if key == 126:
                        print "F1"
                        view_icon(0)
                elif key == 50:
                    key = ord(getch())
                    if key == 126:
                        print "F2"
                        view_icon(1)
                elif key == 51:
                    key = ord(getch())
                    if key == 126:
                        print "F3"
                        view_icon(2)
                elif key == 52:
                    key = ord(getch())
                    if key == 126:
                        print "F4"
                        view_icon(3)
                elif key == 53:
                    key = ord(getch())
                    if key == 126:
                        print "F5"
                        view_icon(4)
                elif key == 55:
                    key = ord(getch())
                    if key == 126:
                        print "F6"
                        view_icon(5)
                elif key == 56:
                    key = ord(getch())
                    if key == 126:
                        print "F7"
                        view_icon(6)
                elif key == 57:
                    key = ord(getch())
                    if key == 126:
                        print "F8"
                        view_icon(7)
            elif key == 50:
                key = ord(getch())
                if key == 48:
                    key = ord(getch())
                    if key == 126:
                        print "F9"
                        view_icon(8)
                elif key == 49:
                    key = ord(getch())
                    if key == 126:
                        print "F10"
                        view_icon(9)
                elif key == 51:
                    key = ord(getch())
                    if key == 126:
                        print "F11"
                elif key == 52:
                    key = ord(getch())
                    if key == 126:
                        print "F12"

    else:
        print "character:{0},    code:{1}".format(chr(key),key)
        write_char(key)


    sleep(0.005)

文字表示座標の考え方

  • 16文字×4行の配置とアドレスの関係を下記に示します。LCDの行数は表の行に、LCDの横の文字数は表の列にアドレスと管理用のPosition番号を記載しています。例えば1行目の1文字目はDDRAMアドレス0x00、3行目の2文字目は0x11といった感じです。
  • わかりづらいですが、1行目の16文字目アドレス0x0Fの次の0x10アドレスは3行目の1文字目といったように、アドレス上は1行目→3行目→2行目→4行目になっています。これは本来、下記のようにst7032iのDDRAMアドレスの並びは40文字×2行なので、3行目以降の概念はないのですが17~32列目を3・4行目にしているからです。

    st7032データシートP15抜粋
    image.png

  • このLCDはアドレスカウンターの値をREADできないのでPositionという変数で座標を保持しています。DDRAMアドレスは16進数、Position変数は10進数です。

行数(※) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1(0000) DDRAM 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Position 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2(0100) DDRAM 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
Position 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
3(0001) DDRAM 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
Position 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
4(0101) DDRAM 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
Position 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

※DDRAMアドレス上位4bits

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0