The NeoPixel Digital RGB LED Strip (144 LED/m) is a really impressive product that will have you lighting up your room in next to no time. The 144 individually addressable LEDs packed onto a 1 metre flexible water resistant strip, enables a world of luminescent creativity that will blow your blinking Arduino friends away. The following tutorial will show you how to create an immersive and interactive LED display using an Arduino UNO, a potentiometer and an accelerometer. There will be a total of FIVE LED sequences to keep you entertained or you can create your own !
Before you start any LED strip project, the first thing you will need to think about is POWER. According to the Adafruit website, each individual NeoPixel LED can draw up to 60 milliamps at maximum brightness - white. Therefore the amount of current required for the entire strip will be way more than your Arduino can handle. If you try to power this LED strip directly from your Arduino, you run the risk of damaging not only your Arduino, but your USB port as well. The Arduino will be used to control the LED strip, but the LED strip will need to be powered by a separate power supply. The power supply you choose to use is important. It must provide the correct voltage, and must able to supply sufficient current.
Operating Voltage(5V)
The operating voltage of the NeoPixel strip is 5 volts DC. Excessive voltage will damage/destroy your NeoPixels.
Current requirements (8.6 Amps)
OpenLab recommend the use of a 5V 10A power supply. Having more Amps is OK, providing the output voltage is 5V DC. The LEDs will only draw as much current as they need. To calculate the amount of current this 1m strip can draw with all LEDs turned on at full brightness - white:
144 NeoPixel LEDs x 60 mA x 1 m = 8640 mA = 8.64 Amps for a 1 metre strip.
Therefore a 5V 10A power supply would be able to handle the maximum current (8.6 Amps) demanded by a single 1m NeoPixel strip of 144 LEDs.
 
Arduino Libraries and IDE
Before you start to hook up any components, upload the following sketch to the Arduino microcontroller. I am assuming that you already have the Arduino IDE installed on your computer. If not, the IDE can be downloaded from here.
The FastLED library is useful for simplifying the code for programming the NeoPixels. The latest "FastLED library" can be downloaded from here. I used FastLED library version 3.0.3 in this project.
If you have a different LED strip or your NeoPixels have a different chipset, make sure to change the relevant lines of code to accomodate your hardware. I would suggest you try out a few of the FastLED library examples before using the code below, so that you become more familiar with the library, and will be better equipped to make the necessary changes. If you have a single 144 NeoPixel LED/m strip with the ws2812B chipset, then you will not have to make any modifications below (unless you want to).
/* ================================================================================================================================================== Project: NeoPixel Playground Neopixel chipset: ws2812B (144 LED/m strip) Author: Scott C Created: 12th June 2015 Arduino IDE: 1.6.4 Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html Description: This project will allow you to cycle through and control five LED animation sequences using a potentiometer and an accelerometer Sequence 1: Cylon with Hue Control Control: Potentiometer only Sequence 2: Cylon with Brightness Control Control: Potentiometer only Sequence 3: Comet effect with Hue and direction control Control: Potentiometer and Accelerometer (Y axis only) Sequence 4: FireStarter / Rainbow effect with Hue and Direction control Control: Potentiometer and Accelerometer (Y axis only) Sequence 5: Digital Spirit Level Control: Accelerometer only (Y axis) This project makes use of the FastLED library. Some of the code below was adapted from the FastLED library examples (eg. Cylon routine). The Comet, FireStarter and Digital Spirit Level sequence was designed by ScottC. The FastLED library can be found here: http://fastled.io/ You may need to modify the code below to accomodate your specific LED strip. See the FastLED library site for more details. ===================================================================================================================================================== */
//This project needs the FastLED library - link in the description. #include "FastLED.h"
//The total number of LEDs being used is 144 #define NUM_LEDS 144
// The data pin for the NeoPixel strip is connected to digital Pin 6 on the Arduino #define DATA_PIN 6
//Initialise the LED array, the LED Hue (ledh) array, and the LED Brightness (ledb) array. CRGB leds[NUM_LEDS]; byte ledh[NUM_LEDS]; byte ledb[NUM_LEDS];
//Pin connections constint potPin = A0; // The potentiometer signal pin is connected to Arduino's Analog Pin 0 constint yPin = A4; // Y pin on accelerometer is connected to Arduino's Analog Pin 4 // The accelerometer's X Pin and the Z Pin were not used in this sketch
//Global Variables --------------------------------------------------------------------------------- byte potVal; // potVal: stores the potentiometer signal value byte prevPotVal=0; // prevPotVal: stores the previous potentiometer value int LEDSpeed=1; // LEDSpeed: stores the "speed" of the LED animation sequence int maxLEDSpeed = 50; // maxLEDSpeed: identifies the maximum speed of the LED animation sequence int LEDAccel=0; // LEDAccel: stores the acceleration value of the LED animation sequence (to speed it up or slow it down) int LEDPosition=72; // LEDPosition: identifies the LED within the strip to modify (leading LED). The number will be between 0-143. (Zero to NUM_LEDS-1) int oldPos=0; // oldPos: holds the previous position of the leading LED byte hue = 0; // hue: stores the leading LED's hue value byte intensity = 150; // intensity: the default brightness of the leading LED byte bright = 80; // bright: this variable is used to modify the brightness of the trailing LEDs int animationDelay = 0; // animationDelay: is used in the animation Speed calculation. The greater the animationDelay, the slower the LED sequence. int effect = 0; // effect: is used to differentiate and select one out of the four effects int sparkTest = 0; // sparkTest: variable used in the "sparkle" LED animation sequence boolean constSpeed = false; // constSpeed: toggle between constant and variable speed.
//=================================================================================================================================================== // setup() : Is used to initialise the LED strip //=================================================================================================================================================== voidsetup() { delay(2000); //Delay for two seconds to power the LEDS before starting the data signal on the Arduino FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS); //initialise the LED strip }
//=================================================================================================================================================== // loop() : The Arduino will take readings from the potentiometer and accelerometer to control the LED strip //=================================================================================================================================================== voidloop(){ readPotentiometer(); adjustSpeed(); constrainLEDs();
switch(effect){ case 0: // 1st effect : Cylon with Hue control - using Potentiometer cylonWithHueControl(); break;
case 1: // 2nd effect : Cylon with Brightness control - using Potentiometer cylonWithBrightnessControl(); break;
case 2: // 3rd effect : Comet effect. Hue controlled by potentiometer, direction by accelerometer cometEffect(); break;
case 3: // 4th effect : FireStarter / Rainbow Sparkle effect. Direction controlled by accelerometer, sparkle by potentiometer. fireStarter(); break;
case 4: levelSense(); // 5th effect : LevelSense - uses the accelerometer to create a digital "spirit" level. break; } }
//=================================================================================================================================================== // readPotentiometer() : Take a potentiometer reading. This value will be used to control various LED animations, and to choose the animation sequence to display. //=================================================================================================================================================== void readPotentiometer(){ //Take a reading from the potentiometer and convert the value into a number between 0 and 255 potVal = map(analogRead(potPin), 0, 1023 , 0, 255);
// If the potentiometer reading is equal to zero, then move to the next effect in the list. if(potVal==0){ if(prevPotVal>0){ // This allows us to switch effects only when the potentiometer reading has changed to zero (from a positive number). Multiple zero readings will be ignored. prevPotVal = 0; // Set the prev pot value to zero in order to ignore replicate zero readings. effect++; // Go to the next effect. if(effect>4){ effect=0; // Go back to the first effect after the fifth effect. } } } prevPotVal=potVal; // Keep track of the previous potentiometer reading }
//=================================================================================================================================================== // adjustSpeed() : use the Y axis value of the accelerometer to adjust the speed and the direction of the LED animation sequence //=================================================================================================================================================== void adjustSpeed(){ // Take a reading from the Y Pin of the accelerometer and adjust the value so that // positive numbers move in one direction, and negative numbers move in the opposite diraction. // We use the map function to convert the accelerometer readings, and the constrain function to ensure that it stays within the desired limits // The values of 230 and 640 were determined by trial and error and are specific to my accelerometer. You will need to adjust these numbers to suit your module.
// If the constSpeed variable is "true", then make sure that the speed of the animation is constant by modifying the LEDSpeed and LEDAccel variables. if(constSpeed){ LEDAccel=0; if(LEDSpeed>0){ LEDSpeed = maxLEDSpeed/1.1; // Adjust the LEDSpeed to half the maximum speed in the positive direction } if (LEDSpeed<0){ LEDSpeed = -maxLEDSpeed/1.1; // Adjust the LEDSpeed to half the maximum speed in the negative direction } }
// The Speed of the LED animation sequence can increase (accelerate), decrease (decelerate) or stay the same (constant speed) LEDSpeed = LEDSpeed + LEDAccel;
//The following lines of code are used to control the direction of the LED animation sequence, and limit the speed of that animation. if (LEDSpeed>0){ LEDPosition++; // Illuminate the LED in the Next position if (LEDSpeed>maxLEDSpeed){ LEDSpeed=maxLEDSpeed; // Ensure that the speed does not go beyond the maximum speed in the positive direction } }
if (LEDSpeed<0){ LEDPosition--; // Illuminate the LED in the Prior position if (LEDSpeed<-maxLEDSpeed){ LEDSpeed = -maxLEDSpeed; // Ensure that the speed does not go beyond the maximum speed in the negative direction } } }
//=================================================================================================================================================== // constrainLEDs() : This ensures that the LED animation sequence remains within the boundaries of the various arrays (and the LED strip) // and it also creates a "bouncing" effect at both ends of the LED strip. //=================================================================================================================================================== void constrainLEDs(){ LEDPosition = constrain(LEDPosition, 0, NUM_LEDS-1); // Make sure that the LEDs stay within the boundaries of the LED strip if(LEDPosition == 0 || LEDPosition == NUM_LEDS-1) { LEDSpeed = (LEDSpeed * -0.9); // Reverse the direction of movement when LED gets to end of strip. This creates a bouncing ball effect. } }
//=================================================================================================================================================== // cylonWithHueControl() : This is the 1st LED effect. The cylon colour is controlled by the potentiometer. The speed is constant. //=================================================================================================================================================== void cylonWithHueControl(){ constSpeed = true; // Make the LED animation speed constant showLED(LEDPosition, potVal, 255, intensity); // Illuminate the LED fadeLEDs(8); // Fade LEDs by a value of 8. Higher numbers will create a shorter tail. setDelay(LEDSpeed); // The LEDSpeed is constant, so the delay is constant }
//=================================================================================================================================================== // cylonWithBrightnessControl() : This is the 2nd LED effect. The cylon colour is red (hue=0), and the brightness is controlled by the potentiometer //=================================================================================================================================================== void cylonWithBrightnessControl(){ constSpeed = true; // Make speed constant showLED(LEDPosition, 0, 255, potVal); // Brightness is controlled by potentiometer. fadeLEDs(16); // Fade LEDs by a value of 16 setDelay(LEDSpeed); // The LEDSpeed is constant, so the delay is constant }
//=================================================================================================================================================== // cometEffect() : This is the 3rd LED effect. The random brightness of the trailing LEDs produces an interesting comet-like effect. //=================================================================================================================================================== void cometEffect(){ constSpeed = false; // The speed will be controlled by the slope of the accelerometer (y-Axis) showLED(LEDPosition, potVal, 255, intensity); // Hue will change with potentiometer.
//The following lines create the comet effect bright = random(50, 100); // Randomly select a brightness between 50 and 100 leds[LEDPosition] = CHSV((potVal+40),255, bright); // The trailing LEDs will have a different hue to the leading LED, and will have a random brightness fadeLEDs(8); // This will affect the length of the Trailing LEDs setDelay(LEDSpeed); // The LEDSpeed will be affected by the slope of the Accelerometer's y-Axis }
//=================================================================================================================================================== // fireStarter() : This is the 4th LED effect. It starts off looking like a ball of fire, leaving a trail of little fires. But as you // turn the potentiometer, it becomes more like a shooting star with a rainbow-sparkle trail. //=================================================================================================================================================== void fireStarter(){ constSpeed = false; // The speed will be controlled by the slope of the accelerometer (y-Axis) ledh[LEDPosition] = potVal; // Hue is controlled by potentiometer showLED(LEDPosition, ledh[LEDPosition], 255, intensity);
//The following lines create the fire starter effect bright = random(50, 100); // Randomly select a brightness between 50 and 100 ledb[LEDPosition] = bright; // Assign this random brightness value to the trailing LEDs sparkle(potVal/5); // Call the sparkle routine to create that sparkling effect. The potentiometer controls the difference in hue from LED to LED. fadeLEDs(1); // A low number creates a longer tail setDelay(LEDSpeed); // The LEDSpeed will be affected by the slope of the Accelerometer's y-Axis }
//=================================================================================================================================================== // levelSense() : This is the 5th and final LED effect. The accelerometer is used in conjunction with the LED strip to create a digital "Spirit" Level. // You can use the illuminated LEDs to identify the angle of the LED strip //=================================================================================================================================================== void levelSense(){ constSpeed = true; LEDPosition = constrain(map(analogRead(yPin), 230, 640, 1, NUM_LEDS-1), 0 , NUM_LEDS-1);
//Jitter correction: this will reduce the amount of jitter caused by the accelerometer reading variability if(abs(LEDPosition-oldPos) < 2){ LEDPosition = oldPos; }
//The following lines of code will ensure the colours remain within the red to green range, with green in the middle and red at the ends. hue = map(LEDPosition, 0, NUM_LEDS-1, 0, 200); if (hue>100){ hue = 200 - hue; }
//Illuminate 2 LEDs next to each other showLED(LEDPosition, hue, 255, intensity); showLED(LEDPosition-1, hue, 255, intensity);
//If the position moves, then fade the old LED positions by a factor of 25 (high numbers mean shorter tail) fadeLEDs(25); oldPos = LEDPosition; }
//=================================================================================================================================================== // fadeLEDs(): This function is used to fade the LEDs back to black (OFF) //=================================================================================================================================================== void fadeLEDs(int fadeVal){ for (int i = 0; i<NUM_LEDS; i++){ leds[i].fadeToBlackBy( fadeVal ); } }
//=================================================================================================================================================== // showLED() : is used to illuminate the LEDs //=================================================================================================================================================== void showLED(int pos, byte LEDhue, byte LEDsat, byte LEDbright){ leds[pos] = CHSV(LEDhue,LEDsat,LEDbright); FastLED.show(); }
//=================================================================================================================================================== // setDelay() : is where the speed of the LED animation sequence is controlled. The speed of the animation is controlled by the LEDSpeed variable. // and cannot go faster than the maxLEDSpeed variable. //=================================================================================================================================================== void setDelay(int LSpeed){ animationDelay = maxLEDSpeed - abs(LSpeed); delay(animationDelay); }
//=================================================================================================================================================== // sparkle() : is used by the fireStarter routine to create a sparkling/fire-like effect // Each LED hue and brightness is monitored and modified using arrays (ledh[] and ledb[]) //=================================================================================================================================================== void sparkle(byte hDiff){ for(int i = 0; i < NUM_LEDS; i++) { ledh[i] = ledh[i] + hDiff; // hDiff controls the extent to which the hue changes along the trailing LEDs
// This will prevent "negative" brightness. if(ledb[i]<3){ ledb[i]=0; }
// The probability of "re-igniting" an LED will decrease as you move along the tail // Once the brightness reaches zero, it cannot be re-ignited unless the leading LED passes over it again. if(ledb[i]>0){ ledb[i]=ledb[i]-2; sparkTest = random(0,bright); if(sparkTest>(bright-(ledb[i]/1.1))){ ledb[i] = bright; } else { ledb[i] = ledb[i] / 2; } } leds[i] = CHSV(ledh[i],255,ledb[i]); } }
NeoPixel Strip connection
The NeoPixel strip is rolled up when you first get it. You will notice that there are wires on both sides of the strip. This allows you to chain LED strips together to make longer strips. The more LEDs you have, the more current you will need. Connect your Arduino and power supply to the left side of the strip, with the arrows pointing to the right side of the strip.
Follow the Arrows
The arrows are quite hard to see on this particular LED strip because they are so small, plus they are located right under the thicker part of the NeoPixel weatherproof sheath. I have circled the arrows in RED so that you know where to look:
NeoPixel Strip Wires
There are 4 wires coming from either side of the NeoPixel LED strip:
One red wire, one white wire, and two black wires.
It doesn't matter which Black wire you use to connect to the power supply (or Arduino) GND. Both black wires appear to be going to the same pin on the LED strip anyway. Use the table below to make the necessary NeoPixel Strip connections to the Arduino and power supply.
Large Capacitor
Adafruit also recommend the use of a large capacitor across the + and - terminals of the LED strip to "prevent the initial onrush of current from damaging the pixels". Adafruit recommends a capacitor that is 1000uF, 6.3V or higher. I used a 4700uF 16V Electrolytic Capacitor.
Resistor on Data Pin
Another recommendation from Adafruit is to place a "300 to 500 Ohm resistor" between the Arduino's data pin and the data input on the first NeoPixel to prevent voltage spikes that can damage the first pixel. I used a 330 Ohm resistor.
Powering your Arduino (USB vs Power supply)
You can power your Arduino board via USB cable or via the LED strip power supply. *** Please note: different power supplies will yield different accelerometer readings. I noticed this when changing the Arduino's power source from USB to LED power supply. My final sketch was designed to eliminate the USB/computer connection, hence I have chosen to power the Arduino via the power supply. The fritzing sketch below shows the Arduino being powered by a power supply only.
**WARNING: If you decide to power your Arduino UNO via a USB cable, please make sure to remove (or disconnect) the wire that goes to the the Arduino VIN pin. The GND connections remain unchanged.
Fritzing Sketch - NeoPixel strip connection
Potentiometer connection
The potentiometer will be used to switch between the different LED sequences. When it reads zero, it will switch to the next sequence in the list. It will jump right back to the beginning after the last sequence. The potentiometer is also used to interact with the LEDs (e.g. controlling hue, brightness etc etc). See the fritzing sketch below to add the potentiometer to this project.
Accelerometer connection (Y-axis)
The accelerometer makes the LEDs much more fun and interactive. We will only be using the Y-axis of the accelerometer in this sketch. By tilting the accelerometer from one side to the other, the LEDs react and respond accordingly. The accelerometer is an essential component of the digital spirit level sequence. That's right ! You can use this sketch to create your own spirit level. This digital version can also be used to measure angles !
Have a look below to see how to hook up the accelerometer to the Arduino. The Y-axis is connected to the Arduino analog pin 4. If you wanted to use the X and Z axis, connect them to one of the other available analog pins (eg. A3 and A5).
Let the fun begin !!
Now that you have the Arduino code uploaded to the Arduino, and have made all of the necessary wire/component connections, it is time to turn on the power supply.
Sequence 1: Cylon with Hue control
The LEDs will move from one end of the strip to the other. It should start off as a RED cylon effect. As you turn the potentiometer clockwise, the colour of the LEDs will change and move through the various colours of the rainbow. If the potentiometer reading gets back to zero (fully anti-clockwise), it will move to sequence 2.
Sequence 2: Cylon with brightness control
You will see that the LEDs have turned off. The potentiometer readings correlate with the LED brightness. At the start of this sequence, the potentiometer readings will be zero, therefore the brightness will be zero (LEDs turned off). As you turn the potentiometer clockwise, the readings increase, and so will the brightness of the LEDs.
Sequence 3: Comet effect with Hue and direction control
This is where the real fun begins. You control the hue of the leading LED with the potentiometer, however the LED will move along the LED strip as though it were affected by gravity. As it hits the end of the LED strip, it will bounce for a while and eventually come to a stop. The more you tilt the accelerometer, the greater the acceleration of the leading LED. The trailing LEDs have an interesting randomised glow, which creates the "comet" effect.
Sequence 4: FireStarter / Rainbow effect : Hue and direction control
The initial colours of LEDs in this sequence creates a fire-like animation. As the leading LED moves along the LED strip, it appears to ignite the LEDs in its path, leaving a fire trail behind it. The fire effect is best when you turn the potentiometer clockwise slightly to introduce a small amount of yellow into the mix of colours. As you turn the potentiometer further clockwise, the fire trail turns into a pretty rainbow trail. The accelerometer affects the leading LED in the same way as the previous sequence.
Sequence 5: Digital spirit level
This sequence was my original idea for this project, however I thought it would be nice to share some of the other cool effects I created on my journey of discovery. The idea was to make a digital version of a spirit level. I originally wanted the LEDs to represent a spirit level bubble that would "float" according to the vertical/horizontal position of the LED strip. However, as I played around with this sketch, I discovered that it could potentially be used to measure the angle of the strip relative to the horizon. The angle can be determined by the illuminated LED. If the strip is horizontal, the illuminated LEDs will be close to the middle of the strip, and their colour will be green. If the strip is vertical, the illuminated LEDs will be close to end of the strip, and their colour will be red. The colour is just an additional visual indicator.
Concluding Comments
The NeoPixel Digital RGB LED strip is a lot of fun. The FastLED library makes for easy programming, and allows you to get up and running really quickly. 144 LEDs on a single strip means you have plenty of room for creative algorithms and lighting effects. Add a few sensors, and "pretty" quickly turns into "awesome" !!
Home-made capacitive touch sensors are used to trigger the MP3 drum sounds stored on the Grove Serial MP3 player. I have used a number of tricks to get the most out of this module, and I was quite impressed on how well it did. Over 130 sounds were loaded onto the SDHC card. Most were drum sounds, but I added some farm animal noises to provide an extra element of surprise and entertainment. You can put any sounds you want on the module and play them back quickly. We'll put the Grove Serial MP3 module through it's paces and make it into a neat little BeatBox !!
Key learning objectives
How to make your own beatbox
How to make capacitive drum pad sensors without using resistors
How to speed up Arduino's Analog readings for better performance
/* ================================================================================================= Project: Arduino Beatbox Author: Scott C Created: 9th April 2015 Arduino IDE: 1.6.2 Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html Description: This project uses home made capacitive sensors to trigger over 130 MP3 sounds on the Grove Serial MP3 player. The ADCTouch library is used to eliminate the resistors from the Capacitive sensing circuit. The code used for capacitive sensing was adapted from the ADCTouch library example sketches. You can find the ADCTouch library and relevant example code here: http://playground.arduino.cc/Code/ADCTouch "Advanced Arduino ADC" is used to improve the analogRead() speed, and enhance the drum pad or capacitive sensor response time. The Advanced Arduino ADC code was adapted from this site: http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/ =================================================================================================== */ #include <ADCTouch.h> #include <SoftwareSerial.h>
//Global variables //=================================================================================================== int potPin = A4; //Grove Sliding potentiometer is connected to Analog Pin 4 int potVal = 0; byte mp3Vol = 0; //Variable used to control the volume of the MP3 player byte oldVol = 0;
int buttonPin = 5; //Grove Button is connected to Digital Pin 5 int buttonStatus = 0;
byte SongNum[4] = {0x01,0x02,0x03,0x04}; //The first 4 songs will be assigned to the drum pads upon initialisation byte numOfSongs = 130; //Total number of MP3 songs/sounds loaded onto the SDHC card
long randNumber; //Variable used to hold the random number - used to randomise the sounds.
int ledState[4]; //Used to keep track of the status of all LEDs (on or off) int counter = 0;
SoftwareSerial mp3(3, 4); // The Grove MP3 Player is connected to Arduino digital Pin 3 and 4 (Serial communication)
int ref0, ref1, ref2, ref3; //reference values to remove offset int threshold = 100;
//Setup() //=================================================================================================== voidsetup(){ //Initialise the Grove MP3 Module delay(2500); //Allow the MP3 module to power up mp3.begin(9600); //Begin Serial communication with the MP3 module setPlayMode(0x00); //0x00 = Single song - played once ie. not repeated. (default)
//Define the Grove Button as an INPUT pinMode(buttonPin, INPUT);
//Define the 4 LED Pins as OUTPUTs pinMode(8, OUTPUT); //Green LED pinMode(9, OUTPUT); //Blue LED pinMode(10, OUTPUT); //Red LED pinMode(11, OUTPUT); //Yellow LED
//Make sure each LED is OFF, and store the state of the LED into a variable. for(int i=8;i<12;i++){ digitalWrite(i, LOW); ledState[i-8]=0; }
//Double our clock speed from 125 kHz to 250 kHz ADCSRA &= ~PS_128; // set up the ADC ADCSRA |= PS_64; // set our own prescaler to 64
//Create reference values to account for the capacitance of each pad. ref0 = ADCTouch.read(A0, 500); ref1 = ADCTouch.read(A1, 500); //Take 500 readings ref2 = ADCTouch.read(A2, 500); ref3 = ADCTouch.read(A3, 500);
//This helps to randomise the drum pads. randomSeed(analogRead(0)); }
//Take a reading from the Grove Sliding Potentiometer, and set volume accordingly potVal = analogRead(potPin); mp3Vol = map(potVal, 0, 1023, 0,31); // Convert the potentometer reading (0 - 1023) to fit within the MP3 player's Volume range (0 - 31) if((mp3Vol>(oldVol+1))|(mp3Vol<(oldVol-1))){ // Only make a change to the Volume on the Grove MP3 player when the potentiometer value changes oldVol = mp3Vol; setVolume(mp3Vol); delay(10); // This delay is necessary with Serial communication to MP3 player }
//Take a reading from the Pin attached to the Grove Button. If pressed, randomise the MP3 songs/sounds for each drum pad, and make the LEDs blink randomly. buttonStatus = digitalRead(buttonPin); if(buttonStatus==HIGH){ SongNum[0]=randomSongChooser(1, 30); SongNum[1]=randomSongChooser(31, 60); SongNum[2]=randomSongChooser(61, 86); SongNum[3]=randomSongChooser(87, (int)numOfSongs); randomLEDBlink(); }
//Get the capacitive readings from each drum pad: 50 readings are taken from each pad. (default is 100) int value0 = ADCTouch.read(A0,50); // Green drum pad int value1 = ADCTouch.read(A1,50); // Blue drum pad int value2 = ADCTouch.read(A2,50); // Red drum pad int value3 = ADCTouch.read(A3,50); // Yellow drum pad
//Remove the offset to account for the baseline capacitance of each pad. value0 -= ref0; value1 -= ref1; value2 -= ref2; value3 -= ref3;
//If any of the values exceed the designated threshold, then play the song/sound associated with that drum pad. //The associated LED will stay on for the whole time the drum pad is pressed, providing the value remains above the threshold. //The LED will turn off when the pad is not being touched or pressed. if(value0>threshold){ digitalWrite(8, HIGH); playSong(00,SongNum[0]); }else{ digitalWrite(8,LOW); }
// writeToMP3: // a generic function that simplifies each of the methods used to control the Grove MP3 Player //=================================================================================================== void writeToMP3(byte MsgLEN, byte A, byte B, byte C, byte D, byte E, byte F){ byte codeMsg[] = {MsgLEN, A,B,C,D,E,F}; mp3.write(0x7E); //Start Code for every command = 0x7E for(byte i = 0; i<MsgLEN+1; i++){ mp3.write(codeMsg[i]); //Send the rest of the command to the GROVE MP3 player } }
//setPlayMode: defines how each song is to be played //=================================================================================================== void setPlayMode(byte playMode){ /* playMode options: 0x00 = Single song - played only once ie. not repeated. (default) 0x01 = Single song - cycled ie. repeats over and over. 0x02 = All songs - cycled 0x03 = play songs randomly */ writeToMP3(0x03, 0xA9, playMode, 0x7E, 0x00, 0x00, 0x00); }
//playSong: tells the Grove MP3 player to play the song/sound, and also which song/sound to play //=================================================================================================== void playSong(byte songHbyte, byte songLbyte){ writeToMP3(0x04, 0xA0, songHbyte, songLbyte, 0x7E, 0x00, 0x00); delay(100); }
//setVolume: changes the Grove MP3 player's volume to the designated level (0 to 31) //=================================================================================================== void setVolume(byte Volume){ byte tempVol = constrain(Volume, 0, 31); //Volume range = 00 (muted) to 31 (max volume) writeToMP3(0x03, 0xA7, tempVol, 0x7E, 0x00, 0x00, 0x00); }
//randomSongChooser: chooses a random song to play. The range of songs to choose from //is limited and defined by the startSong and endSong parameters. //=================================================================================================== byte randomSongChooser(int startSong, int endSong){ randNumber = random(startSong, endSong); return((byte) randNumber); }
//randomLEDBlink: makes each LED blink randomly. The LEDs are attached to digital pins 8 to 12. //=================================================================================================== void randomLEDBlink(){ counter=8; for(int i=0; i<40; i++){ int x = constrain((int)random(8,12),8,12); toggleLED(x); delay(random(50,100-i)); }
//toggleLED: is used by the randomLEDBlink method to turn each LED on and off (randomly). //=================================================================================================== void toggleLED(int pinNum){ ledState[pinNum-8]= !ledState[pinNum-8]; digitalWrite(pinNum, ledState[pinNum-8]); }
Arduino Code Discussion
You can see from the Arduino code above, that it uses the ADCTouch library. This library was chosen over the Capacitive Sensing Library to eliminate the need for a high value resistor which are commonly found in Capacitive Sensing projects).
The readings are increased by modifying the Arduino's ADC clock speed from 125kHz to 250 kHz. I did notice an overall better response time with this modification. However, the Grove Serial MP3 player is limited by it's inability to play more than one song or sound at a time. This means that if you hit another drum pad while the current sound is playing, it will stop playing the current sound, and then play the selected sound. The speed at which it can perform this task was quite impressive. In fact it was much better than I thought it would be. But if you are looking for polyphonic playability, you will be dissapointed.
This Serial MP3 module makes use of a high quality MP3 audio chip known as the "WT5001". Therefore, you should be able to get some additional features and functionality from this document. Plus you may find some extra useful info from the Seeedstudio wiki. I have re-used some code from the Arduino Boombox tutorial... you will find extra Grove Serial MP3 functions on that page.
I will warn you... the Grove Serial MP3 player can play WAV files, however for some reason it would not play many of the sound files in this format. Once the sounds were converted to the MP3 format, I did not look back. So if you decide to take on this project, make sure your sound files are in MP3 format, you'll have a much better outcome.
I decided to introduce a random sound selection for each drum pad to extend the novelty of this instrument, which meant that I had to come up with a fancy way to illuminate the LEDs. I demonstrated some of my other LED sequences on my instagram account. I sometimes use instagram to show my work in progress.
Have a look at the video below to see this project in action, and putting the Grove Serial MP3 player through it's paces.
The Video
First there was the Arduino Boombox, and now we have the Arduino Beatbox..... who knows what will come next !
Whenever I create a new project, I like to improve my Arduino knowledge. Sometimes it takes me into some rather complicated topics. There is a lot I do not know about Arduino, but I am enjoying the journey. I hope you are too !! Please Google plus one this post if it helped you in any way. These tutorials are free, which means I survive on feedback and plus ones... all you have to do is just scroll a little bit more and click that button :)
If you like this page, please do me a favour and show your appreciation :