1. Qiita
  2. Items
  3. fabo

WS2812をArduinoから制御する

  • 1
    Like
  • 0
    Comment

Datasheet

Datasheet

0/1 フォーマット

HIGH/LOW 概要 時間 誤差
T0H 0 high voltage time 0.40us ±150ns
T1H 1 high voltage time 0.8us ±150ns
T0L 0 low voltage time 0.85us ±150ns
T1L 1 low voltage time 0.45us ±150ns
RES low voltage time Above 50µs

WS2812B_Datasheet_tiimeChart.jpg

データフォーマット

24bitの色データ

Green(8bit) Red(8bit) Blue(8bit)

color02.png

データ構造

50usのRETが続いた場合、新しいデータとみなす。1つめのデータは、LED1が抜き取り発色する。2つめのデータは、2番目のLED2が抜き取り発色する。50us以内でデータを結合し、流すだけでマイコンが自分のデータを抜き出し発色する。

color03.png

Delay

delayMicroseconds()は、2usのdelayが可能。これだと遅すぎる。

ArduinoのUNOのクロックは、16MHz

1/16MHz = 0.0625us

1周期 0.0625us。

割り込みMacro

sei()
cli()

をつかって、処理中割り込みを防ぐ。

ArduinoのPORT

port.png

Sample

12個のLEDを光らすサンプルですが、変色、うまく色が出せない。
```cpp:sample

define PORTA1_HIGH 0b1

define PORTA1_LOW 0b0

define BYTENUMBER 8

define NUBEROFLED 12

const uint8_t bitShift = BYTENUMBER - 1 ;
uint8_t colorData[36] = {5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5,
5,5,5};

void setup() {
DDRC = 1; // PORTCを出力に
PORTC = 0b0; // PORTCに 00000000を設定(全部LOW)
}

void loop() {

sei();
for(int i = 0; i<NUBEROFLED; i++){
send(colorData[i*3], colorData[i*3+1], colorData[i*3+2]);
}
cli();
reset();
delay(100);
}

void send(uint8_t g, uint8_t r, uint8_t b){
for(int i = 0; i < BYTENUMBER; i++){
if(g & (1 << (bitShift-i))){
led_one();
} else {
led_zero();
}
}

for(int i = 0; i < BYTENUMBER; i++){
if(r & 1 << ((bitShift-i))){
led_one();
} else {
led_zero();
}
}
for(int i = 0; i < BYTENUMBER; i++){
if(b & 1 << ((bitShift-i))){
led_one();
} else {
led_zero();
}
}
}

void led_zero(){

// HIGH: 0.35us
PORTC |= PORTA1_HIGH; //T 2
asm(" nop"); //T 3
asm(" nop"); //T 4
asm(" nop"); //T 5
asm(" nop"); //T 6 6 * 0.0625 = 0.375us

// LOW: 0.8us
PORTC &= PORTA1_LOW; //T 8
asm(" nop"); //T 9
asm(" nop"); //T 10
asm(" nop"); //T 11
asm(" nop"); //T 12
asm(" nop"); //T 13
asm(" nop"); //T 14
asm(" nop"); //T 15
asm(" nop"); //T 16
asm(" nop"); //T 17
asm(" nop"); //T 18
asm(" nop"); //T 19 13 * 0.0625 = 0.8125us
}

void led_one(){

// HIGH 0.7us
PORTC |= PORTA1_HIGH; // T 2
asm(" nop"); // T 3
asm(" nop"); // T 4
asm(" nop"); // T 5
asm(" nop"); // T 6
asm(" nop"); // T 7
asm(" nop"); // T 8
asm(" nop"); // T 9
asm(" nop"); // T 10
asm(" nop"); // T 11 11 * 0.0625 = 0.6875us

// LOW 0.6us
PORTC &= PORTA1_LOW; // T 13
asm(" nop"); // T 14
asm(" nop"); // T 15
asm(" nop"); // T 16
asm(" nop"); // T 17
asm(" nop"); // T 18
asm(" nop"); // T 19
asm(" nop"); // T 20
//asm(" nop"); // T 21 10 * 0.0625 = 0.625
}

void reset(){
PORTC &= PORTA1_LOW;
for(int i = 0; i < 60; i++){
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
asm(" nop");
}
}
```

実行結果

Delaytime01.jpg
timeDelay02.jpg
highは狙った通りの状態になっていますが、lowは長くなる。24bit間の時間が3000usとなり大きく遅延する。LEDはRest状態だと勘違いしLEDがチラツキ始める。

原因

クロックは正常に動いているが、ビットを出力する前後に遅延があり、if文などの条件分岐やビット演算に時間がかかる。