うーん。

タイトルやここで行っていることは、どういう表現が適切なんでしょうねえ。

MicroPythonの標準的なOLEDディスプレイドライバssd1306では、文字列の出力はtext()メソッドを使用して、座標を指定して出力するようになっています。

コンピュータの文字出力用のコンソールあるいは端末では、ただ文字列を出力すると、文字が左から右に、上から下に、下の端に行きついたら外面が上にスクロールして表示されますよね。

あのある意味普通で御気楽な文字列出力機能が欲しいので、そのドライバを作りました。

OLEDCSドライバ

TFTディスプレイ用などOLEDディスプレイだけではない幅広い拡張性を考えると、ssd1306ドライバの基礎になるFrameBufferを拡張すべきなのですが、そうすると、それを継承する標準のssd1306を書き換える必要が出てきます。特にESP8266では、ssd1306がファームウェアに組み込まれているので、ファームウェアの再構築などをしてssd1306ドライバを置き換えるのは面倒です。

ということで、ssd1306ドライバ(のSSD1306_I2C)を拡張する形で実装したドライバ例を示します。ssd1306ドライバがスーパークラスですが拡張機能の一部として、1.3インチのOLEDディスプレイに多用されているSSH1106も利用できるようにしております。

"""
OLEDCS_I2C OLED Display Driver (ssd1306, ssh1106)
for MicroPython
Version 1.0

Copyright 2023 K.Kakizaki
OLEDCSライブラリ: OLEDディスプレイのコンソール的利用 (MicroPython)
""" import ssd1306 from micropython import const class OLEDCS_I2C(ssd1306.SSD1306_I2C): SSD1306 = const(0) SSH1106 = const(1) SET_LOW_COL = const(0x00) SET_HIGH_COL = const(0x10) SET_PAGE_ADDR = const(0xb0) def __init__(self, width, height, i2c, chip=SSD1306, addr=0x3C, external_vcc=False): self._cx = 0 self._cy = 0 self._chip = chip super().__init__(width, height, i2c, addr, external_vcc) def print(self, text): txt = str(text) while (txt.find('\n') > 0): idx = txt.index('\n') ctxt = txt[0:idx] txt = txt[idx+1:] self.println(ctxt) l = len(txt) while (l + self._cx > self.width // 8): cl = self.width // 8 - self._cx l = l - cl ctxt = txt[0:cl] txt = txt[cl:] self.text(ctxt, self._cx*8, self._cy*8,1) self._scroll_check() self.text(txt, self._cx*8, self._cy*8,1) self._cx += l self.show() def println(self, text=''): self.print(text) self._scroll_check() self.show() def _scroll_check(self): self._cx = 0 self._cy += 1 if (self._cy * 8 >= self.height): self._cy -= 1 self.scroll(0, -8) self.fill_rect(0, self.height-8, self.width-1, self.height-1, 0) def setCursor(self, x, y): self._cx = x self._cy = y def getCursor(self): return (self._cx, self._cy) def clear(self): self.fill(0) self.setCursor(0,0) self.show() def show(self): if self._chip == SSD1306: super().show() else: for page in range(0, self.pages): self.write_cmd(SET_PAGE_ADDR | page) self.write_cmd(SET_LOW_COL | 2) self.write_cmd(SET_HIGH_COL | 0) self.write_data(self.buffer[page * 128:(page + 1) * 128])

OLEDCSの機能概要

oledcsの追加メソッドを紹介します。oledcsはssd1306を継承して作成しているので、従来のssd1306の機能はグラフィックスを含めて同様に使用できます。

  • print(obj) 文字列だけでなく、数値、オブジェクトなどstr()関数で文字列化可能なものは一通り出力できます。文字列の中に改行文字'\n'があればそこで改行します。
  • println(obj) print(obj)の最後に改行機能を加えたものです。引数が指定されていなければ改行のみを行います。
  • setCursor(x,y) 文字カーソルを指定した位置に移動させます。xは横、yは縦軸です
  • getCursor() 文字カーソルの現在位置を返します。
  • clear() 画面を消去し文字カーソルを(0, 0)に設定します。

なお、上記のメソッドでは、画面の変更を表示に反映させるためのshow()メソッドを使用する必要はありません。

OLEDCSの利用例

oledcsの利用例を示します。従来は、ssd1306をインポートしSSD1306_I2Cをインスタンス化していましたが、そこをoledcsとOLEDCS_I2Cに置き換えると、これまでのプログラムと同様に動きます。

従来と同じ機能だけだと価値がありませんが、いちいち表示位置を指定せずにprint(), println()が使えるところが強みですね。

長い文字列でも行の右端で改行して出力されること、改行文字があればそこで改行されること、最下行の出力では、必要に応じて画面がスクロールすることなどが確認できます。

from machine import Pin, I2C
from oledcs import OLEDCS_I2C
import time

i2c = I2C(0) # STM32 は3
# i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=400000) # ESP32-S3, ESP32-C3
# i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000) # ESP32
# i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) # ESP8266
# i2c = I2C(0, scl=Pin(13), sda=Pin(12), freq=400000) # RP2040
oled = OLEDCS_I2C(128, 64, i2c)

oled.println('123456789012345678901234567890')
time.sleep(3)

for i in range(1,20):
    oled.print('OLED-')
    oled.println('{:.3f}'.format(1/i))
time.sleep(3)

oled.println('OLEDCS Driver for MicroPython Version 1.0\nCopyright 2023 K.Kakizaki')

SSH1106への対応

インスタンスの生成時にコントローラチップを特に指定しない場合には、SSD1306を使用した0.96インチのOLEDディスプレイを想定して処理を行いますが、以下の例のように、コントローラチップとしてSSH1106を指定すると、1.3インチディスプレイを操作することができます。

# oled = OLEDCS_I2C(128, 64, i2c)

# コントローラチップとしてSSH1106を指定
oled = OLEDCS_I2C(128, 64, i2c, chip=OLEDCS_I2C.SSH1106)

関連記事