Touch-Activated Lighting
Control WS2812B NeoPixel LEDs from the Touch Board — colour changes, animations, and combined audio-visual responses.
Adding visual feedback
The Touch Board’s built-in LED (D13) is barely visible and not usable for art. WS2812B NeoPixels (sold as Adafruit NeoPixels or similar) are addressable RGB LEDs you can control with a single data wire from the Touch Board — change any LED to any colour from code.
What you need
- Touch Board
- WS2812B LED strip or individual pixels (Adafruit NeoPixel, ALITOVE, etc.)
- 5V power supply (or USB for small LED counts)
- 300–500Ω resistor (on the data line)
- Optional: 1000 μF capacitor across the power rail
Wiring
Touch Board 5V ─────────────────── LED Strip 5V
Touch Board GND ─────────────────── LED Strip GND
Touch Board D6 ──── 470Ω ─────── LED Strip Data
Power warning: Each WS2812B LED draws up to 60mA at full white. 12 LEDs at full brightness = 720mA — more than USB can safely supply. For more than ~8 LEDs, use a separate 5V power supply rated at 1A+ and share the ground with the Touch Board.
Install the Adafruit NeoPixel library
Library Manager → search “Adafruit NeoPixel” → Install
Basic sketch: touch electrode → colour
#include <MPR121.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#define LED_PIN 6
#define LED_COUNT 12
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Assign a colour to each electrode
uint32_t COLOURS[12] = {
strip.Color(255, 0, 0), // E0 red
strip.Color(255, 127, 0), // E1 orange
strip.Color(255, 255, 0), // E2 yellow
strip.Color( 0, 255, 0), // E3 green
strip.Color( 0, 0, 255), // E4 blue
strip.Color(148, 0, 211), // E5 violet
strip.Color(255, 20, 147), // E6 pink
strip.Color( 0, 255, 255), // E7 cyan
strip.Color(255, 165, 0), // E8 amber
strip.Color(127, 255, 0), // E9 lime
strip.Color(138, 43, 226), // E10 purple
strip.Color(255, 255, 255), // E11 white
};
void setup() {
strip.begin();
strip.setBrightness(80); // 0–255
strip.show();
if (!MPR121.begin(0x5C)) { while(1); }
MPR121.setInterruptPin(4);
}
void loop() {
if (MPR121.touchStatusChanged()) {
MPR121.updateTouchData();
for (int i = 0; i < 12; i++) {
if (MPR121.isNewTouch(i)) {
strip.setPixelColor(i, COLOURS[i]);
strip.show();
}
if (MPR121.isNewRelease(i)) {
strip.setPixelColor(i, 0); // off
strip.show();
}
}
}
}
Combined audio + lighting
Add the MP3 player alongside the NeoPixels:
#include <MPR121.h>
#include <Wire.h>
#include <SPI.h>
#include <SdFat.h>
#include <FreeStack.h>
#include <SFEMP3Shield.h>
#include <Adafruit_NeoPixel.h>
SFEMP3Shield MP3player;
Adafruit_NeoPixel strip(12, 6, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(57600);
strip.begin();
strip.setBrightness(60);
strip.clear();
strip.show();
// MPR121 init
if (!MPR121.begin(0x5C)) { Serial.println("MPR121 error"); while(1); }
MPR121.setInterruptPin(4);
// MP3 init
SdFat sd;
if (!sd.begin(SD_SEL, SPI_HALF_SPEED)) { Serial.println("SD error"); while(1); }
if (!MP3player.begin()) { Serial.println("MP3 error"); }
MP3player.setVolume(10, 10); // lower = louder on VS1053
}
void loop() {
if (MPR121.touchStatusChanged()) {
MPR121.updateTouchData();
for (int i = 0; i < 12; i++) {
if (MPR121.isNewTouch(i)) {
// Play sound
char filename[12];
sprintf(filename, "TRACK%03d.mp3", i);
if (MP3player.isPlaying()) MP3player.stopTrack();
MP3player.playMP3(filename);
// Light the LED
strip.setPixelColor(i, COLOURS[i]);
strip.show();
}
if (MPR121.isNewRelease(i)) {
strip.setPixelColor(i, 0);
strip.show();
}
}
}
}
Animations on touch
More expressive than on/off: fade in on touch, fade out on release:
uint8_t brightness[12] = {0};
bool touching[12] = {false};
void loop() {
// Update touch state
if (MPR121.touchStatusChanged()) {
MPR121.updateTouchData();
for (int i = 0; i < 12; i++) {
if (MPR121.isNewTouch(i)) touching[i] = true;
if (MPR121.isNewRelease(i)) touching[i] = false;
}
}
// Animate brightness
for (int i = 0; i < 12; i++) {
if (touching[i]) {
brightness[i] = min(255, brightness[i] + 15); // fade in
} else {
brightness[i] = max(0, brightness[i] - 5); // fade out (slower)
}
// Scale the LED colour by brightness
uint8_t r = (red(COLOURS[i]) * brightness[i]) / 255;
uint8_t g = (green(COLOURS[i]) * brightness[i]) / 255;
uint8_t b = (blue(COLOURS[i]) * brightness[i]) / 255;
strip.setPixelColor(i, r, g, b);
}
strip.show();
delay(16); // ~60fps update
}
Key takeaways
- WS2812B NeoPixels connect via a single data pin (D6) with a 470Ω series resistor
- Each LED draws up to 60mA at full brightness — use a separate power supply for more than 8 LEDs
strip.setPixelColor(i, colour)followed bystrip.show()updates the display- One NeoPixel per electrode creates immediate visual feedback for each touch
- Fade animations (update brightness each frame) are far more expressive than on/off
- The NeoPixel data pin (D6) is fully compatible with the Touch Board alongside MPR121 and MP3 player