Tanuki_Bayashin’s diary

電子工作を趣味としています。最近はラズベリーパイPicoというマイコンを使って楽しんでいます

【Raspberry Pi Pico 専用】WS2812B のためのライブラリの試作

※なにか気になる点がありましたらコメント欄からお伝えください。また、回路を製作する場合には電源を切るなど、注意を払って行うようお願いいたします。
(2021/10/11追記)

目次

1.はじめに

 WS2812BというICチップ内蔵のフルカラーLEDのアレイがある(図1左)。これはRaspberry Pi Pico (以下Pico と記述:図1右)での制御も可能である。これらは筆者も愛用しており、Picoにて制御する際の専用のライブラリがあったら便利かと思い、製作してみた。あくまで自分用である。

※少し調べましたが、まずNeoPixelというものがあり、これはマイコン付RGB LEDを総称したadafruitの商品シリーズ名だそうです。その中にWS2812Bと呼ばれるものも含まれるとのことです。
 したがって、以降、私の記事ではNeopixelと記述することとします。(2021/10/11追記)

図1 左:WS2812B 右:ラズベリーパイPico

2.回路

 WS2812BとPicoについてのくわしいことははここでは詳しくは説明しない。検索などで調べてください。
 全体構成図を以下に示す。(Pico 用の電源は省略。USBケーブルを接続すると給電される)

図3 全体構成図

 簡単に説明すると、WS2812Bには3本の接続する電線がある。1本はGND、1本は電源、残りの1本が制御用である。制御用の電線はPicoからの出力信号を受け取り、WS2812Bの何番目のLEDのRGBをそれぞれどれくらいの強さで光らせるかを受信する。
 また、WS2812Bの電源に関して述べると、WS2812B1素子当たり、RGB3個のLEDが内蔵されていて、それぞれ定格は約12mA流して使う。WS2812Bが100個の素子で構成されているとすると、最大約3.6Aの電流が必要となる。電源ラインと直列に数百Ωの保護抵抗を入れるなど注意が必要である。(WS2812B内に保護抵抗が収められている場合もある。メーカーによって異なる模様)

3.ライブラリ

 リスト1に自作のライブラリを載せる。(多くは以下の書籍を参考にした)
THE OFFICIAL RASPBERRY PI PICO GUIDE : Get started with MicroPython on Raspberry Pi Pico
www.raspberrypi.org

リスト1(ファイル名:Class_ws2812b.py)

import array, utime
from machine import Pin
import rp2
from rp2 import PIO, StateMachine, asm_pio

# PIO State Machine to display ws2812
@asm_pio(sideset_init=PIO.OUT_LOW, out_shiftdir=PIO.SHIFT_LEFT, autopull=True,\
         pull_thresh=24)
def ws2812b():
    T1 = 2
    T2 = 5
    T3 = 3
    label("bitloop")
    out(x, 1)                .side(0)    [T3 - 1]
    jmp(not_x, "do_zero")    .side(1)    [T1 - 1]
    jmp("bitloop")           .side(1)    [T2 - 1]
    label("do_zero")
    nop()                    .side(0)    [T2 - 1]

class Class_ws2812b:
    
    def __init__(self):
        self.sm_no = 0         # state machine No(0-7)
        self.Pin_No = 16       # the Number of conected Pin(GPIO)

    def init_ws2812b(self, sm_no, freq, Pin_No):
        self.sm_no = sm_no
        self.freq = freq
        self.Pin_No = Pin_No

        # Create the StateMachine with the ws2812b program, outputting on Pin_No.
        sm = StateMachine(self.sm_no, ws2812b, self.freq, \
                          sideset_base=Pin(self.Pin_No))
        return sm

説明(筆者はクラスやインスタンスに関してよく理解していない):
 ① 1~ 4行目:必要なライブラリを読み込む
 ② 6~18行目:この部分は筆者はちゃんと理解していない。PIO State MachineというPicoを高速で動かすためのものらしい。(ラズパイPico用のマシン語?)前述の書籍に書かれていた。

 20~34行目:この記事のメインとなる部分である。以下順に見ていく
 ③20行目:クラスClass_ws2812b の宣言
 ④22~24行目:クラスの初期化(microPythonならではの記述である)
 ⑤26~34行目:WS2812Bの初期化。27~29行目で変数の受け渡しを行っている。

  27行目 sm_no:state machine の番号。8個用意され、0-7の間で指定できる。
  28行目 freq  :動作させる周波数
  29行目 Pin_No:信号を出力するピンの指定(GP○○の○○のこと)
  32~33行目   :StateMachine という関数で、sm_no、freq、Pin_Noと動作させる関数(ここではws2812b()(上の9~18行目))を指定し、変数sm にインスタンスを与えている。
  34行目 戻り値sm を返している

4.ライブラリを使ってプログラムを組む

4.1ライブラリの使用例

 実際に3章で紹介したライブラリの使用例を示す(リスト2)。長々と書いているが、大事な部分は18行目ぐらいまでである。

スト2

import array, utime
from Sep_2021 import Class_ws2812b

#Configure the number of WS2812B LEDs.
NUM_LEDS = 16

# Get the Instance of StateMachine with the WS2812B
ws = Class_ws2812b.Class_ws2812b()

# StateMachine(0, ws2812, freq=8000000, sideset_base=Pin(16))
sm = ws.init_ws2812b(0, 8000000, 16)

# start the StateMachine, it will wait for data on its FIFO.
sm.active(1)

# Display a pattern on the LEDs via an array of LED RGB values.
ar = array.array("I", [0 for _ in range(NUM_LEDS)])

# すべてのLEDの r g b の値を、
# 指定されたr g b の値にセットする
def ar_color_all(red, green, blue):
    for i in range(NUM_LEDS):
        ar[i] = (green<<16) + (red<<8) + blue
    sm.put(ar,8)
    utime.sleep(1)
            
# すべてのLED の値をゼロにする
def clear_all():
    for i in range(NUM_LEDS):
        ar[i] = 0
    sm.put(ar,8)


if __name__ == '__main__':
    # Process arguments
    print('Press Ctrl-C to quit.')

    try:
        while True:
        # ar_color_all(red, green, blue)
            ar_color_all(100, 0, 0)         # 赤
                
            ar_color_all(50, 0, 50)         # マゼンタ

            ar_color_all(50, 50, 0)         # 黄色

            ar_color_all(0, 100, 0)         # 緑

            ar_color_all(0, 50, 50)         # 水色

            ar_color_all(0, 0, 100)         # 青

            ar_color_all(20, 20, 20)        # 白

    except KeyboardInterrupt:
        #### clear WS2812B
        clear_all()
        print('program is finished')

解説
1行目 必要なライブラリを読み込む
2行目 3章で作ったライブラリを読み込んでいる。リスト1のファイル名はClass_ws2812b.pyで、Sep_2021という名前のフォルダーに入っている。
5行目 LEDの個数である。
8行目 クラスClass_ws2812bのオブジェクト(?)を取得している。
11行目 smという変数にオブジェクトwsのインスタンスを取得している。
14行目 smはまた、ステートマシンでもあるので、それをオンの状態にしている。
17行目 今までの流れとは別にarというリスト型変数を定義している。要素数はLEDの個数と等しい。
21~25行目 ar_color_all()という関数を定義している。コメントにもあるが、すべてのLEDのRGB値をred、blue、greenの値にセットする。
28~31行目 clear_all()という関数を定義している。すべてのLEDのRBG値を0にしている。
(上の2つの関数のなかに ”sm.put(ar,8)”という記述がある。これにより、変数ar のなかに記述されているデータがWS2812Bに書きこまれている)
34~58行目 プログラムの本体である。if 文とtry と except にて CtrlーC が押されたとき、すべてのLEDを消してプログラムを終了する。
プログラムの中身としては、関数 ar_color_all() により、7色の色を順番に点灯させている。

4.2 動画

 実際にWS2812Bが点灯している様子を以下に示す。

動画:【ラズベリーパイPico専用】WS2812Bのためのライブラリの試作

youtu.be


5.まとめ

 WS2812Bの初期設定を行う、ラズベリーパイPico専用のライブラリを製作した(試作の段階)。microPyhtonの学習の一環でもある。また、少しだけ、独自の関数も例示した。(あくまで自分用である)
 今回は示していないが、もっとグラフィカルな表示も可能である。今後試してみたい。