Bare Conductive Beginner Article 10

Touch-Activated Lighting

Control WS2812B NeoPixel LEDs from the Touch Board — colour changes, animations, and combined audio-visual responses.

⏱ 20 min read NeoPixel WS2812B LEDs lighting Adafruit visual feedback

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 by strip.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