うーん。

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

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)

関連記事