【Raspberry Pi】LCD1602Aにカタカナ表示機能を実装する

# はじめに
この記事は「ラズパイ5を使ってLCD1602Aを操作していこう！」という趣旨のものになります。

以前の記事で作成したプログラムをベースに改修を行いますので、先にご覧いただけますと幸いです！
1. [【Raspberry Pi】I2CアダプターなしでLCD1602Aに文字を表示する](https://qiita.com/ShibesSaico0401/items/2087ea0c3c7891d225c4)
2. [【Raspberry Pi】LCD1602Aに長文表示機能を実装する](https://qiita.com/ShibesSaico0401/items/d2c1e46530f7c8fce37f)


### ■成果物
・ラズパイ5でのLCD操作プログラム（カタカナ表示機能付き）
↓こんな感じで表示ができます↓
![IMG_0968(1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838080/4c89bbda-1db0-5557-b6c3-e19fc7c13d9e.gif)


# 動機
これまで第2回に渡ってラズパイからLCD1602Aを操作するプログラムを作成してきましたが
前回の記事では以下の課題が残っていました。

1. ASCII以外の文字に対応する
2. ~~write_four_bitsのEピン立ち上げ順序を修正~~
3. ~~長文の表示機能を追加~~
4. 部品モジュールとして使用する際の処理・API追加

今回はついに、一番需要が高いであろう1の課題を解決していきましょう！！
かなり力技が連発しますが、それではレッツゴー！


# ライブラリなど
- gpiozero 2.0
- Python 3.11.2

:::note warn
警告
本記事では文量の関係により、ライブラリのインストールなどの手順は記載しませんのでご注意ください。
諸兄が記事にされている内容で特に難しいことはないはずと思います。
:::


# LCD1602A とは
言わずもがなの16文字x2列の液晶ディスプレイです。
外観はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838080/e22b4e67-61b4-dc47-60c1-2b87b113d271.png)
詳細はぜひ[以前の記事](https://qiita.com/ShibesSaico0401/items/2087ea0c3c7891d225c4)をご参照ください！



### ■実装
まずはどういった改修を行えばカタカナ表示が行えるかですが…
端的に言うと、 __文字コードにある特定の上位ビットを送信できるようにコードを改造すれば可能__ であります！
（以下は以前の記事で載せた文字コード表を再掲）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838080/07f57816-524c-db7e-2f96-6e467feaa7bf.png)

赤枠で囲った部分ですね。
今までのコードに追加すべき機能は以下になります。
1. 赤枠で囲った範囲の上位ビット列を送信できるようにすること
2. 文字に対応した上位ビット（+下位ビット）を検索できるようにすること

では早速これらの機能を実装していきましょう。
過去に作成したプログラムのうち、LCD1602Aにビット列を送信しているのは以下の部分になります。
```python:python
    # 引数の文字をASCIIコード表に従って変換し、上位4ビット→下位4ビットの順に送信
    def write_char(self, char):
        GPIO.output(self.RS, GPIO.HIGH)
        self.write_four_bits(ord(char) >> 4)
        self.write_four_bits(ord(char) & 0x0F)
    
    # D4-7に文字データ送信
    def write_four_bits(self, data):
        # E立ち上げ後、データ送信
        self.E.on()
        self.D4.value = bool(data & 0x01)
        self.D5.value = bool(data & 0x02)
        self.D6.value = bool(data & 0x04)
        self.D7.value = bool(data & 0x08)
        
        # Eパルス幅の最小値x1.5倍の時間待機
        time.sleep(2.1e-7)
        self.E.off()
        time.sleep(0.0005)
```

現状では、write_charメソッドにて引数で受け取った文字をASCIIコード表に従って変換し、D4-D7ピンを経由してLCD1602Aに送信しています。

引数の文字は自動的にASCII文字に変換される処理となっていますが、ここに

1. __送りたい文字の範囲によってASCII文字なのか特殊文字コード表に則った文字なのかを区別する機能__ 
2. __特殊文字を検索し、対応するビット列を返す機能__

を付け加える必要があります。

よって、以下のようにwrite_charメソッドを改修します。
また、文字検索機能を実装するため、プログラム冒頭にWORD_DICT_LCD1602Aを定義するとともに、ヘルパーメソッドconvertCharを導入します。

```python:python
    # 文字データ表示(アルファベットと数字,演算記号:ASCII準拠)
    def write_char(self, char):
        display_char = "-"
        char_ASCII = ord(char)

        # ASCIIの範囲ならASCIIコードに沿って変換
        if char_ASCII >= 0x20 and char_ASCII <= 0x7F:
            display_char = ord(char)
        else: # ASCII以外なら独自変換表に沿って変換
            display_char = self.convertChar(char)
        
        self.RS.on()
        self.write_four_bits(display_char >> 4)
        self.write_four_bits(display_char & 0x0F)

    # ASCII以外の文字変換
    def convertChar(self, char):
        result_num = 0xFF # 塗りつぶし文字
        
        # 文字コード表に文字があれば検索して数値を返す
        if char in WORD_DICT_LCD1602A:
            result_num = WORD_DICT_LCD1602A[char]

        return result_num
```

```python:python
# LCD1602Aの文字変換辞書
WORD_DICT_LCD1602A ={"。":0xA1,
                     "「":0xA2,
                     "」":0xA3,
                     "、":0xA4,
                     "・":0xA5,
                     "ｦ":0xA6,
                     "ｧ":0xA7,
                     "ｨ":0xA8,
                     "ｩ":0xA9,
                     "ｪ":0xAA,
                     "ｫ":0xAB,
                     "ｬ":0xAC,
                     "ｭ":0xAD,
                     "ｮ":0xAE,
                     "ｯ":0xAF,
                     "ｰ":0xB0,
                     "ｱ":0xB1,
                     "ｲ":0xB2,
                     "ｳ":0xB3,
                     "ｴ":0xB4,
                     "ｵ":0xB5,
                     "ｶ":0xB6,
                     "ｷ":0xB7,
                     "ｸ":0xB8,
                     "ｹ":0xB9,
                     "ｺ":0xBA,
                     "ｻ":0xBB,
                     "ｼ":0xBC,
                     "ｽ":0xBD,
                     "ｾ":0xBE,
                     "ｿ":0xBF,
                     "ﾀ":0xC0,
                     "ﾁ":0xC1,
                     "ﾂ":0xC2,
                     "ﾃ":0xC3,
                     "ﾄ":0xC4,
                     "ﾅ":0xC5,
                     "ﾆ":0xC6,
                     "ﾇ":0xC7,
                     "ﾈ":0xC8,
                     "ﾉ":0xC9,
                     "ﾊ":0xCA,
                     "ﾋ":0xCB,
                     "ﾌ":0xCC,
                     "ﾍ":0xCD,
                     "ﾎ":0xCE,
                     "ﾏ":0xCF,
                     "ﾐ":0xD0,
                     "ﾑ":0xD1,
                     "ﾒ":0xD2,
                     "ﾓ":0xD3,
                     "ﾔ":0xD4,
                     "ﾕ":0xD5,
                     "ﾖ":0xD6,
                     "ﾗ":0xD7,
                     "ﾘ":0xD8,
                     "ﾙ":0xD9,
                     "ﾚ":0xDA,
                     "ﾛ":0xDB,
                     "ﾜ":0xDC,
                     "ﾝ":0xDD,
                     "ﾞ":0xDE,
                     "ﾟ":0xDF,
                     "α":  0xE0,
                     "a:": 0xE1,
                     "β":  0xE2,
                     "ε":  0xE3,
                     "μ":  0xE4,
                     "σ":  0xE5,
                     "p_": 0xE6, # 崩し字は"_"をつけることとする
                     "q_": 0xE7,
                     "√":  0xE8,
                     "^-1":0xE9,
                     "i":  0xEA,
                     "^x": 0xEB,
                     "Φ":  0xEC,
                     "も": 0xED,
                     "n^-":0xEE,
                     "o:": 0xEF,
                     "p":  0xF0,
                     "q":  0xF1,
                     "θ":  0xF2,
                     "∞":  0xF3,
                     "Ω":  0xF4,
                     "u:": 0xF5,
                     "Σ":  0xF6,
                     "π":  0xF7,
                     "x^-":0xF8,
                     "u":  0xF9,
                     "千":  0xFA,
                     "万":  0xFB,
                     "円":  0xFC,
                     "÷":  0xFD,
                     " ":  0xFE,
                     "■":  0xFF,
                     }
```

以上のコードでは __引数charをASCII文字に変換し、0x20（="!"）から0x7F（="←"）までの範囲に入っているか判定し、入っていなければ新たに定義した文字コードディクショナリから対応するビット列を検索する__ といった処理を行っています。

この処理の追加によって先程の機能1,2を追加できている、、、はず！


### ■動作確認・テスト
では、上で改修したwrite_charメソッドの動作確認をしてみましょう！
動作確認用のテストコードをこんな感じで作成してみました。

```python:python
def test_Katakana():
        lcd = None
        try:
            # GPIOピン番号は実際の接続に合わせて変更してください
            lcd = LCD1602A(rs=17, e=8, d4=25, d5=24, d6=23, d7=18)

            text1 = "ｶﾀｶﾅﾋｮｳｼﾞ"
            text2 = "ﾃﾞｷﾃﾙ?"
            lcd.print_row12(text1, text2)
            
            print("Press Enter to exit...")
            
            while True:
                # 標準入力に何か入力があるかチェック
                if select.select([sys.stdin,], [], [], 0.0)[0]:
                    # 入力があればループを抜ける
                    break

                time.sleep(0.1)  # CPU使用率を下げるための短い待機
        
        except Exception as e:
            print(f"エラーが発生しました: {e}")
        finally:
            if lcd:
                lcd.clear()
                lcd.print("Goodbye!")
                time.sleep(2)  # "Goodbye!"を2秒間表示
                lcd.close()
            print("プログラムを終了します。")
```

配線は[以前の記事](https://qiita.com/ShibesSaico0401/items/2087ea0c3c7891d225c4)のままなので省略！！

プログラムを実行して、LCDに
"ｶﾀｶﾅﾋｮｳｼﾞ"
"ﾃﾞｷﾃﾙ?"
と表示されれば成功です。
 
 さてさて、LCDの表示内容はどうなるでしょうか…
 
![IMG_0968(1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3838080/4c89bbda-1db0-5557-b6c3-e19fc7c13d9e.gif)

OK！無事カタカナが表示されました！


 # まとめ
というわけで今回は、LCD1602Aにカタカナを表示する機能を実装しました！
これで日本語のメッセージを表示したい場合に対応することができるようになりました、いぇい:v_tone1:


# 今後
1. ~~ASCII以外の文字に対応する~~
2. ~~write_four_bitsのEピン立ち上げ順序を修正~~
3. ~~長文の表示機能を追加~~
4. 部品モジュールとして使用する際の処理・API追加

今回、課題1が解決されたので、残る課題は4のみ！
最後はLCD1602Aを部品として何らかのシステムに組み込んだ際、処理を並列化するための機能を追加していこうと思っています。
（が、記事が長くなって書くのが大変そうな予感が満載なので、上がらなければ察してください:innocent:）


# 最後に
本日も乱文でありましたが、ご覧いただきありがとうございました！
これからも組み込みやIoTに関する記事を投稿していく予定ですので、よろしくお願いいたします。:blush: