HOME | Raspberry Pi | ビジネス書籍紹介 | 2026-01-04 (Sun) Today's Access : 194 Total : 1260892. Since 10 Sep. 2019

疑似コンソール
2021.03.06

YouTube でも紹介しています。画像をクリックすると再生できます。

今回は、Adafruit 1.3" Color TFT Bonnet for Raspberry Pi を Raspberry Pi Zero WH の疑似コンソールとして使用します。
このLCDを、システムコンソールとして設定することも可能ですが、カーネルドライバーを書き換えてしまうため、元に戻すのが面倒です。 そこで、Pythonアプリケーションからシステムコンソールのように使えるライブラリーを作成します。


Pimoroni のサイトを散策していたときのことです。普段、アクセスすることのない「Gaming & Arcade」のカテゴリーを間違ってぽちっとしてしまい、運よく発見しちゃいました!
ちなみに、画面右側に写っている「Pico Explorer Base」もお買い上げです!


「ボタンとジョイスティックを備えたコンパクトなカラーディスプレイが必要なあなたにぴったりの商品です」と書かれているではありませんか。 システムコンソールを探していたのですが、このデザインの美しさ!買わないわけにはいきません!ぽちっ!

■とても美しい外観

フロントデザインです。

当然の事なのですが、背面には2x20ピンの Raspberry Pi connector が配置されています。


システムコンソールとして使用した場合です。

■Pinouts

・5.0V - Connected to the display backlight
・3.3V - Connected to the display power and also the STEMMA QT / Qwiic connector
・GND - Ground for everything
・SDA & SCL - I2C data for the STEMMA QT / Qwiic connector. Not used by buttons or display
・GPIO26 - Used to turn the backlight on and off.
・GPIO5 & GPIO6 - Connected to the two front buttons. These pins have 10K pullups to 3.3V so when the button is pressed, you will read a LOW voltage on these pins
・GPIO17, GPIO22, GPIO27, GPIO23 - The four directions on the joystick.
・GPIO4 - Joystick center button.
・SCK, MOSI, CE0 & GPIO25 - These are the display control pins. Note that MISO is not connected even though it is a SPI pin because you cannot read back from the display.
・Not used: GPIO12, GPIO13, GPIO16, GPIO19, GPIO20, GPIO21, GPIO18, GPIO24, TXD, RXD, EEDATA, EECLK, MISO, SPI_CE1

■SPIの有効化
$ sudo vi /boot/config.txt
dtparam=spi=on

■動作環境の整備

Adafruit TFT Bonnet のセットアップは下記のようになっています。
Ref.Python Setup
$ sudo pip3 install adafruit-circuitpython-rgb-display
$ sudo apt-get install python3-pip
$ sudo apt-get install ttf-dejavu
$ sudo apt-get install python3-pil
$ sudo apt-get install python3-numpy
※今回はインストールしていません。


What is CircuitPython?

Adafruit では実行環境に microPython系の CircuitPython を利用してします。 しかし、これを使うと、汎用性が低下してしまうので、標準の ST7789ライブラリーを用いることにします。

Pimoroni 1.3" SPI LCDのサンプルコードを参考にしました。
PIMORONI 1.3" SPI Colour LCD (240x240) Breakout


AdafruitとPimoroniのLCDで使用するピン番号をみてみました。
No AdafruitDescription Pimoroni
3.3V 1 display backlight 1
5V 2 display power 2
GND 6 6
SPI_MOSI19(BCM10) display control 19(BCM10)
SPI_SCLK23(BCM11) display control 23(BCM11)
TFT_DC 22(BCM25) display control 21(BCM9)
TFT_CS 24(CE0/BCM8)display control 26(CE1/BCM7)
TFT_LITE37(BCM26) backlight on and off35(BCM19)
DCとCSおよびbacklightのピン番号が異なっていることがわかります。
※ジョイスティックやボタンの機能は省いています。

まずは、ST7789ディスプレイドライバ用のモジュールをインストールします。

$ sudo pip3 install st7789

Raspberry Pi OS であれば、st7789 が依存するモジュールはすでにインストール済と思われますが、 必要なら、追加インストールしてください。
$ sudo pip3 install pillow
$ sudo pip3 install numpy
$ sudo pip3 install RPI.GPIO
$ sudo pip3 install spidev


scrolling-text.py
先に示した対応表を参考に、Pimoroniで使用しているピン番号から、Adafruit用にピン番号を書き換えます。
disp = ST7789.ST7789(
    port=0,
    cs=ST7789.BG_SPI_CS_FRONT,
    dc=9,
    backlight=19,
    spi_speed_hz=80 * 1000 * 1000
)

 ↓変更

disp = ST7789.ST7789(
    port=0,
    cs=ST7789.BG_SPI_CS_BACK,
    dc=25,
    backlight=26,
    spi_speed_hz=80 * 1000 * 1000
)
ST7789.BG_SPI_CS_FRONT は CE1 の指定なので、ST7789.BG_SPI_CS_BACK に変更して CE0 に変更します。

Source code
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import time

import ST7789


MESSAGE = "Hello World! How are you today?"

# Create ST7789 LCD display class.
disp = ST7789.ST7789(
    port=0,
    cs=ST7789.BG_SPI_CS_BACK,  # BG_SPI_CS_BACK or BG_SPI_CS_FRONT
    dc=25, 
    backlight=26,               # 18 for back BG slot, 19 for front BG slot.
    spi_speed_hz=80 * 1000 * 1000
)

# Initialize display.
disp.begin()

WIDTH = disp.width
HEIGHT = disp.height


img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))

draw = ImageDraw.Draw(img)

font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 30)

size_x, size_y = draw.textsize(MESSAGE, font)

text_x = disp.width
text_y = (80 - size_y) // 2

t_start = time.time()

while True:
    x = (time.time() - t_start) * 100
    x %= (size_x + disp.width)
    draw.rectangle((0, 0, disp.width, 80), (0, 0, 0))
    draw.text((int(text_x - x), text_y), MESSAGE, font=font, fill=(255, 255, 255))
    disp.display(img)

実行してみましょう。
$ python3 scrolling-text.py


動作確認ができたので、次に疑似コンソール用ライブラリーを作成していきます。

■等幅フォントの確認

システムで利用可能な等幅フォントを確認します。
$ fc-match monospace
LiberationMono-Regular.ttf: "Liberation Mono" "Regular"

フォントの場所は下記の通りです。
/usr/share/fonts/truetype/liberation2/LiberationMono-Regular.ttf

他の等幅フォントを利用したい場合は、適時インストールしてください。

■リングバッファ


File:Ring.buffer.svg - Wikimedia Commons
リングバッファは、予め記憶領域を確保して、読み出し位置と書き込み位置をずらしながら処理を行い、領域の終端に到達したら、領域の先頭に繋げ無限ループ的に利用する仕組みです。 C言語などで開発する場合は、ポインターを使って、テキスト文字列を上書きしていけば済むのですが、Pythonではそういう使い方はできません。
コーディング的に美しくないのですが、リストを使ってリングバッファーっぽいものを実装します。

1.LCDの描画サイズを取得します
disp.begin()
pixel_x = disp.width
pixel_y = disp.height

2.等幅フォントのサイズを取得します
font = ImageFont.truetype("/usr/share/fonts/truetype/liberation2/LiberationMono-Regular.ttf",14)
size_x, size_y = self.draw.textsize("F", font=font)

3.LCDサイズとフォントサイズから1行に表示できる桁数と行数を算出します
col = pixel_x // size_x
row = pixel_y // size_y

4.表示したい文字列を桁数で分割して、複数の配列要素として保存します
line_len = len(msg)
line_num = line_len//col
line_rest = line_len % col
line_from = 0
line_to = col
while line_num > 0:
 buffer[pos] = msg[line_from:line_to]
 line_from += col
 line_to += col
 pos += 1
 line_num -= 1
if line_rest > 0:
 buffer[pos] = msg[line_from:line_len]
 pos += 1

5.表示行数未満の場合は、リストの先頭要素から、LCDに描画します
pos_y = 0
draw.rectangle((0, 0, disp.width, disp.height), (0, 0, 0))
for i in range(row):
 draw.text((0,pos_y), buffer[start], font=font, fill=(255, 255, 255))
 start += 1
 pos_y += size_y
 if start == row:
  start = 0
disp.display(img)

6.再度、表示文字列を追加する場合は、直前に保存した次の配列要素に追加します
 この際、配列が末尾に到達した場合には配列の先頭要素から書き換えます
7.更新した配列要素数に応じてリストの途中から循環する形で、LCDを再描画します

6, 7 に関しては短いコードなので、下記のソースを解析してみてください。

疑似コンソール Source code
from PIL import Image, ImageDraw, ImageFont
import ST7789

class Console:
	def __init__(self):

		# Create ST7789 LCD display class.
		self.disp = ST7789.ST7789(
			port=0,
			cs=ST7789.BG_SPI_CS_BACK,
			dc=25, 
			backlight=26,
			spi_speed_hz=80 * 1000 * 1000
		)

		# Initialize display.
		self.disp.begin()
		self.pixel_x = self.disp.width
		self.pixel_y = self.disp.height
		self.img = Image.new('RGB', (self.pixel_x, self.pixel_y), color=(0, 0, 0))
		self.draw = ImageDraw.Draw(self.img)

		self.size_x, self.size_y = self.getFontSize()
		self.col  = self.pixel_x // self.size_x
		self.row  = self.pixel_y // self.size_y
		self.buffer = ["" for _ in range(self.row)]
		self.pos   = 0
		self.start = 0
		self.scroll = False

	def getFontSize(self,fontName=None, fontSize=None):
		if fontName is None:
			self.font = ImageFont.truetype("/usr/share/fonts/truetype/liberation2/LiberationMono-Regular.ttf",14)
		else:
			self.font = ImageFont.truetype(fontName, fontSize)
		self.size_x, self.size_y = self.draw.textsize("F", font=self.font)
		return self.size_x, self.size_y

	def print(self, msg):
		line_len  = len(msg)
		line_num  = line_len//self.col
		line_rest = line_len % self.col
		line_from = 0
		line_to   = self.col
		while line_num > 0:
			if self.scroll:
				self.start += 1
				if self.start == self.row:
					self.start = 0
			self.buffer[self.pos] = msg[line_from:line_to]
			line_from += self.col
			line_to   += self.col
			self.pos += 1
			if self.pos == self.row:
				self.pos = 0
				self.scroll = True
			line_num -= 1
		if line_rest > 0:
			if self.scroll:
				self.start += 1
				if self.start == self.row:
					self.start = 0
			self.buffer[self.pos] = msg[line_from:line_len]
			self.pos += 1
			if self.pos == self.row:
				self.pos    = 0
				self.scroll = True

		pos_y = 0
		self.draw.rectangle((0, 0, self.disp.width, self.disp.height), (0, 0, 0))
		for i in range(self.row):
			self.draw.text((0,pos_y), self.buffer[self.start], font=self.font, fill=(255, 255, 255))
			self.start += 1
			pos_y += self.size_y
			if self.start == self.row:
				self.start = 0
		self.disp.display(self.img)

使用する場合は、RingBuffer.py をカレントディレクトリーに置いて下記のように呼び出します。
文字列の描画位置を意識することなしに利用できます。

from RingBuffer import Console

cs = Console()
cs.print(message1)
cs.print(message2)
・・・・・

ソースコードにちょっと手を加えるとこんな感じになります。

メッセージ単位で交互に色分けして表示しています。

このコンソール機能は、Twelite Neural Network 第2回で使用する予定です。

■参考文献
等幅フォント
Raspberry Pi(stretch)フォント設定 noto font
ラズパイでフレームバッファ(/dev/fb0)を使用して、直接ディスプレイ画像を入出力する
【 fc-match 】コマンド――フォントのマッチングと優先順位を確認する
原色大辞典
Raspberry Pi(ラズベリー パイ)は、ARMプロセッサを搭載したシングルボードコンピュータ。イギリスのラズベリーパイ財団によって開発されている。
2019.12.13 モバイルバッテリーによる瞬間停電対策
2020.01.01 1280x800 HDMI MONITOR
2020.01.12 micro:bitをコマンドラインで使う
2020.02.04 サーマルプリンタを使う
2020.04.10 電卓を制御して数字を表示する
2020.08.03 Seeeduino XIAO
2020.08.09 LGT8F328P - Arduino clone
2020.09.18 電流計測モジュール INA219
2021.02.16 癒しの電子回路
2021.03.06 疑似コンソール
2021.08.08 電子ペーパー
2021.09.04 AVRマイコン・ATTiny85
2021.09.25 pH測定
2021.11.13 NTP時刻取得と活用
2021.11.27 GPS情報取得
2021.12.11 GR-KURUMI
2021.12.25 ATMEGA328P 3.3V/8MHz
2022.01.11 AS-289R2 プリンタシールド
2022.01.25 TM1637 & ATtiny85
2022.02.22 Raspberry Pi Zero 小道具
2022.03.01 ATTinyCore
2022.03.18 Adafruit QT Py + XIAO Expansion board
2022.07.31 サーマルプリンター番外編:通信筒
2023.01.01 FTP Server & SPI Flash SD
2023.02.01 LPC810(ARM Cortex-M0+)
2023.02.15 IchigoJam互換機
2023.03.01 Telnet
2023.04.26 USBメモリをUART接続で利用する
2023.05.14 焦電型赤外線モーションセンサー
2023.07.01 文字化けしないキーボード
2023.08.01 Bluetoothサーマルプリンター
2023.08.12 LattePanda 2G/32GB
2023.09.04 SI-3012KS
2023.12.01 疑似コンソール(C言語編)
2023.12.16 昭和レトロ・温度湿度時刻計
2023.12.25 二酸化炭素濃度監視
2024.01.23 なんちゃってmicro:bit
2024.02.07 オリジナル micro:bit
2024.02.23 ESP32 OTA
2024.03.08 TELNETサーマルプリンター
2024.05.08 ESP32 PROGRAM SELECTOR
2024.05.23 統合開発環境とQwiic
2025.01.24 赤外線リモコン
2025.03.25 QRCode SCANNER
2025.04.08 Keyestudio 328 WiFi Plus
2025.08.23 NanoPi NEO3
2025.09.24 I2C接続microSDモジュール
2025.10.08 UNO 3.3V@8MHz

たいていのことは100日あれば、うまくいく。長田英知著
「時間がなくて、なかなか自分のやりたいことができない」 「一念発起して何かを始めても、いつも三日坊主で終わってしまう」 「色んなことを先延ばしにしたまま、時間だけが過ぎていく」 そこで本書では、そんな著者が独自に開発した、 まったく新しい目標達成メソッド「100日デザイン」について、 その知識と技術を、余すところなくご紹介します。

まんがで納得ナポレオン・ヒル 思考は現実化する
OLとして雑務をこなす日々に飽き足らず、科学者だった父が残した薬品を商品化すべく、起業を決意した内山麻由(27)。彼女はセミナーで知り合った謎の女性からサポートを得ながら、彼女と二人三脚でナポレオン・ヒルの成功哲学を実践し、さまざまな問題を乗り越えていく。 ヒル博士の<ゴールデンルール>に従い、仕事に、恋に全力疾走する彼女の、成功への物語。

今日は人生最悪で最高の日 1秒で世界を変えるたったひとつの方法 ひすいこたろう著
偉人の伝記を読むと、最悪な日は、不幸な日ではなく、新しい自分が始まる日であることがわかります。最悪な出来事は、自分の人生が、想像を超えて面白くなる兆しなのです。偉人伝を読むことで、このときの不幸があったおかげで、未来にこういう幸せがくるのかと、人生を俯瞰する視線が立ち上がるのです。

ご飯は私を裏切らない heisoku著
辛い現実から目を背けて食べるご飯は、いつも美味しく幸せを届けてくれる。 29歳、中卒、恋人いない歴イコール年齢。バイト以外の職歴もなく、短期バイトを転々とする日々。ぐるぐると思索に耽るけど、ご飯を食べると幸せになれる。奇才の新鋭・heisokuが贈るリアル労働グルメ物語!

【最新版Gemini 3に対応!】できるGemini (できるシリーズ)
Geminiを「最強の知的生産パートナー」として使いこなすための、実践的なノウハウを凝縮した一冊です。 基本的な操作方法から、具体的なビジネスシーンでの活用、日々の業務を自動化するGoogle Workspaceとの連携、さらには自分だけのオリジナルAIを作成する方法まで余すところなく解説します。

Rustプログラミング完全ガイド 他言語との比較で違いが分かる!
Rustの各手法や考え方を幅広く解説! 500以上のサンプルを掲載。実行結果も確認。 全24章の包括的なチュートリアル。

ポチらせる文章術
販売サイト・ネット広告・メルマガ・ブログ・ホームページ・SNS… 全WEB媒体で効果バツグン! カリスマコピーライターが教える「見てもらう」「買ってもらう」「共感してもらう」すべてに効くネット文章術

小型で便利な Type-C アダプター USB C オス - USB3.1 オスアダプター
Type-C端子のマイコンボードをこのアダプタを介して直接Raspberry Piに挿すことができます。ケーブルなしで便利なツールです。

Divoom Ditoo Pro ワイヤレススピーカー
15W高音質重低音/青軸キーボード/Bluetooth5.3/ピクセルアート 専用アプリ/USB接続/microSDカード

電源供給USBケーブル スリム 【5本セット】
USB電源ケーブル 5V DC電源供給ケーブル スリム 【5本セット】 電源供給 バッテリー 修理 自作 DIY 電子工作 (100cm)

Copyright © 2011-2027 Sarako Tsukiyono All rights reserved®.