Raspberry Pi Pico WH + MicroPython でOLEDディスプレイ用のデモ動画を作成してみました

0.96インチのI2C接続OLED(128×64ドット)に表示するデモです。

Arduino環境では、Adafruit作成のものがあるようですが、micropythonだとデモが存在しないため、自作してみました。

表示する図形によって表示速度が遅かったり一瞬静止したりする理由は、SPI接続、MicroPython、またはコード上の問題なのか。
RP2040の性能限界ではないと思いますが、よく分かりません。

苦労した点は、random.sampleがないため、自作で関数定義したのと、あとは星のscroll部分を、再帰で処理したことです。

現状の力量はこの程度しかありませんが、コード上の問題点や改良点など教えて頂ければ励みになります。
よろしくお願いします。

追記：
同じコードをCircuitPythonで走らせてみましたが、描画はとても遅くて体感的には1/10程度。このあたりは、情報どおりでした。


```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import machine
import ssd1306
import time
import random
import math
import string

sda = machine.Pin(0)
scl = machine.Pin(1)
i2c = machine.I2C(0,sda=sda, scl=scl, freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)

#中心
xc = 64
yc = 32
ycp = 36
yct = 42
#左上
x1 = 0
y1 = 0
#右上
x2 = 128
y2 = 0
#右下
x3 = 128
y3 = 64
#左下
x4 = 0
y4 = 64
#対角線の長さ
r = 142.3
r2 = 71
r3= 48

#pentagram、star用変数
a1 = 0- math.pi/10
a2 = 2*math.pi/5- math.pi/10
a3 = 4*math.pi/5- math.pi/10
a4 = 6*math.pi/5- math.pi/10
a5 = 8*math.pi/5- math.pi/10

ra2 = round(a2, 1)
ra3 = round(a3, 1)
ra4 = round(a4, 1)
ra5 = round(a5, 1)

s1x = math.cos(a1)
s1y = math.sin(a1)
s2x = math.cos(ra2)
s2y = math.sin(ra2)
s3x = math.cos(ra3)
s3y = math.sin(ra3)
s4x = math.cos(ra4)
s4y = math.sin(ra4)
s5x = math.cos(ra5)
s5y = math.sin(ra5)

LETTERS = string.ascii_letters

def draw_lines1():
    for i in range(90, 27, -1):
        xi = r*math.cos(math.radians(i))
        yi = r*math.sin(math.radians(i))    
        rxi = round(xi, 1)
        ryi = round(yi, 1)
        x11 = x1 + rxi
        y11 = y1 + ryi    
        oled.line(x1, y1, int(x11), int(y11), 1)
        oled.show()

    for j in range(0, 63, 1):
        xj = r*math.cos(math.radians(j))
        yj = r*math.sin(math.radians(j))
        rxj = round(xj, 1)
        ryj = round(yj, 1)
        x12 = x1 + rxj
        y12 = y1 + ryj  
        oled.line(x1, y1, int(x12), int(y12), 1)
        oled.show()     
    
    oled.fill(0)
    oled.show()

def draw_lines2():
    for i in range(90, 153, 1):  
        xi = r*math.cos(math.radians(i))
        yi = r*math.sin(math.radians(i)) 
        rxi = round(xi, 1)
        ryi = round(yi, 1)  
        x21 = x2 + rxi
        y21 = y2 + ryi  
        oled.line(x2, y2, int(x21), int(y21), 1)
        oled.show()
    
    for j in range(180, 153, -1):
        xj = r*math.cos(math.radians(j))
        yj = r*math.sin(math.radians(j))   
        rxj = round(xj, 1)
        ryj = round(yj, 1)      
        x22 = x2 + rxj
        y22 = y2 + ryj   
        oled.line(x2, y2, int(x22), int(y22), 1)
        oled.show()
        
    oled.fill(0)
    oled.show()

def draw_lines3():
    for i in range(180, 207, 1):
        xi = r*math.cos(math.radians(i))
        yi = r*math.sin(math.radians(i)) 
        rxi = round(xi, 1)
        ryi = round(yi, 1)  
        x31 = x3 + rxi
        y31 = y3 + ryi    
        oled.line(x3, y3, int(x31), int(y31), 1)
        oled.show()      

    for j in range(270, 207, -1):   
        xj = r*math.cos(math.radians(j))
        yj = r*math.sin(math.radians(j))     
        rxj = round(xj, 1)
        ryj = round(yj, 1)      
        x32 = x3 + rxj
        y32 = y3 + ryj  
        oled.line(x3, y3, int(x32), int(y32), 1)
        oled.show()

    oled.fill(0)
    oled.show()

def draw_lines4():
    for i in range(360, 333, -1):
        xi = r*math.cos(math.radians(i))
        yi = r*math.sin(math.radians(i))   
        rxi = round(xi, 1)
        ryi = round(yi, 1)     
        x41 = x4 + rxi
        y41 = y4 + ryi        
        oled.line(x4, y4, int(x41), int(y41), 1)
        oled.show()

    for j in range(270, 333, 1):  
        xj = r*math.cos(math.radians(j))
        yj = r*math.sin(math.radians(j))     
        rxj = round(xj, 1)
        ryj = round(yj, 1)     
        x42 = x4 + rxj
        y42 = y4 + ryj  
        oled.line(x4, y4, int(x42), int(y42), 1)
        oled.show()
 
    oled.fill(0)
    oled.show()

def draw_linesC():
    for i in range(0, 90, 1):
        xi1 = r2*math.cos(math.radians(i))
        yi1 = r2*math.sin(math.radians(i))    
        xi2 = r2*math.cos(math.radians(i+90))
        yi2 = r2*math.sin(math.radians(i+90))      
        xi3 = r2*math.cos(math.radians(i+180))
        yi3 = r2*math.sin(math.radians(i+180))        
        xi4 = r2*math.cos(math.radians(i+270))
        yi4 = r2*math.sin(math.radians(i+270))       
        rxi1 = round(xi1, 1)
        ryi1 = round(yi1, 1)
        rxi2 = round(xi2, 1)
        ryi2 = round(yi2, 1)
        rxi3 = round(xi3, 1)
        ryi3 = round(yi3, 1)
        rxi4 = round(xi4, 1)
        ryi4 = round(yi4, 1)
        xc1 = xc + rxi1
        yc1 = yc + ryi1
        xc2 = xc + rxi2
        yc2 = yc + ryi2        
        xc3 = xc + rxi3
        yc3 = yc + ryi3        
        xc4 = xc + rxi4
        yc4 = yc + ryi4                     
        oled.line(xc, yc, int(xc1), int(yc1), 1)
        oled.line(xc, yc, int(xc2), int(yc2), 1)
        oled.line(xc, yc, int(xc3), int(yc3), 1)
        oled.line(xc, yc, int(xc4), int(yc4), 1)
        oled.show()

def draw_rect():
    for i in range(32):
        oled.rect(0+i,0+i, 128-2*i, 64-2*i, 0)
        oled.show()

def draw_rect2():
    for i in range(0,31, 6):
        for j in range(3):
            oled.rect(i+j, i+j, 128-2*(i+j), 64-2*(i+j), 1)
        oled.show()
        time.sleep_ms(10)
        oled.invert(1)
        oled.show()
        time.sleep_ms(10)
        oled.invert(0)
        oled.show()
        time.sleep_ms(10)
        
    oled.fill(0)
    oled.show()

def draw_circle():
    for k in range(0, 45, 3):
        for j in range(1, 4):
            for i in range(360):
                xi = (k+j)*math.cos(math.radians(i))
                yi = (k+j)*math.sin(math.radians(i))               
                rx = round(xi, 1)
                ry = round(yi, 1)
                x = xc + rx
                y = yc + ry
                oled.pixel(int(x), int(y), 1)
        oled.show()

def draw_circle2():
    for k in range(45, -4, -6):
        for j in range(1, 4):
            for i in range(360):
                xi = (k+j)*math.cos(math.radians(i))
                yi = (k+j)*math.sin(math.radians(i))             
                rx = round(xi, 1)
                ry = round(yi, 1)
                x = xc + rx
                y = yc + ry
                oled.pixel(int(x), int(y), 0)
        oled.show()
        time.sleep_ms(10)   
        oled.invert(1)
        oled.show()
        time.sleep_ms(10)
        oled.invert(0)
        oled.show()
        time.sleep_ms(10) 

    oled.fill(0)
    oled.show()

def draw_triangle():
    for ri in range(0,37, 9):
        for j in range(3):
            x30 = (ri+j)*math.cos(math.radians(30))
            y30 = (ri+j)*math.sin(math.radians(30))
            x150 = (ri+j)*math.cos(math.radians(150))
            y150 = (ri+j)*math.sin(math.radians(150))
            x270 = (ri+j)*math.cos(math.radians(270))
            y270 = (ri+j)*math.sin(math.radians(270))       
            rx30 = int(x30)
            ry30 = int(y30)
            rx150 = int(x150)
            ry150 = int(y150)
            rx270 = int(x270)
            ry270 = int(y270)    
            oled.line(xc+rx30, yct+ry30, xc+rx150, yct+ry150, 1)
            oled.line(xc+rx150, yct+ry150, xc+rx270, yct+ry270, 1)
            oled.line(xc+rx270, yct+ry270, xc+rx30, yct+ry30, 1)
        oled.invert(1)
        oled.show()
        time.sleep_ms(50)
        oled.invert(0)
        oled.show()
        time.sleep_ms(50)
    
    oled.fill(0)
    oled.show()

def draw_pentagram():
    for i in range(0, 37, 6):
        for j in range(3):
            oled.line(xc+int(s1x*(i+j)), ycp+int(s1y*(i+j)), xc+int(s2x*(i+j)), ycp+int(s2y*(i+j)), 1)
            oled.line(xc+int(s2x*(i+j)), ycp+int(s2y*(i+j)), xc+int(s3x*(i+j)), ycp+int(s3y*(i+j)), 1)
            oled.line(xc+int(s3x*(i+j)), ycp+int(s3y*(i+j)), xc+int(s4x*(i+j)), ycp+int(s4y*(i+j)), 1)
            oled.line(xc+int(s4x*(i+j)), ycp+int(s4y*(i+j)), xc+int(s5x*(i+j)), ycp+int(s5y*(i+j)), 1)
            oled.line(xc+int(s5x*(i+j)), ycp+int(s5y*(i+j)), xc+int(s1x*(i+j)), ycp+int(s1y*(i+j)), 1)
        oled.invert(1)
        oled.show()
        time.sleep_ms(50)
        oled.invert(0)
        oled.show()
        time.sleep_ms(50)

    oled.fill(0)
    oled.show()

##星demo
xx_lst = [i for i in range(10, 130, 10)]
yy_lst = [i for i in range(5, 10)]

def draw_star():
    for i in range(0, 37, 12):
        for j in range(3):
            oled.line(xc+int(s1x*(i+j)), ycp+int(s1y*(i+j)), xc+int(s3x*(i+j)), ycp+int(s3y*(i+j)), 1)
            oled.line(xc+int(s3x*(i+j)), ycp+int(s3y*(i+j)), xc+int(s5x*(i+j)), ycp+int(s5y*(i+j)), 1)
            oled.line(xc+int(s5x*(i+j)), ycp+int(s5y*(i+j)), xc+int(s2x*(i+j)), ycp+int(s2y*(i+j)), 1)
            oled.line(xc+int(s2x*(i+j)), ycp+int(s2y*(i+j)), xc+int(s4x*(i+j)), ycp+int(s4y*(i+j)), 1)
            oled.line(xc+int(s4x*(i+j)), ycp+int(s4y*(i+j)), xc+int(s1x*(i+j)), ycp+int(s1y*(i+j)), 1)
        oled.invert(1)
        oled.show()
        time.sleep_ms(50)    
        oled.invert(0)
        oled.show()
        time.sleep_ms(50)

    oled.fill(0)
    oled.show()
    
def draw_mstars(xi, yi):
    for j in range(0, 10, 1):
        oled.line(xi+int(s1x*j), yi+int(s1y*j), xi+int(s3x*j), yi+int(s3y*j), 1)
        oled.line(xi+int(s3x*j), yi+int(s3y*j), xi+int(s5x*j), yi+int(s5y*j), 1)
        oled.line(xi+int(s5x*j), yi+int(s5y*j), xi+int(s2x*j), yi+int(s2y*j), 1)
        oled.line(xi+int(s2x*j), yi+int(s2y*j), xi+int(s4x*j), yi+int(s4y*j), 1)
        oled.line(xi+int(s4x*j), yi+int(s4y*j), xi+int(s1x*j), yi+int(s1y*j), 1)
    oled.show()

def make_star5():
    n = random.choice([j for j in range(1,6)])
    for i in range(n):
      xx = random.choice(xx_lst)
      yy = random.choice(yy_lst)
      draw_mstars(xx, yy)
    oled.show()

def fall_stars():    
    make_star5()
    for i in range(18):    
        oled.scroll(0, 1)
        oled.show()
        time.sleep_ms(10)
        oled.fill_rect(0,0, 128, i, 0)
        oled.show()

##テキストdemo
def get_random_string(num):
    rcletters_lst = []
    for i in range(num):
        rc = random.choice(LETTERS)
        rcletters_lst.append(rc)
    random_string = ''.join(rcletters_lst)
    return random_string   

#ディスプレイに表示するランダム文字列
str_0 = get_random_string(16)
str_1 = get_random_string(16)
str_2 = get_random_string(16)
str_3 = get_random_string(16)
str_4 = get_random_string(16)
str_5 = get_random_string(16)

#Lt16は、0-15の数字順リスト。ここからダブりなく数字を取り出す。文字列の位置指定となる。
Lt16_0 = [i for i in range(16)]
Lt16_1 = [i for i in range(16)]
Lt16_2 = [i for i in range(16)]
Lt16_3 = [i for i in range(16)]
Lt16_4 = [i for i in range(16)]
Lt16_5 = [i for i in range(16)]

ln0, ln1, ln2, ln3, ln4, ln5 = 16, 16, 16, 16, 16, 16

def text_display():
    for i in range(16):
        oled.text(str_0[i], 8*i, 0)
        oled.text(str_1[i], 8*i, 10)
        oled.text(str_2[i], 8*i, 20)
        oled.text(str_3[i], 8*i, 30)
        oled.text(str_4[i], 8*i, 40)
        oled.text(str_5[i], 8*i, 50)
        oled.show()
        time.sleep_ms(50)

def text_eraseall():
    global str_0, str_1, str_2, str_3, str_4, str_5
    global Lt16_0, Lt16_1, Lt16_2, Lt16_3, Lt16_4, Lt16_5
    global ln0, ln1, ln2, ln3, ln4, ln5

    #取り出した数字を要素の番号にして、文字列からその部分を空白にする  
    for j in range(16):
        oled.fill(0)
        #rrが、Lt16の位置をランダムで指定
        rr0 = random.randint(0, ln0-1)
        rr1 = random.randint(0, ln1-1)
        rr2 = random.randint(0, ln2-1)
        rr3 = random.randint(0, ln3-1)
        rr4 = random.randint(0, ln4-1)
        rr5 = random.randint(0, ln5-1)   
        #numは、Lt16のrrに位置する数字
        num0 = Lt16_0[rr0]
        num1 = Lt16_1[rr1]
        num2 = Lt16_2[rr2]
        num3 = Lt16_3[rr3]
        num4 = Lt16_4[rr4]
        num5 = Lt16_5[rr5]
        #Lt16からnumが削除される
        Lt16_0.remove(num0)
        Lt16_1.remove(num1)
        Lt16_2.remove(num2)
        Lt16_3.remove(num3)
        Lt16_4.remove(num4)
        Lt16_5.remove(num5) 
        ln0 = len(Lt16_0)
        ln1 = len(Lt16_1)
        ln2 = len(Lt16_2)
        ln3 = len(Lt16_3)
        ln4 = len(Lt16_4)
        ln5 = len(Lt16_5)
        
        #ランダム文字列においてnumに位置する文字を空白にして、穴あきの文字列を作って上書き
        str_0 = str_0[:num0]+str(" ")+str_0[num0+1:]
        str_1 = str_1[:num1]+str(" ")+str_1[num1+1:]
        str_2 = str_2[:num2]+str(" ")+str_2[num2+1:]
        str_3 = str_3[:num3]+str(" ")+str_3[num3+1:]
        str_4 = str_4[:num4]+str(" ")+str_4[num4+1:]
        str_5 = str_5[:num5]+str(" ")+str_5[num5+1:]
        
        #再描画する
        oled.text(str_0, 0, 0, 1)
        oled.text(str_1, 0, 10, 1)
        oled.text(str_2, 0, 20, 1)
        oled.text(str_3, 0, 30, 1)   
        oled.text(str_4, 0, 40, 1)
        oled.text(str_5, 0, 50, 1)   
        
        oled.show()        
        time.sleep_ms(300)

if __name__ == '__main__':
    draw_lines1()
    draw_lines2()
    draw_lines3()
    draw_lines4()
    draw_linesC()
    draw_rect()
    draw_rect2()
    draw_circle()
    draw_circle2()
    
    draw_triangle()
    draw_pentagram()
    draw_star()
    
    text_display()
    text_eraseall()
    
    while True:
        fall_stars()
```
デモ画像
![oled01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730738/e2626cf1-9028-9f68-7c19-27ab73ed250a.png)