WS2812をArduinoから制御する


# Datasheet

[Datasheet](http://www.world-semi.com/uploads/soft/150522/1-150522091P5.pdf)

# 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 |

<img width="589" alt="WS2812B_Datasheet_tiimeChart.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/112699/ccf891ab-4165-8898-2629-d367d7a0fed7.jpeg">

# データフォーマット

24bitの色データ

|Green(8bit)|Red(8bit)|Blue(8bit)|
|:--|:--|:--|

<img width="730" alt="color02.png" src="https://qiita-image-store.s3.amazonaws.com/0/63450/13244225-9682-c28f-478c-4f73e65aa5f4.png">

# データ構造

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

<img width="972" alt="color03.png" src="https://qiita-image-store.s3.amazonaws.com/0/63450/5cb3526c-93a3-c545-9bd0-136c06d6ba59.png">

# Delay

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

ArduinoのUNOのクロックは、16MHz
> 1/16MHz = 0.0625us

1周期 0.0625us。

割り込みMacro

> sei()
> cli()

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

# ArduinoのPORT

![port.png](https://qiita-image-store.s3.amazonaws.com/0/63450/97625108-55b7-499d-04c1-e8b55e9b02ec.png)


# Sample
１２個の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](https://qiita-image-store.s3.amazonaws.com/0/112699/6216d4aa-0b5f-c0d6-f6e6-3089d9788d0b.jpeg)
![timeDelay02.jpg](https://qiita-image-store.s3.amazonaws.com/0/112699/b95794bd-c8fd-d07c-0737-9c630c366f82.jpeg)
highは狙った通りの状態になっていますが、lowは長くなる。24bit間の時間が3000usとなり大きく遅延する。LEDはRest状態だと勘違いしLEDがチラツキ始める。
#原因
クロックは正常に動いているが、ビットを出力する前後に遅延があり、if文などの条件分岐やビット演算に時間がかかる。