フォト
2018年6月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
無料ブログはココログ

« NeoPixel(WS2812B)の制御 | トップページ | 梅澤無線電機さんの「電子倶楽部60」を購入してみました »

2018年5月22日 (火)

NeoPixel(WS2812B)の制御 その2

前回行った、ArduinoによるNeoPixel(WS2812B)の制御の続きです。
前回の処理の一部をSPIを利用する方式に書き換えました。

SPIを使っているため、出力ピンはMOSIピン(D11)固定となりますが、
前回よりも安定したクロックでの出力となりました。

  04

前回の信号生成の条件を考慮し、

02

03

SPIのクロックを8MHzとした場合、1クロック幅は0.125μ秒となります。
このクロック幅を元に利用して、

   T0H、T1L : 0.375μ秒 (3クロック分)
   T0L、T1H : 0.625μ秒 (5クロック分)

として利用します。値としては、「Data transfer time」の表の有効範囲から
少々ずれていますが、問題無いようです。

ちょうど0、1の送信とも8クロック分になりSPIの送信単位の8ビットにマッチします。

01
NeoPixelに1ビット送信するのに、SPIを利用して1バイト送れば良いことになります。
    0 : 0b11100000
    1 : 0b11111000



修正したスケッチ(2018/05/30 修正)

前回のスケッチでNeoPixelの初期化とデータ送信を行っている
NeoInit() 、NeoUpdate()をSPIを利用する方式に修正しました。

//
// Neopixelの制御 SPIバージョン by たま吉さん  2018/05/22
//

#include <SPI.h>

//***************
// 定数
//***************

#define PIXCELNUM   16           // Neopixel ピクセル数(LED数)
#define PIN         11           // Neopixel 制御用ピン番号
#define NEOSPI_0    0b11100000   // 1ビット 値0
#define NEOSPI_1    0b11111000   // 1ビット 値1
#define NEOSPI_RST  0b00000000   // REST

//***************
// グローバル変数
//***************
uint8_t buf[PIXCELNUM*3];     // Nexpixel用ピクセル色データ(ピクセル数 x 24ビット)

//***************
// 関数
//***************
// Neopixel初期化
void NeoInit() {
  memset(buf, 0, PIXCELNUM*3); // バッファの初期化

  // SPIの初期化
  SPI.setBitOrder(MSBFIRST);            // 最上位ビットから送信
  SPI.setClockDivider(SPI_CLOCK_DIV2);  // クロック 8MHz
  SPI.setDataMode(SPI_MODE1);           // アイドル時 LOW、立上りエッジ時送信
  SPI.begin();                          // 開始
}

// Neopixelへのデータ送信
void NeoUpdate() {
  // RESET送信
  SPDR = NEOSPI_RST;              // SPIデータ送信
  while(!(SPSR & (1 << SPIF))) ;  // 送信完了待ち
  delayMicroseconds(50);

  // ピクセル数x24ビット送信
  for (uint8_t i = 0; i < PIXCELNUM*3; i++) {
    for (uint8_t j = 0; j < 8; j++) {
      SPDR = buf[i] & (0x80>>j) ? NEOSPI_1:NEOSPI_0; // SPIデータ送信
      while(!(SPSR & (1 << SPIF))) ;                 // 送信完了待ち
    }
  }
}

// Neopixelの表示クリア
void NeoCLS() {
    memset(buf, 0, PIXCELNUM*3); // バッファの初期化
    NeoUpdate();                 // 表示更新
}

// 指定したピクセルの色を設定
void NeoSetRGB(uint8_t no, uint8_t R, uint8_t G, uint8_t B, uint8_t flgUpdate=false) {
  if (no < PIXCELNUM) {
    buf[no*3+0] = G;
    buf[no*3+1] = R;
    buf[no*3+2] = B;    
  }
  if (flgUpdate)
    NeoUpdate();
}

// ピクセルのシフト
void ShiftPixel() {
  uint8_t tmpbuf[3];
  memmove(tmpbuf,buf,3);
  memmove(buf, buf+3, (PIXCELNUM-1)*3);
  memmove(buf+(PIXCELNUM-1)*3,tmpbuf,3);
  NeoUpdate();
}

void setup() {
  
  NeoInit();  // Neopixcelの初期化
  NeoCLS();   // Neopixcelの表示クリア
  
  NeoSetRGB(0, 128,0,0,true); // No.0のピクセルを赤
  NeoSetRGB(1, 0,128,0,true); // No.1のピクセルを緑
  NeoSetRGB(2, 0,0,128,true); // No.2のピクセルを青
}

void loop() {
 delay(80);
 ShiftPixel(); // ピクセルをシフトして更新表示
}

SPIによるデータ送信は、関数呼び出しだと処理が間に合わないと判断し、
データレジスタSPDRに送信データをセットし、ステータスレジスタSPSRを参照して
送信完了待ちを行っています。

次回は8x8ドットマトリックスタイプのNeopixelを使ってもう少し複雑なことをやろうかと思います。

関連記事
 NeoPixel(WS2812B)の制御 その3(2018.05.30)  ・・・ 8x8マトリックスの制御
 NeoPixel(WS2812B)の制御 その2(2018.05.22)   ・・・ SPIを使った制御(この記事です)
 NeoPixel(WS2812B)の制御(2018.05.20)            ・・・ GPIOを使った制御

参考にしたサイト
Todotaniのはやり物Log - SPIの基本動作とArduinoでの使い方
しなぷすのハード製作記 - 「SPI」の解説
garretlab - Arduinoで遊ぶページ - SPI関連レジスタ
Stupiddog - ArduinoでSPI通信を行う方法
株式会社インデペンデンスシステムズ横浜 - Arduino UnoでSPI通信(その1)Arduino Uno2台で通信
QEEWiki - SPI (Serial Peripheral Interface)

« NeoPixel(WS2812B)の制御 | トップページ | 梅澤無線電機さんの「電子倶楽部60」を購入してみました »

arduino」カテゴリの記事

表示器制御関連」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/571408/66747100

この記事へのトラックバック一覧です: NeoPixel(WS2812B)の制御 その2:

« NeoPixel(WS2812B)の制御 | トップページ | 梅澤無線電機さんの「電子倶楽部60」を購入してみました »