Tanuki_Bayashin’s diary

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

【Neopixel】彩度、明度、色の表示の速度を制御してみた

※なにか気になる点がありましたらコメント欄にご記入ください。また、工作や回路を製作する場合には、細かい作業などに対して、細心の注意を払われるようお願いいたします。

1.はじめに

以前の記事の発展形です。

以前の記事:
自作の色を作り出す関数を検証してみた~HSV色空間 - Tanuki_Bayashin’s diary

今回も10×10のNeopixelを使用します。

図1 実験の様子

ボリュームの電圧値をラズベリーパイPico(以下Picoと記述)のA/D変換機能により取り込み、Neopixelの色の変化の度合い、彩度(色の鮮やかさ)、明度(色の明るさ)を制御してみました。

彩度や明度の変更については、HSV空間という色の表現の考え方を参考にしています。HSV空間に関しては前の記事でも取り上げているので、詳しくはそちらを参考にして下さい。
(今回も、前回の動画で参考にしたYoutubeの動画内のライブラリを使用させていただきました)

参考にした動画:
youtu.be

以下述べていきます。

※素人レベルの電子工作erの書いた記事です。いたらない点などあるかと思いますが、大目に見て頂けると助かります。(;´∀`)

2.実態配線図

全体の実態配線図を図2に示します。

図2 実態配線図

3 製作したソースコード

製作したソースコードをリスト1に示します。
Ctrl‐Cを押すと表示を消して、処理を終了するようにしています。

リスト1 ソースコード

#必用なライブラリをインポートします
import array, utime, math, machine
from machine import Pin, ADC
import rp2
from rp2 import PIO, StateMachine, asm_pio
import cvt_col

# クロック周波数を250MHzにしています。(オーバークロックです)
machine.freq(250_000_000)

#AD変換のポート(GP26~GP28)を割り当てて、vr0~vr2のインスタンスを生成します。
vr0 = ADC(26)
vr1 = ADC(27)
vr2 = ADC(28)

# 変換係数です
K_speed = 6.0 / (65535)
K_val = 20.0 / (65535)
K_sat = 150.0 / (65535)

#WS2812 のLEDの数を指定します
NUM_LEDS = 100
# Pico特有のstate machine を用いてWS2812の制御を行っています
# PIO State Machine to display ws2812
@asm_pio(sideset_init=PIO.OUT_LOW, out_shiftdir=PIO.SHIFT_LEFT, autopull=True,\
         pull_thresh=24)
def ws2812():
    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]

# Create the StateMachine with the ws2812 program, outputting on Pin(16)().
sm = StateMachine(0, ws2812, freq=8000000, sideset_base=Pin(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)])

#position の位置のLEDをred, green, blue の値にて指定します
def ar_color(position, red, green, blue):
    ar[position] = (green<<16) + (red<<8) + blue

#全ての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.')
    
    r_max = 4.5 * math.sqrt(2)
    color = 0.0
    try:
        # 無限ループです
        while True:
            # A/D変換により値を読み取っています。
            # 変数変換をしています。
            # speed: -3.0~3.0
            speed = vr0.read_u16() * K_speed - 3.0
            color = (color - speed) % 60.0
            # v: 0~20
            v = int(vr1.read_u16() * K_val)
            # s:105~255
            s = int(vr2.read_u16() * K_sat) + 105

            # Neopixelを同心円上に色を変化させて表示するための計算です
            for i in range(NUM_LEDS):
                # 左から何列目かを計算し、4.5を引いています
                x = float(i % 10) - 4.5
                # 下から何段目かを計算し、4.5を引いています
                y = float(i) / 10.0 - 4.5
                # 中心(4.5, 4.5)からの距離を求め、最大値を1に規格化しています
                r = math.sqrt(x*x + y*y) / r_max
                r_int = int(r  * 40.0 + color) % 60

                #それぞれのLEDの色を計算し、値を書き込んでいます
                (r, g, b) = cvt_col.hsv_to_rgb(r_int * 6, s, v)
                ar_color(i, r, g, b)
            # 色を表示しています
            sm.put(ar,8)
            utime.sleep_us(100)

    # ctl-C が押されたときの処理です
    except KeyboardInterrupt:
        #### clear ws2812b
        clear_all()

リストの内容については、コメントにて説明しています。参考にして下さい。

4.動画

実際に動かしている様子です。
www.youtube.com

付録

GitHub上にソースコードや実態配線図などをpushしておきました。
cloneするなり、zipファイルをダウンロードするなりしていただいて構わないです。

github.com


以上で終わりです。
お付き合いくださり、ありがとうございました。