ArduinoでクリスマスツリーのLEDライト:WS2812Bで雪と虹のエフェクト
ArduinoでクリスマスツリーのLEDライトを作ります。WS2812BのLEDテープ、雪、虹、きらめきのエフェクト、ボタンでのモード切り替え、5 V電源の計算とコードを紹介します。
クリスマスツリーのLEDプロジェクトにArduinoとWS2812BのLEDテープを使うと、市販のツリーライトにある決まった数種類のモードを超えて、いちばん楽しく遊べます。LEDを1個ずつ色と明るさを制御できるので、てっぺんから舞い降りる雪、枝のまわりを回る虹、ランダムにきらめく赤・緑・金色の星などを加えられます。しかも必要なのは、データ線1本、ボタン1個、そして正しく選んだ5 V電源だけです。
このガイドでは、部品リストから始めて、テープの長さに合わせた電源の計算、電源・ボード・テープの正しい配線、ボタンでエフェクトを切り替える完全なArduino Unoのプログラム(FastLED)、そして同じプロジェクトのESP32版(Adafruit NeoPixel)とRaspberry Pi Pico版(MicroPython)を、ステップごとに組み立てていきます。最後に、テープをツリーに巻く方法、安全面で気をつけること、よくある問題の解決方法も紹介します。

クリスマスツリーにWS2812BのLEDテープを使う理由
昔ながらのクリスマスライトでは、すべての電球が同時に点灯するか、いくつかのグループに分かれて順番に点灯します。一方WS2812Bは、LEDの1個1個に小さなドライバチップが入っています。Arduinoはデータ線で色の情報を次々に送り、最初のLEDが自分の分の24ビットを受け取って、残りを次のLEDに渡します。そのため100個や300個のLEDテープを1本のピンで制御でき、LEDごとに別々の色を設定できます。この仕組みのおかげで、雪のように動くエフェクトに、固定のライトでは出せない生き生きとした表情が生まれます。アドレサブルLEDの仕組みをもっと詳しく知りたい場合は、WS2812B NeoPixelの記事をご覧ください。
| 項目 | 値 |
|---|---|
| パッケージ | 5050 SMD、ドライバチップはLEDに内蔵 |
| 電源 | 5 V(おおよそ3.5〜5.3 V) |
| 電流 | 1色あたり約20 mA、白の最大輝度で約60 mA |
| データ | 1本の信号線、800 kHz、LED1個あたり24ビット(G-R-Bの順) |
| データの送信時間 | LED1個あたり30 µs、100個で約3 ms |
| データ入力のしきい値 | 論理1には少なくとも0.7 × VDD(5 Vで3.5 V) |
| 色 | 1チャンネルあたり256段階、合計1,670万色 |
| テープの密度 | 30、60、144 LED/m |
| カット | LEDの間にある銅パッドの中央で切断できる |
部品リスト
- WS2812BのLEDテープ:高さ1.5〜1.8 mのツリーなら、60 LED/mのテープ2.5 mか、30 LED/mのテープ5 mから始めるのがおすすめです。シリコン被覆のIP65タイプは、枝に引っかけたりほこりがついたりしても丈夫です。
- 制御用ボード:Arduino Uno、Nano、ESP32、またはRaspberry Pi Pico。
- 5 V電源:電流値は下の表を見て選んでください。LED 100個なら5 V 4 Aが余裕のある選択です。
- DCジャック(メス、ネジ端子付き):電源のプラグを、はんだ付けなしで配線につなぐためのものです。
- 1000 µF / 10 Vの電解コンデンサ:テープの入口で急な電流の変動をなだらかにします。
- 330 Ωの抵抗:データ線に直列に入れます。信号の反射をおさえ、最初のLEDの入力電流を制限します。
- 押しボタン:エフェクトを切り替えるためのものです。
- 太い電線:5VとGNDのラインには、断面積が少なくとも0.75〜1.5 mm²の電線を使います。
- 必要に応じて74AHCT125または74HCT245:ESP32やPicoの3.3 Vのデータ信号を5 Vに引き上げるためのものです。
電源の計算:何アンペアの電源が必要?
WS2812Bの中にある赤・緑・青のチップは、それぞれ最大輝度で約20 mAを消費します。つまりLED1個は、白の最大輝度で約60 mAを使います。最悪の場合の電流はI = LEDの数 × 60 mAの式で求められます。LED 100個のテープは、すべてのLEDが真っ白で最大輝度のとき6 Aを消費し、P = 5 V × 6 A = 30 Wになります。虹、雪、星のエフェクトでは、ほとんどのLEDが単色か暗めなので、実際の電流は最悪の場合の3分の1程度にとどまります。安全に選ぶには、この標準的な電流を2倍してから一番近い電源の定格に切り上げ、ソフトウェアの電流制限を電源の約80%に設定してください。電流・電圧・電力の関係は、オームの法則計算ツールで簡単に確認できます。
| LEDの数 | 最悪の場合(白の最大輝度) | エフェクトの標準的な電流 | おすすめの電源 | ソフトウェアの制限(MAX_MA) |
|---|---|---|---|---|
| 30 | 1.8 A | 約0.6 A | 5 V 2 A | 1600 mA |
| 60 | 3.6 A | 約1.2 A | 5 V 3 A | 2400 mA |
| 100 | 6 A | 約2 A | 5 V 4 A | 3200 mA |
| 150 | 9 A | 約3 A | 5 V 6 A | 4800 mA |
| 300(5 m、60 LED/m) | 18 A | 約6 A | 5 V 12 A | 9600 mA |
長いテープでは、2つ目の問題として電圧降下が起こります。テープ上の細い銅のパターンには抵抗があるため、5 mのテープの終端では電圧が4 Vを下回ることがあります。すると青と緑のチップが弱くなり、白が黄色っぽくくすんで見えます。対策は、5VとGNDをテープの始まりだけでなく、1〜1.5 mごと(またはLED 100〜150個ごと)に、電源から引いた別の電線でもう一度給電することです。これを電源インジェクション(給電の追加)といいます。この電線には、5 Aなら少なくとも0.75 mm²、10 Aなら1.5 mm²の太さを使ってください。データ線はテープの始まりにだけつなぎます。
配線図:5 V電源、テープ、ボード
| 接続 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| テープのDIN(データ) | D6(330 Ω経由) | GPIO 13(330 Ω経由) | GP0(330 Ω経由) |
| テープの5V | 電源の+5 V | 電源の+5 V | 電源の+5 V |
| テープのGND | 電源のGND + UnoのGND | 電源のGND + ESP32のGND | 電源のGND + PicoのGND |
| ボタン | D2とGND | GPIO 4とGND | GP15とGND |
| 1000 µFのコンデンサ | テープの入口で5V–GND間 | テープの入口で5V–GND間 | テープの入口で5V–GND間 |
| ボードの電源(完成時) | 5VピンまたはUSB | 5V(VIN)ピンまたはUSB | VSYS(ショットキーダイオード経由)またはUSB |
- テープ上の矢印を探し、矢印が始まる側の端(DIN)に電線をはんだ付けします。反対側のDOUT側からデータを送っても、LEDは1個も点灯しません。
- 電源の+5 V出力をテープの5V端子(テープによっては+5VやVCCと表記)に、電源のGNDをテープのGND端子につなぎます。
- 1000 µFのコンデンサを、テープの入口で5VとGNDの間につなぎます。長い足(プラス)を5Vに、本体に帯の印がある側の足(マイナス)をGNDにつなぎます。
- ボードのGNDピンを電源のGNDにつなぎます。共通のGNDがないと、データ信号の基準がなくなります。
- ボードのデータピン(UnoではD6)を、330 Ωの抵抗を通してテープのDIN端子につなぎます。抵抗はテープに近い側に置くと、より安定します。
- ボタンの片方の足をD2に、もう片方をGNDにつなぎます。内部プルアップはコードで有効にします。
- LEDを150個より多く使う場合は、テープの中央と終端にも、電源から別の5VとGNDの電線を引いてください。
- 開発中はボードをUSBから、テープを電源から給電します。完成したら電源の5 VをUnoの5Vピンに入れてもかまいませんが、その場合はUSBケーブルを同時に挿さないでください。
Arduino Unoのコード(FastLED):3つのエフェクトとボタンでのモード切り替え
Arduino IDEでライブラリマネージャを開き、FastLEDを検索してライブラリをインストールします。詳しい手順はArduinoにライブラリを追加する方法をご覧ください。下のプログラムには、虹、雪、星のようにきらめくエフェクトが入っていて、ボタンを押すたびに次のエフェクトに切り替わります。コードはdelay()ではなくmillis()を使っているので、エフェクトの動作中もいつでもボタンを検出できます。この方法の考え方はmillis()とdelay()の違いの記事で紹介しています。
1#include <FastLED.h>
2
3#define LED_PIN 6 // şeridin DIN girişi (330 ohm üzerinden) / strip DIN input (via 330 ohm)
4#define BUTTON_PIN 2 // buton, diğer bacak GND / button, other leg to GND
5#define NUM_LEDS 100 // şeritteki LED sayısı / number of LEDs on the strip
6#define BRIGHTNESS 120 // genel parlaklık 0-255 / global brightness 0-255
7#define MAX_MA 3200 // 4 A adaptörün %80'i / 80% of a 4 A supply
8
9CRGB leds[NUM_LEDS];
10
11const uint8_t MODE_COUNT = 3; // 0 gökkuşağı, 1 kar, 2 yıldız / 0 rainbow, 1 snow, 2 twinkle
12const uint16_t FRAME_MS[MODE_COUNT] = {20, 60, 30}; // kare süreleri (ms) / frame times (ms)
13const CRGB XMAS[4] = {CRGB::Red, CRGB::Green, CRGB::Gold, CRGB::White};
14
15uint8_t mode = 0;
16uint8_t hue = 0;
17
18void setup() {
19 pinMode(BUTTON_PIN, INPUT_PULLUP);
20 FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
21 FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_MA); // akım sınırı / current limit
22 FastLED.setBrightness(BRIGHTNESS);
23 FastLED.clear(true); // açılışta hepsini söndür / all off at start
24}
25
26void checkButton() {
27 static bool lastState = HIGH;
28 static unsigned long lastChange = 0;
29 bool state = digitalRead(BUTTON_PIN);
30 if (state != lastState && millis() - lastChange > 50) { // 50 ms zıplama filtresi / 50 ms debounce
31 lastChange = millis();
32 lastState = state;
33 if (state == LOW) { // basıldı / pressed
34 mode = (mode + 1) % MODE_COUNT;
35 FastLED.clear();
36 }
37 }
38}
39
40void rainbow() {
41 fill_rainbow(leds, NUM_LEDS, hue, 3); // her LED'de ton 3 artar / hue +3 per LED
42 hue += 2; // renkler döner / colours rotate
43}
44
45void snowfall() {
46 for (int i = 0; i < NUM_LEDS - 1; i++) {
47 leds[i] = leds[i + 1]; // bir LED aşağı kaydır / shift one LED down
48 }
49 if (random8() < 38) {
50 leds[NUM_LEDS - 1] = CRGB::White; // tepede yeni kar tanesi / new flake at the top
51 } else {
52 leds[NUM_LEDS - 1] = CRGB(0, 0, 24); // koyu mavi gece / dark blue night
53 }
54}
55
56void twinkle() {
57 fadeToBlackBy(leds, NUM_LEDS, 20); // hepsini biraz kıs / dim everything a little
58 if (random8() < 80) {
59 leds[random16(NUM_LEDS)] = XMAS[random8(4)]; // rastgele yıldız / random star
60 }
61}
62
63void loop() {
64 checkButton();
65 static unsigned long lastFrame = 0;
66 if (millis() - lastFrame >= FRAME_MS[mode]) {
67 lastFrame = millis();
68 if (mode == 0) rainbow();
69 else if (mode == 1) snowfall();
70 else twinkle();
71 FastLED.show(); // renkleri şeride gönder / push colours to the strip
72 }
73}| 行・設定 | 役割 |
|---|---|
| NUM_LEDS | テープのLEDの数です。間違えると、テープの一部が点灯しなかったり、エフェクトがずれたりします。 |
| BRIGHTNESS | 全体の明るさ(0〜255)です。120くらいでツリーには十分明るく、電流と発熱の面でも安全です。 |
| setMaxPowerInVoltsAndMilliamps(5, MAX_MA)(電流制限) | FastLEDがフレームごとの消費電流を予測し、制限を超えそうなら自動で明るさを下げます。 |
| addLeds<WS2812B, LED_PIN, GRB>(テープの設定) | テープの種類、データピン、色の順番を設定します。WS2812Bの順番はGRBです。 |
| FRAME_MS | 各エフェクトのフレーム時間(ms)です。値が小さいほどアニメーションが速くなります。 |
| checkButton()(ボタンの読み取り) | 50 msのチャタリング対策をしてボタンを読み取り、押すたびにモードを1つ進めます。 |
| FastLED.show()(テープへの送信) | メモリ上の色をテープに送ります。呼び出さないと、変化は何も表示されません。 |
エフェクトの仕組み
虹:fill_rainbow関数は、最初のLEDに指定した色相(hue)から始めて、LEDごとに色相を3ステップずつ増やします。FastLEDの色相は0〜255の範囲なので、LED 100個では色相が合計300ステップ進み、テープ全体で色の輪が1周より少し多く表示されます。フレームごとに変数hueを2ずつ増やしているので、色がツリーのまわりをゆっくり回ります。色の帯をもっと広くしたい場合は、3の代わりに1か2を使ってください。
雪:テープをツリーに下から上へ巻くと、最初のLEDがいちばん下、最後のLEDがてっぺんになります。フレームごとにすべての色をLED1個分下にずらし、てっぺんに白い雪の粒か濃い青の夜空のピクセルを追加します。random8()は0〜255の数を返すので、38より小さくなる確率は約15%です。この数を大きくすると雪が多くなります。フレーム時間が60 msなら、雪の粒は6秒でLED 100個分を降りてきます。きらめき(星):fadeToBlackByはフレームごとにすべてのLEDを約8%暗くします。同時に、ランダムに選んだLEDを1個、赤・緑・金色・白のどれかで最大輝度に点灯させます。昔ながらのクリスマスライトを思わせながら、ずっと生き生きとしたきらめきになります。
ESP32で作るクリスマスツリー(Adafruit NeoPixel)
ESP32でもFastLEDは動きますが、ここでは同じプロジェクトをAdafruit NeoPixelライブラリで書きます。こうすれば人気のある2つのライブラリの両方に触れられます。このライブラリの最新版は、ESP32 Arduinoコアの2.xと3.xで同じコードのままコンパイルでき、ハードウェアのRMTユニットで信号を生成します。Adafruit NeoPixelではsetBrightnessで暗くした色を読み戻すと崩れることがあるため、エフェクトは独自の明るさの配列(level)で計算し、フレームごとにテープへ最初から書き直しています。データピンはGPIO 13、ボタンはGPIO 4です。あとでツリーをスマホから操作したくなったら、WLEDのセットアップの記事で、すぐに使える操作画面を紹介しています。
1#include <Adafruit_NeoPixel.h>
2
3#define LED_PIN 13 // şeridin DIN girişi (330 ohm üzerinden) / strip DIN input (via 330 ohm)
4#define BUTTON_PIN 4 // buton, diğer bacak GND / button, other leg to GND
5#define NUM_LEDS 100 // şeritteki LED sayısı / number of LEDs on the strip
6
7Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
8
9const uint8_t MODE_COUNT = 3; // 0 gökkuşağı, 1 kar, 2 yıldız / 0 rainbow, 1 snow, 2 twinkle
10const uint16_t FRAME_MS[MODE_COUNT] = {20, 60, 30}; // kare süreleri (ms) / frame times (ms)
11const uint8_t PALETTE[4][3] = {{255, 0, 0}, {0, 255, 0}, {255, 160, 0}, {255, 255, 255}};
12
13uint8_t level[NUM_LEDS]; // LED başına parlaklık / per-LED level
14uint8_t colorIdx[NUM_LEDS]; // yıldız rengi / star colour index
15uint8_t mode = 0;
16uint16_t hue = 0;
17
18void setup() {
19 pinMode(BUTTON_PIN, INPUT_PULLUP);
20 strip.begin();
21 strip.setBrightness(110); // genel parlaklık / global brightness
22 strip.clear();
23 strip.show();
24}
25
26void checkButton() {
27 static bool lastState = HIGH;
28 static unsigned long lastChange = 0;
29 bool state = digitalRead(BUTTON_PIN);
30 if (state != lastState && millis() - lastChange > 50) { // 50 ms zıplama filtresi / 50 ms debounce
31 lastChange = millis();
32 lastState = state;
33 if (state == LOW) { // basıldı / pressed
34 mode = (mode + 1) % MODE_COUNT;
35 memset(level, 0, sizeof(level)); // efekt belleğini sıfırla / reset effect buffer
36 strip.clear();
37 }
38 }
39}
40
41void rainbow() {
42 for (int i = 0; i < NUM_LEDS; i++) {
43 uint16_t h = hue + (uint32_t)i * 65536UL / NUM_LEDS; // LED'e göre ton / hue per LED
44 strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(h)));
45 }
46 hue += 256; // renkler döner / colours rotate
47}
48
49void snowfall() {
50 for (int i = 0; i < NUM_LEDS - 1; i++) level[i] = level[i + 1]; // bir LED aşağı kaydır / shift one LED down
51 level[NUM_LEDS - 1] = (random(100) < 15) ? 255 : 0; // tepede yeni kar / new flake on top
52 for (int i = 0; i < NUM_LEDS; i++) {
53 if (level[i]) strip.setPixelColor(i, 255, 255, 255); // kar tanesi / snowflake
54 else strip.setPixelColor(i, 0, 0, 24); // koyu mavi gece / dark blue night
55 }
56}
57
58void twinkle() {
59 for (int i = 0; i < NUM_LEDS; i++) {
60 level[i] = (level[i] > 12) ? level[i] - 12 : 0; // yavaşça sön / fade out
61 }
62 if (random(100) < 30) {
63 int p = random(NUM_LEDS);
64 level[p] = 255; // yeni yıldız / new star
65 colorIdx[p] = random(4);
66 }
67 for (int i = 0; i < NUM_LEDS; i++) {
68 const uint8_t *c = PALETTE[colorIdx[i]];
69 strip.setPixelColor(i, c[0] * level[i] / 255, c[1] * level[i] / 255, c[2] * level[i] / 255);
70 }
71}
72
73void loop() {
74 checkButton();
75 static unsigned long lastFrame = 0;
76 if (millis() - lastFrame >= FRAME_MS[mode]) {
77 lastFrame = millis();
78 if (mode == 0) rainbow();
79 else if (mode == 1) snowfall();
80 else twinkle();
81 strip.show(); // renkleri şeride gönder / push colours to the strip
82 }
83}Raspberry Pi PicoとMicroPythonで作るクリスマスツリー
Raspberry Pi PicoのMicroPythonにはneopixelモジュールが最初から入っているので、追加で何かをインストールする必要はありません。このモジュールがWS2812Bの精密なタイミングを自分で処理するため、どのGPピンでも使えます。下の例では、データをGP0に、ボタンをGP15につないでいます。MicroPythonには全体の明るさの設定がないので、BRIGHT係数で色を自分で暗くしています。PythonはC++より動作が遅いため、LED 100個ならエフェクトはなめらかですが、300個を超えるとフレーム時間が長くなることがあります。MicroPythonが初めてなら、MicroPythonの基本の記事から始めてみてください。
1from machine import Pin
2import neopixel, time, random
3
4NUM_LEDS = 100
5BRIGHT = 0.4 # 0-1 parlaklık / brightness
6np = neopixel.NeoPixel(Pin(0), NUM_LEDS) # veri GP0 / data on GP0
7button = Pin(15, Pin.IN, Pin.PULL_UP) # buton GP15-GND / button GP15-GND
8
9mode = 0
10MODE_COUNT = 3 # 0 gökkuşağı, 1 kar, 2 yıldız / 0 rainbow, 1 snow, 2 twinkle
11FRAME_MS = (20, 60, 30) # kare süreleri / frame times
12level = [0] * NUM_LEDS # LED başına parlaklık / per-LED level
13color_idx = [0] * NUM_LEDS # yıldız rengi / star colour index
14PALETTE = ((255, 0, 0), (0, 255, 0), (255, 160, 0), (255, 255, 255))
15hue = 0
16
17def scale(r, g, b):
18 return (int(r * BRIGHT), int(g * BRIGHT), int(b * BRIGHT))
19
20def wheel(pos):
21 # 0-255 -> gökkuşağı rengi / rainbow colour
22 pos = pos & 255
23 if pos < 85:
24 return (255 - pos * 3, pos * 3, 0)
25 if pos < 170:
26 pos -= 85
27 return (0, 255 - pos * 3, pos * 3)
28 pos -= 170
29 return (pos * 3, 0, 255 - pos * 3)
30
31def rainbow():
32 global hue
33 for i in range(NUM_LEDS):
34 np[i] = scale(*wheel(hue + i * 256 // NUM_LEDS))
35 hue = (hue + 2) & 255 # renkler döner / colours rotate
36
37def snowfall():
38 for i in range(NUM_LEDS - 1):
39 level[i] = level[i + 1] # bir LED aşağı kaydır / shift one LED down
40 level[-1] = 255 if random.randint(0, 99) < 15 else 0
41 for i in range(NUM_LEDS):
42 np[i] = scale(255, 255, 255) if level[i] else scale(0, 0, 24)
43
44def twinkle():
45 for i in range(NUM_LEDS):
46 level[i] = level[i] - 12 if level[i] > 12 else 0 # yavaşça sön / fade out
47 if random.randint(0, 99) < 30:
48 p = random.randint(0, NUM_LEDS - 1)
49 level[p] = 255 # yeni yıldız / new star
50 color_idx[p] = random.randint(0, 3)
51 for i in range(NUM_LEDS):
52 r, g, b = PALETTE[color_idx[i]]
53 k = level[i] * BRIGHT / 255
54 np[i] = (int(r * k), int(g * k), int(b * k))
55
56effects = (rainbow, snowfall, twinkle)
57last_btn = 1
58last_change = time.ticks_ms()
59last_frame = time.ticks_ms()
60
61while True:
62 now = time.ticks_ms()
63 state = button.value()
64 if state != last_btn and time.ticks_diff(now, last_change) > 50: # zıplama filtresi / debounce
65 last_change = now
66 last_btn = state
67 if state == 0: # basıldı / pressed
68 mode = (mode + 1) % MODE_COUNT
69 for i in range(NUM_LEDS):
70 level[i] = 0
71 if time.ticks_diff(now, last_frame) >= FRAME_MS[mode]:
72 last_frame = now
73 effects[mode]()
74 np.write() # şeride gönder / push to the stripテープをツリーに取り付ける方法と安全対策
- 下から始める:テープのDIN側をツリーの根元、制御ボックスの横に置き、らせん状に上へ巻いていきます。こうすると雪のエフェクトがてっぺんから下へ流れ、データ線も短くできます。
- らせんの間隔:1.8 mのツリーなら、20〜25 cm間隔で巻くと5 mのテープが枝にバランスよく広がります。ツリーの上に行くほど1周の直径が小さくなるので、間隔を少しせまくしてもかまいません。
- 縦方向のテープ:テープを上から下、下から上へとジグザグに配置することもできます。この配置では、雪のエフェクトの向きが1本おきに逆になるため、テープの番号からLEDの順番を計算する小さな修正が必要です。
- 発熱:WS2812Bのテープは明るさが高いと熱くなります。紙の飾りや乾いた枝に強く押しつけないでください。明るさを100〜150くらいにしておくと、発熱も電流も減らせます。
- 電源の安全:220 V側に自作の回路を組まないでください(日本の商用電源は100V(50/60Hz)です)。CEマーク付き(日本ではPSEマーク付き)で、ケースに収まった市販の5 V電源を使ってください。制御ボックスは水や植木の水やりから離し、外出するときはツリーの電源を切ってください。
- ヒューズ:5 Aを超えるシステムでは、電源の出力に適切な定格のブレードヒューズを入れておくと、万一のショートへの備えになります。
クリスマスツリーのプロジェクトアイデア
- 音楽に反応するツリー:マイクを使って、曲のリズムに合わせてライトを光らせます。詳しくは音楽に反応するLEDの記事をご覧ください。
- 新年のカウントダウン:深夜0時までの残り時間をディスプレイに表示し、00:00になったらツリーで花火のエフェクトを始めます。新年のカウントダウンタイマーの記事をご覧ください。
- 自動で点灯するツリー:LDR光センサーで、暗くなったら自動でライトを点灯させます。
- 近づくと明るくなるツリー:部屋に人が入ったらPIR人感センサーで明るさを上げ、誰もいないときは暗くします。
- スマホから操作:ESP32でWebページを開き、エフェクトや色をスマホから選びます。ESP32のWebサーバーの記事が出発点としておすすめです。
- てっぺんの星のディスプレイ:ツリーのてっぺんに小さなWS2812B LEDマトリクスを付けて、星や雪の結晶のアニメーションを再生します。
よくあるミスと対処法
| 症状 | 考えられる原因 | 対処法 |
|---|---|---|
| LEDが1個も点灯しない | データがDOUT側につながっている、またはGNDが共通になっていない | 矢印の向きを確認してDIN側につなぎ、ボードと電源のGNDをつなぐ |
| 最初のほうのLEDがちらつく、ランダムな色になる | データ信号が弱い、3.3 Vのレベル、データ線が長い | 330 Ωの抵抗をテープに近づけ、データ線を短くし、74AHCT125を使う |
| 色が違う(赤のはずが緑) | 色の順番の設定ミス | FastLEDではGRB、NeoPixelではNEO_GRBを使う。RGBの順番のテープもある |
| テープの終端が黄色っぽく暗い | 電圧降下 | 中央と終端にも給電を追加し、太い電線を使う |
| 白にするとボードがリセットする | 電源の容量不足、急な電流の消費 | 電源を大きくし、MAX_MAの制限を下げ、1000 µFのコンデンサを追加する |
| ボタンを1回押すとモードが2つ進む | ボタンのチャタリング | チャタリング対策の時間を50 msから80 msに延ばし、ボタンの配線を短くする |
| Picoでエフェクトの動きが遅い | LEDが多すぎる、Pythonの計算 | NUM_LEDSを減らすか、フレーム時間を長くするか、Arduino IDEとC++に切り替える |
数メートルのLEDテープ、ボタン1個、適切な容量の5 V電源があれば、クリスマスツリーは毎年新しいエフェクトで楽しめるプログラム可能な光のショーに変わります。カラーパレットやフレーム時間をいろいろ変えて、オリジナルのエフェクトを作ってみてください。電源や配線で迷ったときは、Arduinoの電源の取り方のガイドを読み返してください。BlueGraysアプリでは、WS2812Bを使った流れるLED、ナイトライダー、パトランプ、アニメーションのプロジェクトのほか、ESP32でのNeoPixelテープの制御も、回路図とコードつきでステップごとに紹介しています。
よくある質問
クリスマスツリーにはLEDが何個必要ですか?
高さ1.5〜1.8 mのツリーなら、LED 150〜300個、つまり30 LED/mのテープ5 mか、60 LED/mのテープ2.5〜5 mで、にぎやかで生き生きとした見た目になります。もっと少なくても動きますが、エフェクトがまばらに見えます。LEDの数が増えるほど、電源の電流とボードのRAM(LED1個あたり3バイト)も考慮する必要があります。
WS2812BのLEDテープには何アンペアの電源が必要ですか?
LED1個は白の最大輝度で約60 mAを消費するので、100個では最悪の場合6 Aになります。カラフルなエフェクトでは実際の電流はその3分の1程度なので、FastLEDのsetMaxPowerInVoltsAndMilliamps関数で電流を3200 mAに制限すれば、LED 100個に5 V 4 Aの電源で足ります。白の最大輝度で長時間使う場合は、最悪の場合に合わせて電源を選んでください。
WS2812Bのテープは12 Vで動きますか?
いいえ。WS2812Bは5 V用のテープで、12 Vをつなぐと LEDがすぐに壊れます。12 Vで動くアドレサブルLEDテープがほしい場合は、WS2811かWS2815のタイプを選んでください。手持ちの12 V電源を小さなテープに使いたい場合は、LM2596のような降圧コンバーターで5 Vを作れますが、こうしたモジュールは約2〜3 Aまでに限られます。
FastLEDとAdafruit NeoPixelのどちらを使えばいいですか?
どちらもWS2812Bを問題なく駆動できます。FastLEDは虹、カラーパレット、減光、電流制限などの関数がそろっていてエフェクトを書きやすく、たいていこちらのほうが高速です。Adafruit NeoPixelはよりシンプルなAPIです。初めてなら、どちらか一方から始めて、そのあともう一方を試すのがよい方法です。
Arduino UnoではWS2812BのLEDを最大何個まで制御できますか?
上限はRAMと速度で決まります。Unoの2 KBのRAMではLED1個に3バイト使うので、ほかの変数も含めると実用上は500個くらいが限界です。また、LED1個にデータを送るのに30 µsかかるため、1000個では1フレームが30 msになります。ESP32やPicoはRAMが豊富なので数千個も可能で、本当の制限は電源になります。
LEDテープの終端が黄色っぽく、または暗く光るのはなぜですか?
これは電圧降下のサインです。テープの細い銅のパターンでは、電流が増えるほど電圧が下がります。4 Vを下回ると終端のLEDは青と緑が弱くなり、白が黄色寄りになります。テープの中央と終端に電源から別の5VとGNDの電線を引き、明るさを少し下げれば解決します。
この記事を読んだ後に作れるプロジェクト
全プロジェクトを見る
WS2812B LEDテープの使い方
1つずつ自由に色を変えられるスマートLEDテープを使ってみます。Arduinoが最初の5個のLEDを赤く点灯し、1秒後に残りの5個を青く点灯します。その後すべて消灯し、最初から繰り返します。1本の配線で何十個ものLEDを個別の色にするための第一歩です。このようなテープは、装飾用のライトや部屋の照明にも使われています。

WS2812Bで作るパトカー風ライト
パトカーの屋根にある赤と青の点滅灯を、机の上で再現します。10個のLEDを備えたWS2812Bテープの半分が赤で素早く3回点滅し、続いて残りの半分が青で3回点滅します。このパターンを繰り返し続けます。1本のデータ線につながったカラーLEDを、それぞれ好きな色に設定する方法がわかります。

WS2812Bで流れるLED
10個のLEDが並ぶテープで、緑の光が端から端へ1個ずつ進み、最後まで来ると先頭に戻ります。各LEDは3分の1秒ずつ点灯します。WS2812Bテープでは、1本のデータ線で各LEDを個別に制御でき、Arduinoへの接続も3本の配線だけで済みます。カラフルなLEDテープを使う第一歩です。

WS2812Bで流れるLED(積み上げ点灯)
コップに水を注ぐように、光が満ちては減っていくLEDテープです。Arduinoが10個のカラーLEDをオレンジ色に1個ずつ点灯し、点灯したままにします。すべて点灯すると、同じ順番で1個ずつ消灯し、最初から繰り返します。このシンプルなアニメーションで、1本の配線から各LEDを個別に制御する方法がわかります。

WS2812Bのナイトライダー風ライト
スマートLEDテープの赤い光が端から端へ移動して戻り、往復を繰り返し続けます。Arduinoは各ステップで1個のLEDだけを点灯し、0.1秒待ってから隣へ移ります。6個の個別のLEDと何十本もの配線を使う代わりに、1本のテープと1本のデータ線で同じ流れる光を実現できます。

WS2812Bアニメーション1
56個のLEDが並ぶテープで、虹のすべての色が隣り合って途切れずに流れます。まるで光の川がテープの上を流れるようです。各LEDは1つ前のLEDと少し違う色に光り、色が移り変わるたびにテープが生き生きと見えます。部屋や机を彩る、いちばん手軽な方法です。

WS2812Bアニメーション2
自動で色が変わる光のショーを部屋に作ります。Arduinoが30個のLEDを備えたテープに色を流し続け、数秒ごとに新しい配色へ切り替えます。虹色、紫と緑の縞模様、白黒の縞模様、雲を思わせる色、パーティー向けの色、ランダムな色の組み合わせが登場します。何も操作せずに、テープが1分間のショーを最初から最後まで再生します。

ESP32 WS2812B NeoPixel LEDテープの制御
WS2812B(NeoPixel)は、1本のデータピンで連結したLEDを個別に制御できるスマートなRGB LEDです。このプロジェクトでは、8個のLEDを備えたWS2812BテープをAdafruit_NeoPixelライブラリで制御し、滑らかな虹色のアニメーションを作ります。ESP32の3.3VロジックレベルはほとんどのWS2812Bのロットで問題なく動作しますが、不安定な場合に備え、470Ωの直列抵抗と1000µFのコンデンサを使う対策も紹介します。アニメーションは、HSV色空間の色相(hue)をずらして作ります。
ほかの記事
BlueGraysアプリ
この回路をスマホでステップごとに作る
回路図、コード、部品リストを1つの画面で確認できます。Arduino、ESP32、Picoのプロジェクトを200件以上用意しています。

