#概要
Raspberry Piでストロベリーリナックス社製LCD(LCDコントローラはST7032i)を制御するプログラムを作成しました。LCDは16文字×2行表示ですが、コントローラ自体はDDRAMに80文字まで文字を保持できるので、16文字×4行を画面切り替えによって制御できるようにしました。たった64文字を制御するだけですが、私にとっては難しくて大変でした。
##動作動画
youtubeにアップした動作概要動画へのリンクです。まずはファンクションキーに割り当てたアイコンの表示/非表示動作、次にカーソルを矢印キーで移動して画面の切り替え動作及びカーソルがZ字型に移動する動作、次にカーソルに文字を入力する動作、最後にエンターキーで1・2行目と3・4行目を2秒おきに切り替える動作でCtrl+C押下で切り替え動作から入力モードへ戻ります。
#構成
下記のように接続します、I/FはI2Cです。
PinNo | LCD | RaspberryPi |
---|---|---|
1 | RST | 3.3V |
2 | SCL | SCL1 |
3 | SDA | SDA1 |
4 | VSS | GND |
5 | VDD | 3.3V |
#機能仕様
- Deleteキーでカーソル位置の文字を消去、消去後のカーソル(点滅、以下同様)は移動させない
- カーソルを矢印キーでリアルタイムに動かす
- 任意の文字キー入力でカーソル位置に文字を表示させる、入力後のカーソルは右に移動させる
- F1~F9キーに9種類のアイコンを割り当て押すたびに表示/非表示のトグル動作をさせる
- カーソルを2行目から3行目に移動させる時に画面が1・2行目表示から3・4行目表示に切り替わる
- エンターキーを押したら2秒おきに1・2行目と3・4行目表示を繰り返す、カーソルはOFFにする
- 1行目の右端で右キーを押すと2行目の左端のようにZ字型に遷移する
- 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行目にしているからです。
- この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
#参考