お父にゃんの電子工作 -26ページ目

お父にゃんの電子工作

暇なおじさんが、電子工作(主にラジオ製作)をして勝手な感想を書く

前回、とても苦労したがRaspberry Pi Zero 2 Wで、Windows PCからリモートで接続して動かすことが出来るようになった。
これで、ようやくプログラムを作って試すことが出来る。
 
まずは、なんと言っても基本はLチカ。
とりあえず、GPIO4にLEDを繋いでおいた。
 
おじさんはRaspberry PiもPythonもズブの素人なので、ChatGPTにLチカのコードをお願いしてみる。
Raspberry Pi Zeroのスタートメニュー?からThonnyを立ち上げて、コピペして動かす。
 
Runボタンを押して動かすと、おお、ちゃんと動く。
 
 
次に、240×320dot カラーLCDを繋いでいく。
これはおじさんの以前の記事↓で試したもので、手元に残っていた。
ST7789というICで駆動するSPI接続のカラー液晶。
明るくて発色が良く、とてもきれいに表示してくれる。
ただ、バックライト制御端子が出ていないのでPWMによる輝度調整は出来ない。
あと、2インチなので、やや画面が小さい。
 
例によって、どのように動かすのか分からないので、ChatGPTに訊いてみる。
まずは、結線についての指示があったので、このように接続。
DCとRSTは任意のGPIOでOKらしい。
 
サンプルプログラムを書いてもらったが、また動かない。
しょうがないので、いろいろやり取りする。
ChatGPTの指示に従って、最初Pimoroni の st7789 ライブラリを使って動かそうとしたのだが、何故か動かない。
次に adafruit-circuitpython-st7789を使って動かそうとするも、何故か上手くいかない。
最後に Luma.lcd を使って動かしてみると、液晶に表示できるようになった
 
まとめると
●Luma.lcdのインストール
  sudo apt update
  sudo apt install python3-luma.lcd python3-pil
 
●日本語対応フォントがインストールされていないので、noto-cjkをインストール。
  sudo apt install fonts-noto-cjk
 
ChatGPTが書いた以下のコードを、Thonnyにコピペして実行
from luma.core.interface.serial import spi
from luma.lcd.device import st7789
from PIL import Image, ImageDraw, ImageFont
import RPi.GPIO as GPIO
 
GPIO.setwarnings(False)
 
# SPI接続
serial = spi(port=0, device=0, gpio_DC=24, gpio_RST=25)
 
# ディスプレイ (320x240 横長)
device = st7789(serial, width=320, height=240, rotate=0)
 
# 画像生成
image = Image.new("RGB", (320, 240), "black")
draw = ImageDraw.Draw(image)
 
# フォントの読み込み(サイズは適宜調整)
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
font = ImageFont.truetype(font_path, 32)
 
# 英数字描画
draw.text((20, 40), "Hello, World!", font=font, fill="white")
 
# 区切り線(横線)
draw.line((20, 90, 300, 90), fill="yellow", width=2)
 
# 日本語描画
draw.text((20, 120), "こんにちは世界", font=font, fill="cyan")
 
# 画面に表示
device.display(image)
 
ここまで、ずいぶんと苦労したが、ようやく動くように。
TrueTypeフォントなので文字がギザギザしてなくてきれい
 
次に、文字列が長い場合、普通にdraw.textで表示させると、画面にはみ出した文字は折り返して表示できない。
これも、ChatGPTにお願いして解決してもらう。
指定幅を超えると、折り返したtextを返すようにコードを書いてくれた。
 
で、それをベースにWebラジオをイメージして表示プログラムにしてみた
from luma.core.interface.serial import spi
from luma.lcd.device import st7789
from PIL import Image, ImageDraw, ImageFont
import RPi.GPIO as GPIO
 
GPIO.setwarnings(False)
 
# SPI設定
serial = spi(port=0, device=0, gpio_DC=24, gpio_RST=25)
device = st7789(serial, width=320, height=240, rotate=0)
 
# 描画用キャンバス
image = Image.new("RGB", (320, 240), "black")
draw = ImageDraw.Draw(image)
 
# フォント設定
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
font_bold = "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc"
font40 = ImageFont.truetype(font_bold, 40)
font32 = ImageFont.truetype(font_bold, 32)
font28 = ImageFont.truetype(font_path, 28)
font28_bold = ImageFont.truetype(font_bold, 28)
font20 = ImageFont.truetype(font_bold, 20)
 
#global
ch_no = 0
volume_level = 10
bit_rate = 128
station_name = "181.FM - Power 181  (Top 40)  US"
streamtitle = "Poppin'party(戸山香澄(愛美)、花園たえ(大塚紗英)、牛込りみ(西本りみ)、山吹沙綾(大橋彩香)、市ヶ谷有咲(伊藤彩沙)) - 開けたらDream!"
 
# 折り返し関数
def wrap_text(text, font, draw, max_width):
    lines = []
    line = ""
    for char in text:
        test_line = line + char
        w = draw.textbbox((0, 0), test_line, font=font)[2]
        if w <= max_width:
            line = test_line
        else:
            lines.append(line)
            line = char
    if line:
        lines.append(line)
    return lines
 
def show_ch():
    global ch_no , font40
    ch = "Ch:"+str(ch_no)
    draw.rectangle((0, 0, 160, 48), fill="black")
    draw.text((0, 0), ch, font=font40, fill="yellow")
 
def show_vol():
    global volume_level ,font32
    vol = "Vol:"+str(volume_level)
    draw.rectangle((140, 0, 259, 48), fill="black")
    draw.text((140, 10), vol, font=font32, fill="cyan")
 
def show_bitrate():
    global bit_rate ,font20
    bitr = str(bit_rate) + "K"
    draw.rectangle((240, 0, 320, 52), fill="black")
    draw.text((260, 0), bitr, font=font20, fill="magenta")
    draw.text((260, 20), "bps", font=font20, fill="magenta")
 
def show_station():
    global station_name,font28_bold
    draw.rectangle((0, 58, 320, 127), fill="black")
 
    station = station_name
    lines = wrap_text(station, font28_bold, draw, max_width=315)
    y = 54
    for line in lines:
        draw.text((0, y), line, font=font28_bold, fill="lime")
        bbox = font28.getbbox(line)
        line_height = bbox[3] - bbox[1]
        y += line_height  # 行間0
 
def show_streamtitle():
    global station_name,font28
    draw.rectangle((0, 129, 320, 240), fill="black")
 
    stream = streamtitle
    lines = wrap_text(stream, font28, draw, max_width=315)
    y = 129
    for line in lines:
        draw.text((0, y), line, font=font28, fill="white")
        bbox = font28.getbbox(line)
        line_height = bbox[3] - bbox[1]
        y += line_height  # 行間0
 
#イメージの作成
show_ch()
show_vol()
show_bitrate()
draw.line((0, 56, 320, 56), fill="orange", width=2)
show_station()
draw.line((0, 128, 320, 128), fill="orange", width=2)
show_streamtitle()
 
# 表示
device.display(image)
 
こんな感じ
 
拡大すると、こんな感じ。TrueType文字がきれい。
 
ああ、今回も最初はうまく動かなくて苦労した。
Arduino IDE環境なら簡単に動き出すのに、Raspberry Pi Zeroだと動き出すまでに、やたらと苦労するのである。
素人のおじさんにとって、つまずいたら二度と起き上がれなくなるのではないか?と思うくらいなのである。
まぁ、しょうがないから気長にぼちぼちやっていく。
 
 
「おいらも、起き上がるのに苦労するニャ」
いや、それはやばいって