micro:bit Advent Calendar 2021の7日目の続きです。
今回は、ssd1306モジュールを7日目に作成した MicroPython で使えるようにしてみます。
I2C API の相違
ssd1306モジュールは machine.I2C モジュールの利用を前提にしていますが、micro:bit にはこのモジュールが無く、I2C の利用には microbit.i2cを使います。両者のAPIは多少違っているので、ssd1306モジュールを micro:bit 用に書き換える必要があります。具体的には以下のように書き換えてみました。
--- micropython/drivers/display/ssd1306.py 2021-11-27 19:36:01.000000000 +0900
+++ ssd1306.py 2021-12-10 00:29:43.000000000 +0900
@@ -114,17 +114,16 @@
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
- self.write_list = [b"\x40", None] # Co=0, D/C#=1
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.temp[0] = 0x80 # Co=1, D/C#=0
self.temp[1] = cmd
- self.i2c.writeto(self.addr, self.temp)
+ self.i2c.write(self.addr, self.temp)
def write_data(self, buf):
- self.write_list[1] = buf
- self.i2c.writevto(self.addr, self.write_list)
+ data = b'\x40' + bytes(buf)
+ self.i2c.write(self.addr, data)
class SSD1306_SPI(SSD1306):
mpremoteを使って、micro:bit に転送しておきます。
$ mpremote cp ssd1306.py :ssd1306.py
これで ssd1306
モジュールが micro:bit でも使えるようになりました。
動かしてみる
試しに 3D CUBE のアニメーションを動かしてみます。
I2C インタフェースの OLED と micro:bit のピンとは以下のように配線します。
OLED | micro:bit |
---|---|
VCC | 3V |
GND | GND |
SCL | 19 (SCL) |
SDA | 20 (SDA) |
# 3D CUBE MicroPython version with micro:bit and ssd1306 OLED
from microbit import i2c, sleep
from math import sin, cos
from ssd1306 import SSD1306_I2C
X = const(64)
Y = const(32)
oled = SSD1306_I2C(X * 2, Y * 2, i2c)
f = [[0.0 for _ in range(3)] for _ in range(8)]
cube = ((-20,-20, 20), (20,-20, 20), (20,20, 20), (-20,20, 20),
(-20,-20,-20), (20,-20,-20), (20,20,-20), (-20,20,-20))
while True:
for angle in range(0, 361, 3): # 0 to 360 deg 3step
for i in range(8):
r = angle * 0.0174532 # 1 degree
x1 = cube[i][2] * sin(r) + cube[i][0] * cos(r) # rotate Y
ya = cube[i][1]
z1 = cube[i][2] * cos(r) - cube[i][0] * sin(r)
x2 = x1
y2 = ya * cos(r) - z1 * sin(r) # rotate X
z2 = ya * sin(r) + z1 * cos(r)
x3 = x2 * cos(r) - y2 * sin(r) # rotate Z
y3 = x2 * sin(r) + y2 * cos(r)
z3 = z2
x3 = x3 + X
y3 = y3 + Y
f[i][0] = x3 # store new values
f[i][1] = y3
f[i][2] = z3
oled.fill(0) # clear
oled.line(int(f[0][0]), int(f[0][1]), int(f[1][0]), int(f[1][1]), 1)
oled.line(int(f[1][0]), int(f[1][1]), int(f[2][0]), int(f[2][1]), 1)
oled.line(int(f[2][0]), int(f[2][1]), int(f[3][0]), int(f[3][1]), 1)
oled.line(int(f[3][0]), int(f[3][1]), int(f[0][0]), int(f[0][1]), 1)
oled.line(int(f[4][0]), int(f[4][1]), int(f[5][0]), int(f[5][1]), 1)
oled.line(int(f[5][0]), int(f[5][1]), int(f[6][0]), int(f[6][1]), 1)
oled.line(int(f[6][0]), int(f[6][1]), int(f[7][0]), int(f[7][1]), 1)
oled.line(int(f[7][0]), int(f[7][1]), int(f[4][0]), int(f[4][1]), 1)
oled.line(int(f[0][0]), int(f[0][1]), int(f[4][0]), int(f[4][1]), 1)
oled.line(int(f[1][0]), int(f[1][1]), int(f[5][0]), int(f[5][1]), 1)
oled.line(int(f[2][0]), int(f[2][1]), int(f[6][0]), int(f[6][1]), 1)
oled.line(int(f[3][0]), int(f[3][1]), int(f[7][0]), int(f[7][1]), 1)
oled.line(int(f[1][0]), int(f[1][1]), int(f[3][0]), int(f[3][1]), 1)
oled.line(int(f[0][0]), int(f[0][1]), int(f[2][0]), int(f[2][1]), 1)
oled.text('3D CUBE', 0, 0)
oled.show() # display
sleep(1)
めでたく動きました。
$ mpremote cp main.py :main.py