240個/4m NeoPixel tapeを光らせてみました (HSL指定)

こんにちは。
NaKaTaFuです。
[microbit Advent Calendar 2017](https://qiita.com/advent-calendar/2017/microbit) の20日目に載せていたけど、差し替えたねたです。

しつこいようですが、再度NeoPixelネタです。
今日は、4mのテープを光らせてみました。
HSL(色相、再度、輝度)で色指定できる関数を作ったので、色や輝度の制御がやりやすくなりました。
<img width="300" alt="" src="http://drive.google.com/uc?export=view&id=116WAY-fSRh8AHxxCco7YCRQmEfDY_cQ2">

# 必要な物
沢山のNeo Pixel LEDを光らせる場合は、micro:bit本体の電源では容量が足りません。以下が必要になります。
- micro:bit
- LEDテープ
- 5V電源
- レベルコンバータ(無くても動かせる場合もあります)
- 配線材料

# LEDテープ
<img width="300" alt="" src="https://docid81hrs3j1.cloudfront.net/contents/large/2100_001.jpg">
製品はスイッチサイエンスから購入した240個のWS2812Bが搭載された4mのLEDテープになります。
[シリアルLEDテープ 1リール（4m)](https://www.switch-science.com/catalog/2100/)
* 同様のテープはいろいろな場所で入手できます。もっと安い場合もあります。WS2812BあるいはNeoPixelがキーワードになります。

# ５V電源
<img width="300" alt="" src="http://akizukidenshi.com/img/goods/C/M-08705.jpg">
上記LEDテープへの電源供給用５V DC電源。
スイッチサイエンスさんでの実測では約13A必要だったそうです。
輝度を落として使えば、それほど必要は無いのですが、私は以下の製品を使っています。
[スイッチング電源ボード　ＤＣ５Ｖ２０Ａ　出力１００Ｗタイプ　ＶＳ１００Ｅ－５(秋月電子)](http://akizukidenshi.com/catalog/g/gM-08705/)
なお、輝度が高いと4mのLEDテープは途中で電圧降下が起こるため、電源用のケーブルを分岐して複数か所に供給するなど必要になる場合があります。

# レベルコンバータ(必要時)
条件が良ければ無くても動きます。
<img width="300" alt="" src="https://docid81hrs3j1.cloudfront.net/contents/large/1466_4.jpg">

micro:bitの信号レベルは3.3Vです。NeoPixelのデータ入力端子(DIN)は0.7VDDが必要ですので、3.5Vを供給する必要があります。
NepPixelに5Vを供給する場合、micro:bitの信号は少し電圧が足りないということになります。
手元にあった、[TXB0104利用の製品](https://www.switch-science.com/catalog/1466/)を使いました。
(3.3V, 5.5Vのレベルコンバータであれば何でも利用できると思います。また、双方向である必要はありません。)

今日の実験ではレベルコンバータありで最初実施していましたが、途中で試しにレベルコンバータを外してみたら、動作しました。

# 配線
レベルコンバータを使わない場合は、NeoPixelに5V電源を供給すると同時に、micro:bitとNeoPixelのGNDを接続、micro:bitのP0をNepPixelのDINにつないでください。
レベルコンバータを使う場合は、
- NeoPixelに5Vの電源供給
- NepPixelのVDD(5V),GND,DINをレベルコンバータの高圧側に接続
- Micro:bitのVDD(3.3V),GND,P0をレベルコンバータの低圧側に接続
という接続となります。

# プログラム
- [こちら](https://makecode.microbit.org/_hcCFPvTrUEbc)となります。
<a href="https://makecode.microbit.org/_hcCFPvTrUEbc">
<img width="420" alt="" src="http://drive.google.com/uc?export=view&id=1j74gAyXcAwbob9OTQ_ehNmD_zToCLkYm">
<img width="600" alt="" src="http://drive.google.com/uc?export=view&id=10gJp0JEY4OQGanaKd9o3GPUTDSpwx-EG">
<img width="640" alt="" src="http://drive.google.com/uc?export=view&id=1BxYHuhCujoIOXy9TP1aq9bouMNYql7gk">
</a>

- HSL(色相(0～359)、彩度(0～99)、輝度(0～99))で色指定する関数を用意しました。
- NeoPixelライブラリ内にHSL色指定関数を組み込む作業は進んでいるようですので、いずれ自前で関数を準備しなくても使える様になると思います。
- RGBとHSLの関係については、ネット上にいろいろ情報がありますので、省略します。[こちら](https://www.peko-step.com/tool/hslrgb.html)など。
- Javascriptモードでのリストは次の通りとなります。|


```
let 色相ステップ = 0 
let 輝度 = 0  
let LED数 = 0
let ネオピクセル: neopixel.Strip = null
let LED位置 = 0
let 変数 = 0
let 傾き = 0
let 色相 = 0
変数 = 0
LED位置 = 0
LED数 = 240
輝度 = 32
色相ステップ = 2 * 360 / LED数
LED数 = 240
ネオピクセル = neopixel.create(DigitalPin.P0, 240, NeoPixelMode.RGB)
色相 = 0
for (let カウンター = 0; カウンター <= LED数 / 1; カウンター++) {
    ネオピクセル.setPixelColor(カウンター,  hslToRgb(色相, 99, 8))
    色相 = 色相 + 色相ステップ
    if (色相 > 360) {
        色相 = 色相 - 360
    }
}
ネオピクセル.show()
function packRGB(a: number, b: number, c: number): number {
    return ((a & 0xFF) << 16) | ((b & 0xFF) << 8) | (c & 0xFF);
}
function hslToRgb(h: number, s: number, l: number): number {
    h = h % 360;
    s = Math.clamp(0, 99, s);
    l = Math.clamp(0, 99, l);
    let c = (((100 - Math.abs(2 * l - 100)) * s) << 8) / 10000; //chroma, [0,255]
    let h1 = h / 60;//[0,6]
    let h2 = (h - h1 * 60) * 256 / 60;//[0,255]
    let temp = Math.abs((((h1 % 2) << 8) + h2) - 256);
    let x = (c * (256 - (temp))) >> 8;//[0,255], second largest component of this color
    let r$: number;
    let g$: number;
    let b$: number;
    if (h1 == 0) {
        r$ = c; g$ = x; b$ = 0;
    } else if (h1 == 1) {
        r$ = x; g$ = c; b$ = 0;
    } else if (h1 == 2) {
        r$ = 0; g$ = c; b$ = x;
    } else if (h1 == 3) {
        r$ = 0; g$ = x; b$ = c;
    } else if (h1 == 4) {
        r$ = x; g$ = 0; b$ = c;
    } else if (h1 == 5) {
        r$ = c; g$ = 0; b$ = x;
    }
    let m = ((l * 2 << 8) / 100 - c) / 2;
    let r = r$ + m;
    let g = g$ + m;
    let b = b$ + m;
    return packRGB(r, g, b);
}
basic.forever(() => {
    傾き = input.rotation(Rotation.Roll)
    if (傾き < -10) {
        ネオピクセル.rotate(-10)
        ネオピクセル.show()
    }
    if (傾き > 10) {
        ネオピクセル.rotate(10)
        ネオピクセル.show()
    }
})
```


HSL sample

[https://makecode.microbit.org/_CmdCa71g2REF]