結構特殊な条件下なのでそれを最初に言っておこう、、、
・テープLED(WS2812)を制御する
・F303K8で制御したい
・MbedOS6でプログラムする
・とりあえず光らせたいだけで細かい挙動は知らないよ()
って人はどうぞご覧ください。正直私も最近Mbedを勉強し始めたばかりで教えてほしいレベルなんですけど、、、
WS2812について
軽く説明します。とりあえずデータシートどうぞ↓(内容は古い場合があります)
https://cdn-shop.adafruit.com/datasheets/WS2812.pdf
データシートから、とりあえず光らせる要点だけ挙げると、、、
・1つのLEDに対する色の指定はGRBそれぞれ8bit*3=24bitで構成
・WS2812にデータを送ると、24bitずつ前から取ってくれるため、24*(LEDの個数)分のデータを送ることでLEDの個数を指定できる
・WS2812がデータの0/1を認識する条件として、それぞれのHIGHとLOWの時間が指定されている(上記のデータシートの場合、0.35usHIGH、0.8usLOWを送ると「0」として認識し、0.7usHIGH、0.6usLOWを送ると「1」として認識する)
以上を踏まえてコードを書いていきます。
F303K8に書き込んでいく、、、前に
少しだけ蛇足?というかお話。そもそもテープLED自体は多くの人が使ってるものではある。だから、上に書いたような、0.35usHIGHにして、、、ってのはよくある話。
ただ、この時間指定が結構シビアなのが今回の問題。
よくあるのが、0.35usより長くHIGHになった結果、「0」を認識せず、すべてのデータを「1」と認識するせいで、RGBの全てのbitが「1」つまりは白色に光るように認識するためずっと白色に点灯する状態。
このシビアなのを解決するために、Arudinoとかだと有識者が作ったライブラリ(Adafruitとか)を使えばいいのだけれど、F303K8で制御したいとなるとライブラリが少ないんだよね、、、(これに関しては私の勉強不足かも。誰か教えて。。)
一応Nucleo系ボードで使えるライブラリもあるけど、残念ながらF303K8は非対応。
あとは、DMA使うなり、SPI使うなり、CubeMXで中身いじるなりあるけど、よくわかんない☆(使い始めて1ヵ月なんです。限界です。)
というわけで、ライブラリとか細かいのを使わずにコード書くことにした。
改めて、F303K8に書き込んでいく
まず結論から。というわけで1秒ごとに10個のLEDが赤色に点滅するプログラムを書きました。
- #include "mbed.h"
- //pinnumber of WS2812
- DigitalOut ws2812(PF_0);
- //number of leds
- const int NUM_LEDS = 10;
- //number of leds * 3byte(R,G,B)
- uint8_t buffer[NUM_LEDS*3];
- //set color(R, G, B)
- void setbuffer(int r, int g, int b){
- for(int i = 0; i < NUM_LEDS * 3; i += 3){
- buffer[i] = g;
- buffer[i+1] = r;
- buffer[i+2] = b;
- }
- }
- //light WS2812
- void sendWS2812() {
- for (int i = 0; i < NUM_LEDS * 3; i++) {
- //reset
- ws2812 = 0;
- wait_us(50);
- for (int j = 7; j >= 0; j--) {
- int r = (buffer[i] >> j) & 1;
- if(r == 1){
- //send 1 code
- ws2812 = 1;
- wait_us(0.35);
- ws2812 = 0;
- wait_us(0.25);
- }else{
- //send 0 code
- ws2812 = 1;
- ws2812 = 0;
- wait_us(0.45);
- }
- }
- }
- }
- int main() {
- while (1) {
- setbuffer(255, 0, 0);
- sendWS2812();
- wait_us(1000000);
- setbuffer(0, 0, 0);
- sendWS2812();
- wait_us(1000000);
- }
- }
軽く説明をしていきます。
4行目:任意のデジタルピンを指定してください
7行目:光らせたいLEDの個数を指定してください
12行目:ここの関数で光らせる色を指定します。(R, G, B)の順で、それぞれ0~255の値をセットしてください。なお、main()で(255, 0, 0)は赤色、(0, 0, 0)は黒色(つまりは光らない)を指定してます。
21行目:12行目で色を指定し、buffer内に格納したので、それをWS2812に送る関数です。ここで、前述のの通り0.35usがかなりシビアなのですが、、、、
適当に値を入れて実験していると、どうやらwait_us()を入れずに、つまりはHIGHにした直後にLOWにすることで(処理速度がうまい感じに働いて)WS2812が「0」と認識しました。
、、、つまりは、たまたま上手くいったかんじです☆
しらみつぶしに値を入れてみるもんだなぁ、、、大学入試用の数学の問題みたく、実験て大事ですね(すっとぼけ)
そのため、処理速度の異なる基板で同じことを試そうものなら、その基盤に適した時間をみつけてやる必要があるわけです。大変ですね。。。
というか、たまたま上手くいったんですけど、さらにたまに、送るデータがずれるせいか、指定した色に光らないことがあります。そのあたり、保証しませんので、、、
まぁ、今回私がテープLEDを使う目的としては数回点滅させられればいいだけで、細かい色の指定はする必要がないんですよね。。。
そのため、実用上の問題は無いに等しく、上記のプログラムで十分と判断しました。
結論:実験は大事
そうとうコアなテープLEDのお話でした。。。