LCDでカタカナ表示
こんにちは。ラズパイやArduinoでセンサ等を利用していると、気温などの数値をどうやって表示するか意外に悩みます。そんなメッセージや数字を表示したい時に便利なのがLCDディスプレイです。LCDは電光掲示板のようにドットで表現された文字を表示するデバイスで、ラズパイの5V電源でも動かすことが出来ます。

上の電子工作入門セットに入っていたOsoyoo製LCDは、I2Cで簡単にラズパイと接続できて、さらに制御用pythonプログラムも公式で公開されているのでとっても簡単にメッセージが表示できる…、のですがこの制御プログラム、英数字の出力のみでカタカナの表示方法が全く説明されていません。ドキュメントは日本語なのに不親切極まりないです。(初心者向けセットなのにマニュアル等一切なし。せめて各文字に対応するアドレスだけでも公開して欲しい…)
というわけで今回はこれにカタカナや記号を表示させることを目標にしたいと思います。
(追記)
このLCDの裏にはんだ付けされているI2C接続用マイコン「HD44780」は有名らしく、こちらで検索するとわりとヒットしました。今回はOsoyooのプログラムをもとにpythonで操作する方法をご紹介します。

表示は出来るっぽい
Osoyooの公式ページに従って進めてみます。
とりあえずドキュメントに従ってLCD制御用pythonプログラムをダウンロードして、文字を表示させてみる。LCDとラズパイの5V、OUT、SDA(#2ピン)、SDL(#3ピン)を接続して、制御プログラムのmain関数の中に次のように書けば英数字は表示できます。
def main(): lcd_init() lcd_string("Hello world!",LCD_LINE_1)
このままだと表示されたメッセージが一瞬で消えてしまうので、一番下の二行をコメントアウトしておきます。
#finally: #lcd_byte(0x01,LCD_CMD)
これで英数字は問題ないのですが、カタカナを表示しようとすると文字化けしてしまいます。
対策
かなり強引ですが、文字化けすることを見越して元のテキストを変えてしまう変換表を作ってみました。表示したいテキストを一回この関数で変換した後、上記の方法でとりあえず正しい文字が表示できます。
def katakana(text): list1a = u"「。、」ヲ・ィァェゥォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜" list1b = u"アァイィウゥエェオォカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミ" list2a = u"ガギグゲゴザジズゼゾダヂヅデドバビブベボ" list2b = u"ザシジスズセゼソゾタダチヂッツナニヌネノ" list3a = u"パピプペポ" list3b = u"ナニヌネノ" text_changed = "" for l in text: #カタカナを変換 if list1a.find(l) >= 0: text_changed += list1b[list1a.find(l)] #濁音を清音+濁点に elif list2a.find(l) >= 0: text_changed += list2b[list2a.find(l)] text_changed += u"マ" #半濁音を清音+半濁点に elif list3a.find(l) >= 0: text_changed += list3b[list3a.find(l)] text_changed += u"ミ" #その他の文字はそのままにする else: text_changed += l return text_changed
def main(): lcd_init() text = u"ラズベリーパイ" text2 = katakana(text) lcd_string(text2,LCD_LINE_1)
対策②
上の方法は対処療法であまりよろしくないので、いっそ表示出来る文字を全て調べてみました。制御プログラムを見たところによると、文字の表示は「0x80 0x##」を送ることで出来るみたいです。「##」の部分に対応する文字を全て表示させてみた結果はこのようになりました。

どうしてもPCで出せなかった文字は説明にしてあります。英数字やカタカナはShift-JISに沿っていますが、「千」「万」「円」「√」などの文字もあります。これだけあれば色んな情報が表示出来そうですね。個人的には「℃」が使いたいのですが、「゜」「C」で表示出来そうです。
これらの文字を出すにはmain関数内に次のように書きます。
def main(): lcd_init() #何行目に表示するか指定 lcd_byte(LCD_LINE_1,LCD_CMD) #0xFC=「円」を表示 lcd_byte(0xFC,LCD_CHR)
「円」を表示することができたでしょうか?
これだと一文字しか表示できず、また毎回表を見るのも面倒なので文字コードの順に並べたリストを作ってみました。文字コードnの文字がn番目に出てくるようにしてあります。これでカタカナを含む文字列を上の表の文字コードに変換して表示出来ます。
2019/11/3追記: 表示される文字のリストcodesの0x27のシングルクォーテーションが抜けていましたので修正しました。
def lcd_string_kana(message,line): #文字コードnの文字 = n番目の文字 codes = u'線線線線線線線線線線線線線線線線 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}→← 。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜αäβεμσρq√陰ι×¢£nöpqθ∞ΩüΣπxν千万円÷ 塗' #変換する文字の辞書(ex.「バ」=「ハ」「゛」) dic ={u'ガ':u'カ゛',u'ギ':u'キ゛',u'グ':u'ク゛',u'ゲ':u'ケ゛',u'ゴ':u'コ゛',u'ザ':u'サ゛',u'ジ':u'シ゛',u'ズ':u'ス゛',u'ゼ':u'セ゛',u'ゾ':u'ソ゛',u'ダ':u'タ゛',u'ヂ':u'チ゛',u'ヅ':u'ツ゛',u'デ':u'テ゛',u'ド':u'ト゛',u'バ':u'ハ゛',u'ビ':u'ヒ゛',u'ブ':u'フ゛',u'ベ':u'ヘ゛',u'ボ':u'ホ゛',u'パ':u'ハ゜',u'ピ':u'ヒ゜',u'プ':u'フ゜',u'ペ':u'ヘ゜',u'ポ':u'ホ゜',u'℃':u'゜C'} message = message.ljust(LCD_WIDTH," ") lcd_byte(line, LCD_CMD) #濁音など、文字の変換 message2 = "" for i in range(LCD_WIDTH): if ( message[i] in dic.keys() ): message2 += dic[message[i]] else: message2 += message[i] #文字コードのリストにある文字なら表示、それ以外は表示しない for i in range(LCD_WIDTH): if (codes.find(message2[i]) >= 0): lcd_byte(codes.find(message2[i])+1,LCD_CHR) elif (message2[i] != u' '): print "No such character! :" + message2[i]
ついでに「ガ」などLCDでは二文字で表示する文字を「カ」「゛」に分解する処理も混ぜておきました。
全体のプログラムも載せておきますご参考までにどうぞ。
#coding:utf-8 import smbus import time import sys # Define some device parameters I2C_ADDR = 0x3f # I2C device address, if any error, change this address to 0x3f LCD_WIDTH = 16 # Maximum characters per line # Define some device constants LCD_CHR = 1 # Mode - Sending data LCD_CMD = 0 # Mode - Sending command LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line LCD_BACKLIGHT = 0x08 # On #LCD_BACKLIGHT = 0x00 # Off ENABLE = 0b00000100 # Enable bit # Timing constants E_PULSE = 0.0005 E_DELAY = 0.0005 #Open I2C interface #bus = smbus.SMBus(0) # Rev 1 Pi uses 0 bus = smbus.SMBus(1) # Rev 2 Pi uses 1 def lcd_init(): # Initialise display lcd_byte(0x33,LCD_CMD) # 110011 Initialise lcd_byte(0x32,LCD_CMD) # 110010 Initialise lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size lcd_byte(0x01,LCD_CMD) # 000001 Clear display time.sleep(E_DELAY) def lcd_byte(bits, mode): # Send byte to data pins # bits = the data # mode = 1 for data # 0 for command bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT # High bits bus.write_byte(I2C_ADDR, bits_high) lcd_toggle_enable(bits_high) # Low bits bus.write_byte(I2C_ADDR, bits_low) lcd_toggle_enable(bits_low) def lcd_toggle_enable(bits): # Toggle enable time.sleep(E_DELAY) bus.write_byte(I2C_ADDR, (bits | ENABLE)) time.sleep(E_PULSE) bus.write_byte(I2C_ADDR,(bits & ~ENABLE)) time.sleep(E_DELAY) def lcd_string(message,line): # Send string to display message = message.ljust(LCD_WIDTH," ") lcd_byte(line, LCD_CMD) for i in range(LCD_WIDTH): lcd_byte(ord(message[i]),LCD_CHR) def lcd_string_kana(message,line): #文字コードnの文字 = n番目の文字 codes = u'線線線線線線線線線線線線線線線線 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}→← 。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜αäβεμσρq√陰ι×¢£nöpqθ∞ΩüΣπxν千万円÷ 塗' #変換する文字の辞書(ex.「バ」=「ハ」「゛」) dic ={u'ガ':u'カ゛',u'ギ':u'キ゛',u'グ':u'ク゛',u'ゲ':u'ケ゛',u'ゴ':u'コ゛',u'ザ':u'サ゛',u'ジ':u'シ゛',u'ズ':u'ス゛',u'ゼ':u'セ゛',u'ゾ':u'ソ゛',u'ダ':u'タ゛',u'ヂ':u'チ゛',u'ヅ':u'ツ゛',u'デ':u'テ゛',u'ド':u'ト゛',u'バ':u'ハ゛',u'ビ':u'ヒ゛',u'ブ':u'フ゛',u'ベ':u'ヘ゛',u'ボ':u'ホ゛',u'パ':u'ハ゜',u'ピ':u'ヒ゜',u'プ':u'フ゜',u'ペ':u'ヘ゜',u'ポ':u'ホ゜',u'℃':u'゜C'} message = message.ljust(LCD_WIDTH," ") lcd_byte(line, LCD_CMD) #濁音など、文字の変換 message2 = "" for i in range(LCD_WIDTH): if ( message[i] in dic.keys() ): message2 += dic[message[i]] else: message2 += message[i] #文字コードのリストにある文字なら表示、それ以外は表示しない for i in range(LCD_WIDTH): if (codes.find(message2[i]) >= 0): lcd_byte(codes.find(message2[i])+1,LCD_CHR) elif (message2[i] != u' '): print "No such character! :" + message2[i] def main(): # Main program block # Initialise display lcd_init() argv = sys.argv argc = len(argv) if (argc == 2): lcd_string(katakana(argv[1].decode('utf-8')),LCD_LINE_1) elif (argc == 3): lcd_string(katakana(argv[1].decode('utf-8')),LCD_LINE_1) lcd_string(katakana(argv[2].decode('utf-8')),LCD_LINE_2) else: #lcd_string(katakana(u"No data."),LCD_LINE_1) lcd_string_kana(u"キオン:∞℃です",LCD_LINE_1) lcd_string_kana(u"チョキン:1千万円",LCD_LINE_2) if __name__ == '__main__': try: main() except KeyboardInterrupt: pass #finally: #lcd_byte(0x01, LCD_CMD)
カタカナや記号を含めたメッセージを表示することに成功しました!
色々表示させて遊んでみます。
