メインページに戻る

参考:シリアルLED(WS2822S)をつかってみました。

(大前提)半田付けができなくても大丈夫です!あくまでのモノづくり体験の一環としてトライという程度で半田付できなくてもモノづくりは可能です!


0. 半田付けをしてみよう

講義中に実演しつつ説明します。以下は復習用に。

半田付け基本

デジタルマルチメータで短絡チェック

以下のようにブレッドボードへの接続部分を作成します。

1. LEDを光らせてみよう!

WS2822Sについて:https://trac.switch-science.com/wiki/WS2822S

1.1 材料

  • Arduino Nano
  • ブレッドボード
  • USBケーブル
  • フルカラーシリアルLEDテープ(WS2822S)
  • ジャンパーワイヤ
  • ヘッダピン
  • 導線

シリアル線1本でフルカラーを制御できるLEDテープ。

1.2 ブレッドボード図

それでは、以下のようにLEDテープとArduinoを繋げてみましょう。

LEDテープArduino
G (GND) GND
D (DAT)D13
AiD12
5V 5V

実際の写真は以下の通り。

1.3 ライブラリのインストール

以下より、Code=> Download Zip でWS2822S-master.zipというZIPファイルをダウンロードします。

https://github.com/SWITCHSCIENCE/WS2822S

解凍したフォルダを[userdir]/Arduino/librariesに移動させます。

  • Mac
    • ユーザーディレクトリ下の「書類」フォルダの中にArduinoがあります。
    • /Users/yourname/Documents/Arduino/libraries 内にフォルダごとドラッグ&ドロップしてください。
  • Windows
    • ユーザーディレクトリ下の「\Documents\Arduino\libraries」内にフォルダごとドラッグ&ドロップしてください。

1.4 コード

1.4.1 基本編

まずはアドレスを書き込む必要があります。この動作は一度で大丈夫です。※電源が切れてもアドレスは残ります

コードは以下の通りです。Arduinoに書き込んでみましょう。

#include "Ws2822s.h"

const uint8_t PIXEL_NUM = 6;   
const uint8_t LED_PIN   = 13;  // DAI 
const uint8_t ADR_PIN   = 12;  // ADRI

Ws2822s LED(LED_PIN, ADR_PIN, PIXEL_NUM);

void setup() {
  LED.setAddress(0, PIXEL_NUM - 1);   // 0〜5 の連番を書き込む
  delay(5000);                        // 5 秒間白点灯して完了サイン
}

void loop() {}   // ループは空で OK

そうするとLED6個が白色に光るかと思います。光っていればOKです。

アドレスの書き込みが終えたら次はLED明滅の演出コードを書き込みます。コードは以下の通りです。Arduinoに書き込んでみましょう。

#include "Ws2822s.h"

// ==== ユーザー設定ここだけ ====
const uint8_t NUM_PIXELS = 6;   // ← 10 個あれば +9 まで安全。6 個なら 6 に
const uint8_t LED_PIN    = 13;   // DAI ピン
// ===========================

Ws2822s LED(LED_PIN, NUM_PIXELS);

void setup() {
  // 起動時は全消灯
  for (int i = 0; i < NUM_PIXELS; ++i) LED.setColor(i, 0, 0, 0);
  LED.send();
}

void loop() {
  // i が「先頭(赤)の位置」
  for (int i = 0; i < NUM_PIXELS; ++i) {

    // 6 色を順番に並べる
    LED.setColor(i              % NUM_PIXELS, 0xFF, 0x00, 0x00); // 赤
    LED.setColor((i + 1) % NUM_PIXELS, 0xFF, 0xFF, 0x00); // 黄
    LED.setColor((i + 2) % NUM_PIXELS, 0x00, 0xFF, 0x00); // 緑
    LED.setColor((i + 3) % NUM_PIXELS, 0x00, 0xFF, 0xFF); // シアン
    LED.setColor((i + 4) % NUM_PIXELS, 0x00, 0x00, 0xFF); // 青
    LED.setColor((i + 5) % NUM_PIXELS, 0xFF, 0x00, 0xFF); // マゼンタ

    // 後ろは余白として消灯
    //LED.setColor((i + 6) % NUM_PIXELS, 0x00, 0x00, 0x00);

    LED.send();     // 色データを LED へ転送
    delay(300);     // 0.3 秒ごとに 1 コマ進行
  }
}

上記が光ればOK!
※LEDは間近で直視しないことを推奨。明滅を確認したらUSB抜いてしまってください。

16進数(0xFFなど)とは

16進数(16進法)は、数字を表す方法の一つで、0から9までの数字とAからFまでの6つのアルファベットを使って数を表します。これは、私たちが普段使っている10進数と似ていますが、10進数では0から9までの10種類の数字しか使わないのに対して、16進数では16種類の記号を使います。

例えば、10進数では「10」という数字は「10」を意味しますが、16進数では「10」は「16」を意味します。10進数の16は、16進数では「10」になるのです。

具体的には:

  • 16進数の「0x0」は10進数の「0」
  • 16進数の「0x1」は10進数の「1」
  • 16進数の「0xA」は10進数の「10」
  • 16進数の「0xF」は10進数の「15」

次に、16進数の「0x10」は10進数の「16」、そして「0xFF」は10進数の「255」です。数字の前に「0x」が付くと、それは16進数を意味します。

どうして16進数を使うのか?

コンピュータは情報を扱うとき、基本的には2進数(0と1だけの数)を使います。しかし、2進数は桁数が多くて読みづらいので、それをまとめた形で表すために16進数が使われます。16進数だと、1つの桁で4つのビット(2進数の単位)をまとめて表すことができるため、コンピュータの情報を扱うのに便利です。

例えば、コンピュータで色を指定するとき、赤、緑、青の各色の明るさを0から255の範囲で表します。これは10進数でいうと「255」ですが、16進数で表すと「0xFF」になります。このため、赤色を「255, 0, 0」と指定する代わりに、16進数で「0xFF, 0x00, 0x00」と書くことが多いです。

1.4.2 発展編

以下は発展編です!

#include "Ws2822s.h"        // ライブラリ

// ------------ 設定 ------------
#define NUM_PIXELS 6        // ★ LED 本数を 6 に
#define LED_PIN    13       // ★ DAI ピン番号
// -----------------------------

Ws2822s LED(LED_PIN, NUM_PIXELS);

void setup() {
  // 起動時に全消灯(念のため)
  for (int i = 0; i < NUM_PIXELS; ++i) LED.setColor(i, 0, 0, 0);
  LED.send();
}

void loop() {
  // 基本のエフェクトを順番に実行
  colorWipe(0xFF, 0x00, 0x00, 50);     // 赤
  colorWipe(0x00, 0xFF, 0x00, 50);     // 緑
  colorWipe(0x00, 0x00, 0xFF, 50);     // 青

  theaterChase(0x7F, 0x7F, 0x7F, 80);  // 白シアター
  theaterChase(0x7F, 0x00, 0x00, 80);  // 赤シアター
  theaterChase(0x00, 0x00, 0x7F, 80);  // 青シアター

  rainbow(20);          // レインボー
  rainbowCycle(20);     // レインボーサイクル
  theaterChaseRainbow(80); // レインボーシアター
}

/* ---------- エフェクト関数 ---------- */

// LED を先頭から順に塗る
void colorWipe(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {
  for (uint8_t i = 0; i < NUM_PIXELS; ++i) {
    LED.setColor(i, r, g, b);
    LED.send();
    delay(wait);
  }
}

// シアターチェイス
void theaterChase(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {
  for (uint8_t cycle = 0; cycle < 10; ++cycle) {     // 10 周回
    for (uint8_t phase = 0; phase < 3; ++phase) {    // 点灯位置をずらす
      for (uint8_t i = phase; i < NUM_PIXELS; i += 3)
        LED.setColor(i, r, g, b);
      LED.send();
      delay(wait);

      // 消灯
      for (uint8_t i = phase; i < NUM_PIXELS; i += 3)
        LED.setColor(i, 0, 0, 0);
    }
  }
}

// レインボー (単発)
void rainbow(uint8_t wait) {
  for (uint16_t j = 0; j < 256; ++j) {
    for (uint8_t i = 0; i < NUM_PIXELS; ++i) {
      uint8_t r, g, b;
      colorWheel((i + j) & 255, r, g, b);
      LED.setColor(i, r, g, b);
    }
    LED.send();
    delay(wait);
  }
}

// レインボー (5 周回)
void rainbowCycle(uint8_t wait) {
  for (uint16_t j = 0; j < 256 * 5; ++j) {
    for (uint8_t i = 0; i < NUM_PIXELS; ++i) {
      uint8_t r, g, b;
      colorWheel(((i * 256 / NUM_PIXELS) + j) & 255, r, g, b);
      LED.setColor(i, r, g, b);
    }
    LED.send();
    delay(wait);
  }
}

// レインボー × シアターチェイス
void theaterChaseRainbow(uint8_t wait) {
  for (uint16_t j = 0; j < 256; ++j) {
    for (uint8_t phase = 0; phase < 3; ++phase) {
      for (uint8_t i = phase; i < NUM_PIXELS; i += 3) {
        uint8_t r, g, b;
        colorWheel((i + j) & 255, r, g, b);
        LED.setColor(i, r, g, b);
      }
      LED.send();
      delay(wait);

      // 消灯
      for (uint8_t i = phase; i < NUM_PIXELS; i += 3)
        LED.setColor(i, 0, 0, 0);
    }
  }
}

// 0–255 → RGB 変換
void colorWheel(uint8_t pos, uint8_t &r, uint8_t &g, uint8_t &b) {
  pos = 255 - pos;
  if (pos < 85) {                 // R→G
    r = 255 - pos * 3;
    g = pos * 3;
    b = 0;
  } else if (pos < 170) {         // G→B
    pos -= 85;
    r = 0;
    g = 255 - pos * 3;
    b = pos * 3;
  } else {                        // B→R
    pos -= 170;
    r = pos * 3;
    g = 0;
    b = 255 - pos * 3;
  }
}

※LEDは間近で直視しないことを推奨。明滅を一通り確認したらUSB抜いてしまってください。

2. 課題

以下をアップロードしてください。

  • 制作物の写真 1枚
    • Arduinoと自身で作成したLED全体が入るように写真を撮ってアップロードしてください(上記のGIF画像のイメージ)。LEDは光っている状態にしてください。
    • GIF画像でアップロードできる方は加点(ヒント:
       ffmpeg -i test.mp4 -vf scale=320:-1 -r 10 test.gif)。
  • LEDの半田付け部分の拡大写真 1枚
    • 半田付けのクオリティが確認できるように近くで撮影してください。
  • リアクションペーパーに回答してください。
    • 「なぜソフトウェアのみのアプリケーション開発と比べて、ハードウェアを含めたアプリケーション開発のデバッグ(エラーや不具合を見つけて修正すること)は難しいか?」に対する考えを書いてください。簡単な感想やもしわかりにくかった点・改善点などあれば教えてください。

2025/7/29 土田 更新