こんにちは、にどねゆうきです。
梅雨に入りましたが、田んぼのザリガニも茹で上がるような暑さの日々が続いています。
そんな時期、おうちで出来る遊びの一つがRasberry Pi(ラズパイ)やPythonを使ったマイコン遊び。
ラズパイを使うことですべてが画面上で完結するPCでのプログラミングとは異なり、個別のモノから音を鳴らしたり光を出したり、実際に何かを動かすことができるので、双子たちのリアクションもよくなかなか楽しめます。
そんな趣味になっているラズパイ工作セット(SunFounder STEAM EDUCATION)に入っているのが小さな液晶ディスプレイ(LCD)。たまごっちとかデジモンとか、おそらく上の世代の方が見たらポケベルっぽいというかもしれません。こんな感じのやつです。
waves 1602 IIC/I2C/TWI LCD液晶 モジュール 青
私も平成生まれの一人として、この感じのディスプレイに文字を表示させることには謎の憧れがあります。あのとき遊んでいたおもちゃをまさか自分で作れるなんて・・!!
そこで今回、手元にあったRaspberry Pi Zeroと安価な液晶ディスプレイ(LCD1602)を使って、文字表示に挑戦してみました。
とりあえず作ったプログラムで、アルファベットや数字は上記のサンプル画像のように問題なく表示できたのですが…
日本語のカタカナを表示させようとすると、残念ながら文字化けして上手くいかず。(写真撮り忘れ)
調べてみたところ、基本的にこういうものでカンタンに表示させられるのはアルファベットと数字で、日本語を表示させようと思うと一工夫が必要だったようです。
そんなわけで、一工夫をしてLCDディスプレイにカタカナを表示できるようになりましたので、今回備忘録としてまとめ、皆さまのお役に立てればと思います。よろしくお願いいたします。
そもそもなぜカタカナが文字化けするのか
さて、この文字化けの原因。調べてみるとPythonがプログラム内で扱う文字のデータ(文字コード)と、LCDディスプレイが表示できる文字の種類が違うことにあるようです。
- Pythonのプログラムで私たちが書く文字(例:「ハロー」)は、「Unicode」という国際的なルールで管理されていて、世界中のいろんな文字が含まれています。
- 一方、今回使ったような安価なLCDディスプレイ(LCD1602など)は、表示できる文字が最初から決まっていて、その中に全角のカタカナは直接入っていないことが多いんです。(※半角カタカナなら入っていることが多いみたいです)
つまり、ラズパイ君は「“ハロー”って表示してね!」とUnicodeでお願いしても、LCD君は「え?“ハ”って何?知らない文字だなあ…とりあえずこれ表示しとくか…(豆腐)」ってなっちゃうわけです。これが文字化けの正体ですね。
文字コードを全部変換ですればカタカナ表示が出来る
ということは解決策はシンプル。
要は、Pythonが送る全角カタカナの情報を、LCDが表示できる半角カタカナの情報にプログラム側で翻訳(変換)してあげればいいわけです。
今回は、よく使われているLCD制御ライブラリ(`LCD1602.py`)をカスタマイズして、この「カタカナ翻訳機能」を追加してみました。
具体的には、表示したい全角カタカナと、それに対応するLCD内蔵の半角カタカナの対応表(辞書みたいなもの)をプログラムに持たせて、文字を送る直前に変換処理を挟むイメージです。
単純な文字ならシンプルに変換。「ハ」なら「ハ」に。ちょっと工夫がいるのが濁点や半濁点がついたもので、「プ」なら「プ」(「フ」と「゚」の組み合わせ)といった具合に変換します。
修正版プログラム
今回は「LCD1602.py」というベースとなるプログラムと、「display_kana.py」という表示させる文字を入力するプログラム、2つのプログラムを使って表示をさせます。
以下のような流れで使用が可能です。
1.それぞれのコードをコピペし、このファイル名で保存する
2.ピン番号や表示させたい文字列をを適切なものに変換する
3.この2つのファイルをラズパイの中の同じディレクトリ(フォルダ)に転送する
4.ラズパイで「display_kana.py」を実行する
5.このkana内に書かれた文字が表示される
`LCD1602.py`のコードと、それを使ってカタカナを表示させるサンプルプログラム`display_kana.py`は以下の通りです。こちらのコードをコピーしてご使用ください。
▼ `LCD1602.py`(カタカナ対応版)
# --- START OF FILE LCD1602.py (修正版) ---
#!/usr/bin/env python3
import time
import smbus2 as smbus
BUS = smbus.SMBus(1)
# 全角カタカナと記号を、LCD内蔵の半角カタカナコードに変換するための対応表
KANA_MAP = {
# 濁点・半濁点付き文字
'ガ': 'ガ', 'ギ': 'ギ', 'グ': 'グ', 'ゲ': 'ゲ', 'ゴ': 'ゴ',
'ザ': 'ザ', 'ジ': 'ジ', 'ズ': 'ズ', 'ゼ': 'ゼ', 'ゾ': 'ゾ',
'ダ': 'ダ', 'ヂ': 'ヂ', 'ヅ': 'ヅ', 'デ': 'デ', 'ド': 'ド',
'バ': 'バ', 'ビ': 'ビ', 'ブ': 'ブ', 'ベ': 'ベ', 'ボ': 'ボ',
'パ': 'パ', 'ピ': 'ピ', 'プ': 'プ', 'ペ': 'ペ', 'ポ': 'ポ',
'ヴ': 'ヴ',
# カタカナ
'ア': 'ア', 'イ': 'イ', 'ウ': 'ウ', 'エ': 'エ', 'オ': 'オ',
'カ': 'カ', 'キ': 'キ', 'ク': 'ク', 'ケ': 'ケ', 'コ': 'コ',
'サ': 'サ', 'シ': 'シ', 'ス': 'ス', 'セ': 'セ', 'ソ': 'ソ',
'タ': 'タ', 'チ': 'チ', 'ツ': 'ツ', 'テ': 'テ', 'ト': 'ト',
'ナ': 'ナ', 'ニ': 'ニ', 'ヌ': 'ヌ', 'ネ': 'ネ', 'ノ': 'ノ',
'ハ': 'ハ', 'ヒ': 'ヒ', 'フ': 'フ', 'ヘ': 'ヘ', 'ホ': 'ホ',
'マ': 'マ', 'ミ': 'ミ', 'ム': 'ム', 'メ': 'メ', 'モ': 'モ',
'ヤ': 'ヤ', 'ユ': 'ユ', 'ヨ': 'ヨ',
'ラ': 'ラ', 'リ': 'リ', 'ル': 'ル', 'レ': 'レ', 'ロ': 'ロ',
'ワ': 'ワ', 'ヲ': 'ヲ', 'ン': 'ン',
# 小文字
'ァ': 'ァ', 'ィ': 'ィ', 'ゥ': 'ゥ', 'ェ': 'ェ', 'ォ': 'ォ',
'ッ': 'ッ', 'ャ': 'ャ', 'ュ': 'ュ', 'ョ': 'ョ',
# 記号
'。': '。', '「': '「', '」': '」', '、': '、', '・': '・',
'ー': 'ー', '゛': '゙', '゜': '゚'
}
def write_word(addr, data):
global BLEN
temp = data
if BLEN == 1:
temp |= 0x08
else:
temp &= 0xF7
BUS.write_byte(addr ,temp)
def send_command(comm):
# Send bit7-4 firstly
buf = comm & 0xF0
buf |= 0x04 # RS = 0, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (comm & 0x0F) << 4
buf |= 0x04 # RS = 0, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
def send_data(data):
# Send bit7-4 firstly
buf = data & 0xF0
buf |= 0x05 # RS = 1, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (data & 0x0F) << 4
buf |= 0x05 # RS = 1, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)
def init(addr, bl):
global LCD_ADDR
global BLEN
LCD_ADDR = addr
BLEN = bl
try:
send_command(0x33) # Must initialize to 8-line mode at first
time.sleep(0.005)
send_command(0x32) # Then initialize to 4-line mode
time.sleep(0.005)
send_command(0x28) # 2 Lines & 5*7 dots
time.sleep(0.005)
send_command(0x0C) # Enable display without cursor
time.sleep(0.005)
send_command(0x01) # Clear Screen
BUS.write_byte(LCD_ADDR, 0x08)
except Exception as e:
print(f"Error during LCD initialization: {e}")
return False
else:
return True
def clear():
send_command(0x01) # Clear Screen
def openlight(): # Enable the backlight
BUS.write_byte(0x27,0x08)
BUS.close()
def write(x, y, str_in):
if x < 0:
x = 0
if x > 15:
x = 15
if y <0:
y = 0
if y > 1:
y = 1
# Move cursor
addr = 0x80 + 0x40 * y + x
send_command(addr)
# ======================= MODIFIED AREA START =======================
# 文字列を1文字ずつ処理
for char in str_in:
# KANA_MAPを使って全角カタカナを半角カタカナ文字列に変換
# (例: 'ガ' -> 'ガ'、 'ア' -> 'ア'、 'A' -> 'A')
mapped_str = KANA_MAP.get(char, char)
# 変換後の文字列をLCDに送信 (例: 'ガ' は 'カ' と '゙' に分けて送信)
for c in mapped_str:
try:
# Shift_JISの半角カナのバイトコードがLCDのコードと一致することを利用
code = c.encode('shift_jis')[0]
send_data(code)
except (UnicodeEncodeError, IndexError):
# 変換できない文字(ひらがな、漢字など)は '?' を表示
send_data(ord('?'))
# ======================= MODIFIED AREA END =========================
if __name__ == '__main__':
if init(0x27, 1):
write(0, 0, 'カタカナ テスト') # カタカナ表示のテスト
write(0, 1, 'PYTHON 3')
else:
print("Failed to initialize LCD.")
# --- END OF FILE LCD1602.py (修正版) ---
▼ カタカナ表示サンプルプログラム `display_kana.py`
# --- START OF FILE display_kana.py ---
import LCD1602
import time
def setup():
# LCDを初期化 (アドレスは環境に合わせて0x27や0x3fなどに変更してください)
if not LCD1602.init(0x27, 1): # ← ご自身のLCDアドレスに合わせて変更!
print("LCDが見つかりません。配線とアドレスを確認してください。")
return
print("LCDにカタカナを表示します。")
print("終了するには Ctrl+C を押してください。")
# 1行目に「ハローワールド!」と表示
LCD1602.write(0, 0, "ハローワールド!")
# 2行目に「プログラム」と表示 (濁点・半濁点も表示可能)
LCD1602.write(0, 1, "プログラム")
# 参考: 漢字やひらがなは '?' に置き換えられます
# LCD1602.write(0, 0, "日本語表示") # -> '????' と表示される
def destroy():
# 終了時に画面をクリアする
LCD1602.clear()
print("\nプログラムを終了します。")
# メインの処理
if __name__ == "__main__":
try:
setup()
# プログラムがすぐに終了しないように無限ループで待機
while True:
time.sleep(1)
except KeyboardInterrupt:
# Ctrl+Cが押されたらdestroy関数を呼び出して終了
destroy()
# --- END OF FILE display_kana.py ---
にどねの環境での配線(とりあえずこう繋げば動きます)
プログラムの準備ができたら、次はラズパイとLCDを接続します。
今回使用したLCD1602はI2C(アイツーシー)という通信方式に対応しているので、少ない配線で済むのが嬉しいポイントです。主に必要なのは以下の4本線です(お使いの環境によって若干異なる場合があります)。
- VCC(電源:ラズパイの5Vまたは3.3Vへ)
- GND(グランド:ラズパイのGNDへ)
- SDA(データ線:ラズパイのSDAピンへ)
- SCL(クロック線:ラズパイのSCLピンへ)
※上記はあくまで一般的な例です。お使いのラズパイのモデルやLCDモジュール、GPIO拡張ボードのピン配置を確認のうえ、ご接続ください。間違えると最悪ラズパイが天に召されることも…。
ラズパイのGPIOピン配置はモデルによって異なるので、Raspberry Pi公式サイトなどで確認するのが確実です。
点灯!カタカナ表示!
配線とプログラムの準備が整ったら、いよいよラズパイのターミナルからプログラムを実行します。
python3 display_kana.py
コマンドを入力してEnterキーを押すと…
ハローワールド プログラム!!
文字化けせず、無事にカタカナで文字が表示されました。内部的には半角カタカナを表示しているのですが、意外とフツーのカタカナっぽく見えます。平成の時代によく見たあのカタカナです。
自分で書いた(今回はちょっと改造しただけですが)プログラムが、実際にモノを動かして、目に見える形で結果が出る。これぞラズパイの醍醐味です。
ひらがなや漢字は表示できず
今回、無事にカタカナ表示はできましたが、今回の修正はカタカナに特化したものなので、ひらがなや漢字を表示しようとすると、残念ながら「?」に置き換えられてしまいます。これらを表示するには、グラフィックLCDを使ったり、もっと複雑な処理が必要になりそうです。
とはいえ、カタカナが表示できるようになっただけでも、作れるものの幅がグンと広がります。表現力が上がったことで、メッセージを表示したり、ゲームを作ったり、どんなものが出来そうかと想像力が広がります。
まとめ
というわけで今回は、Raspberry PiとLCDディスプレイで日本語カタカナが文字化けする問題の解決策をご紹介しました。もし同じような悩みでつまづいている方がいたら、この記事が少しでもお役に立てれば嬉しいです。
※この記事で紹介したプログラムや配線は、お使いの環境や部品によって動作しない場合があります。ご自身の責任においてお試しください。
コメント