Learn Arduino with Olympia Circuits
Learn Arduino
  • Home
    • Get Started
    • How to Use This Site
  • Electronics
    • The Basics
    • Electricity Flows like Water
    • Electronic Components
    • The Arno Board
  • Programming
    • The Basics
    • setup and loop Blocks
    • Variables and Arrays
    • Connecting with the Pins
    • Flow Control >
      • if Statement
      • Loops
      • Delays
    • Functions
    • Serial Communication
    • USB
    • Some Thoughts
  • Projects
    • Projects 1 >
      • 1.01: Blink
      • 1.02 Blink x2
      • 1.03 Blink Faster
      • 1.04 LED Chase!
      • 1.05 Wait To Blink
      • 1.06 Blink a Little Faster Now
      • 1.07 LED Fade
      • 1.08 RGB Blink
      • 1.09 Change RGB Color with SW1
      • 1.10 Fade RGB Colors
      • 1.11 Reaction Time Game
    • Projects 2 >
      • 2.01 Hello World
      • 2.02 Talk Back
      • 2.03 ASCII Values
      • 2.04 Ski Game
      • 2.05 Demonstration of the String Object
    • Projects 3 >
      • 3.01 Read the Potentiometer
      • 3.02 ASCIIbet Soup
      • 3.03 Potentiometer sets LED Brightness
      • 3.04 Potentiometer Sets Blink Rate
      • 3.05 LED Chase, Part II
    • Projects 4 >
      • 4.01 Bringing the Piezo to Life
      • 4.02 Controlling the Piezo with a Function
      • 4.03 Piezo C Major
      • 4.04 Piezo Greensleaves
      • 4.05 Piezo Metronome
      • 4.06 Piezo as an Input
      • 4.07 Piezo as an Input 2
      • 4.08 Metronome II
      • 4.09 Piezo Playback
      • 4.10 Piezo Fireworks
      • 4.11 Piezo Mosquito
    • Projects 5 >
      • 5.01 The Phototransistor
      • 5.02 Light and Sound
      • 5.03 Light and Sound II
    • Projects 6 >
      • 6.01 EEPROM
      • 6.02 I2C Address Scan
      • 6.03 Read the I2C Temperature Sensor
      • 6.04 High Temperature Alarm
    • Projects 7 >
      • 7.01 Arno Phone Home
      • 7.02 Keyboard Alphabet
      • 7.03 Move Mouse
      • 7.04 Draw Squares
    • Special Projects >
      • Bike Light Demo
  • References
    • Arno Pin Key
    • Arno Schematic
    • Project Index

bike light demo

The bike light project is a great way for people to learn some basic electronic skills, become acquainted with Arduino, and create something impressive in the process.  Check out the YouTube video below to see an example. 

If you built one of our bike lights and you want to dive deeper into the programming side, upload the program below using the USB cable.  To upload the program, you'll need to set up your computer with Codebender which hosts the it using their excellent web interface. You can find setup information here. 

If you want to learn more about Arduino, then check out our Arno kit.  You can find it here.  With the Arno you can learn more about the hardware and software used in the Arduino platform.  We have a bunch of information and projects to get you started. Begin your journey here.  

The bike lights consists of a microcontroller (we like the Pro Micros that run the Atmega 32U4), a power source, and strip of programmable LEDs. The LEDs provide the real magic in this project. They have microchips embedded in them that allow them to become 'aware' of one another so that each LED knows where it is within the strip. This allows us to control them independently. The color and brightness of each LED is set by using three 8-bit values so that control the amount of red, blue, and green light that they emit.

This sketch runs through 18 different example settings. If you run it as-is, each setting will run for 10 seconds. If you find one you like, you can make your bike light run only that sketch by setting the variable doAll to false and ledMode to the setting number 1 through 18.


Select Sketch

/*************************************************************************************
Olympia Circuits Bike Light Demo
learn.olympiacircuits.com
Contact: peter@olympiacircuits.com
The demo includes 18 different LED settings that each run for 10 seconds
To cycle through all of the demos, set the doAll below to true.
You can see which of the settings is running by watching the serial monitor.
To stay with one of the settings, set doAll = false and ledMode to the setting number (e.g.,1, 5 , or 7)
This code was adapted from teldredge, www.funkboxing.com, teldredge1979@gmail.com
**********************************************************************************
*/
//Which Arduino pin is connected to the data line?
//THIS SETS THE LED MODE
//********************************************
boolean doAll = true;
int ledMode = 1;
//********************************************
//variables to keep track of LED patterns
int BOTTOM_INDEX = 0;
int TOP_INDEX = int(NUM_LEDS/2);
int EVENODD = NUM_LEDS%2;
int idex = 0; //-LED INDEX (0 to NUM_LEDS-1
int idx_offset = 0; //-OFFSET INDEX (BOTTOM LED TO ZERO WHEN LOOP IS TURNED/DOESNT REALLY WORK)
int ihue = 0; //-HUE (0-360)
int ihue2 = 0;
int ibright = 0; //-BRIGHTNESS (0-255)
int isat = 0; //-SATURATION (0-255)
int bouncedirection = 0; //-SWITCH FOR COLOR BOUNCE (0-1)
float tcount = 0.0; //-INC VAR FOR SIN LOOPS
int lcount = 0; //-ANOTHER COUNTING VAR
long lastTime = 0;
int istep = 1;
long now = 0; //keep track of time

//-YOU MAY HAVE TO PLAY WITH THE R,G,B ORDER OF THIS TO SUIT YOUR STRIP
struct CRGB {
unsigned char g;
unsigned char r;
unsigned char b;
};
//struct CRGB { unsigned char r; unsigned char b; unsigned char g; };
struct CRGB *leds;


//------------------SETUP------------------
void setup()
{
setupLEDS();
Serial.begin(9600);
}
// -----------end setup-------------------



//------------------MAIN LOOP------------------
void loop() {
if(doAll && millis() > now + 10000L){
ledMode++;
if(ledMode > 18) ledMode = 1;
now = millis();
Serial.println(ledMode);
}
switch(ledMode){
case 1:
rainbow_loop(10, 100);
break;
case 2:
random_burst(20);
break;
case 3:
rainbow_fade(50);
break;
case 4:
sin_col_wave(0,360,10);
break;
case 5:
sin_col_wave(300,360,10);
break;
case 6:
rainbow_bright_wave(0,360,2);
break;
case 7:
rainbow_vertical(1,10);
break;
case 8:
fade_vertical(270,5);
break;
case 9:
flame();
break;
case 10:
quad_bright_curve(133,10);
break;
case 11:
color_loop_vardelay();
break;
case 12:
white_temps();
break;
case 13:
pulse_one_color_all(240,3);
break;
case 14:
pulse_one_color_all(90,3);
break;
case 15:
flicker(330,10);
break;
case 16:
color_bounceFADE(20);
break;
case 17:
police_lightsONE(50);
break;
case 18:
police_lightsALL(50);
break;
}
}
//end of main loop!


//------------------------------------- UTILITY FXNS --------------------------------------
//initial setup
void setupLEDS(){
FastSPI_LED.setLeds(NUM_LEDS);
FastSPI_LED.setChipset(CFastSPI_LED::SPI_TM1809);
FastSPI_LED.setPin(PIN);
FastSPI_LED.setDataRate(7); //-IF LEDS FLICKER, PLAY WITH THIS (0-7)
FastSPI_LED.init();
FastSPI_LED.start();
leds = (struct CRGB*)FastSPI_LED.getRGBData();
one_color_all(0,0,0); //-BLANK STRIP
FastSPI_LED.show();
}

//-SET THE COLOR OF A SINGLE RGB LED
void set_color_led(int adex, int cred, int cgrn, int cblu) {
int bdex;

if (idx_offset > 0) { //-APPLY INDEX OFFSET
bdex = (adex + idx_offset) % NUM_LEDS;
}
else {
bdex = adex;
}

leds[bdex].r = cred;
leds[bdex].g = cgrn;
leds[bdex].b = cblu;
}


//-FIND INDEX OF HORIZONAL OPPOSITE LED
int horizontal_index(int i) {
//-ONLY WORKS WITH INDEX < TOPINDEX
if (i == BOTTOM_INDEX) {
return BOTTOM_INDEX;
}
if (i == TOP_INDEX && EVENODD == 1) {
return TOP_INDEX + 1;
}
if (i == TOP_INDEX && EVENODD == 0) {
return TOP_INDEX;
}
return NUM_LEDS - i;
}


//-FIND INDEX OF ANTIPODAL OPPOSITE LED
int antipodal_index(int i) {
//int N2 = int(NUM_LEDS/2);
int iN = i + TOP_INDEX;
if (i >= TOP_INDEX) {
iN = ( i + TOP_INDEX ) % NUM_LEDS;
}
return iN;
}


//-FIND ADJACENT INDEX CLOCKWISE
int adjacent_cw(int i) {
int r;
if (i < NUM_LEDS - 1) {
r = i + 1;
}
else {
r = 0;
}
return r;
}


//-FIND ADJACENT INDEX COUNTER-CLOCKWISE
int adjacent_ccw(int i) {
int r;
if (i > 0) {
r = i - 1;
}
else {
r = NUM_LEDS - 1;
}
return r;
}


//-CONVERT HSV VALUE TO RGB
void HSVtoRGB(int hue, int sat, int val, int colors[3]) {
// hue: 0-359, sat: 0-255, val (lightness): 0-255
int r, g, b, base;

if (sat == 0) { // Achromatic color (gray).
colors[0]=val;
colors[1]=val;
colors[2]=val;
}
else {
base = ((255 - sat) * val)>>8;
switch(hue/60) {
case 0:
r = val;
g = (((val-base)*hue)/60)+base;
b = base;
break;
case 1:
r = (((val-base)*(60-(hue%60)))/60)+base;
g = val;
b = base;
break;
case 2:
r = base;
g = val;
b = (((val-base)*(hue%60))/60)+base;
break;
case 3:
r = base;
g = (((val-base)*(60-(hue%60)))/60)+base;
b = val;
break;
case 4:
r = (((val-base)*(hue%60))/60)+base;
g = base;
b = val;
break;
case 5:
r = val;
g = base;
b = (((val-base)*(60-(hue%60)))/60)+base;
break;
}
colors[0]=r;
colors[1]=g;
colors[2]=b;
}
}


//------------------------LED EFFECT FUNCTIONS------------------------

void one_color_all(int cred, int cgrn, int cblu) { //-SET ALL LEDS TO ONE COLOR
for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, cred, cgrn, cblu);
FastSPI_LED.show();
delay(1);
}
}

void colorDial(int col1) { //-SET ALL LEDS TO ONE COLOR
int icolor[3];
HSVtoRGB(col1, 255, 200, icolor);
for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, icolor[0], icolor[1], icolor[2]);
FastSPI_LED.show();
delay(1);
}
}
void one_color_allNOSHOW(int cred, int cgrn, int cblu) { //-SET ALL LEDS TO ONE COLOR
for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, cred, cgrn, cblu);
//FastSPI_LED.show();
//delay(1);
}
}


void rainbow_fade(int idelay) { //-FADE ALL LEDS THROUGH HSV RAINBOW
ihue++;
ibright--;
if(ibright < 0) ibright = 100;
if (ihue >= 359) {
ihue = 0;
}
int thisColor[3];
HSVtoRGB(ihue, 255,ibright , thisColor);
for(int idex = 0 ; idex < NUM_LEDS; idex++ ) {
set_color_led(idex,thisColor[0],thisColor[1],thisColor[2]);
}
FastSPI_LED.show();
delay(idelay);
}


void rainbow_loop(int istep, int idelay) { //-LOOP HSV RAINBOW
idex++;
ihue = ihue + istep;
int icolor[3];

if (idex >= NUM_LEDS) {
idex = 0;
}
if (ihue >= 359) {
ihue = 0;
}

HSVtoRGB(ihue, 255, 100, icolor);
set_color_led(idex, icolor[0], icolor[1], icolor[2]);
FastSPI_LED.show();
delay(idelay);
}



void random_burst(int idelay) { //-RANDOM INDEX/COLOR
int icolor[3];

idex = random(0,NUM_LEDS);
ihue = random(0,359);

HSVtoRGB(ihue, 255, 100, icolor);
set_color_led(idex, icolor[0], icolor[1], icolor[2]);
FastSPI_LED.show();
delay(idelay);
}


void color_bounce(int idelay) { //-BOUNCE COLOR (SINGLE LED)
if (bouncedirection == 0) {
idex = idex + 1;
if (idex == NUM_LEDS) {
bouncedirection = 1;
idex = idex - 1;
}
}
if (bouncedirection == 1) {
idex = idex - 1;
if (idex == 0){
bouncedirection = 0;
}
}
for(int i = 0; i < NUM_LEDS; i++) {
if(i == idex){
set_color_led(i,0,120,240);
}
else{
set_color_led(i,0,230,359);
}
}
FastSPI_LED.show();
delay(idelay);
}


void police_lightsONE(int idelay) { //-POLICE LIGHTS (TWO COLOR SINGLE LED)
idex++;
if (idex >= NUM_LEDS) {
idex = 0;
}
int idexR = idex;
int idexB = antipodal_index(idexR);
for(int i = 0; i < NUM_LEDS; i++ ) {
if (i == idexR) {
set_color_led(i, 255, 0, 0);
}
else if (i == idexB) {
set_color_led(i, 0, 0, 255);
}
else {
set_color_led(i, 0, 0, 0);
}
}
FastSPI_LED.show();
delay(idelay);
}


void police_lightsALL(int idelay) { //-POLICE LIGHTS (TWO COLOR SOLID)
idex++;
if (idex >= NUM_LEDS) {
idex = 0;
}
int idexR = idex;
int idexB = antipodal_index(idexR);
set_color_led(idexR, 100, 0, 0);
set_color_led(idexB, 0, 0, 100);
FastSPI_LED.show();
delay(idelay);
}


void color_bounceFADE(int idelay) { //-BOUNCE COLOR (SIMPLE MULTI-LED FADE)
if (bouncedirection == 0) {
idex = idex + 1;
if (idex == NUM_LEDS) {
bouncedirection = 1;
idex = idex - 1;
}
}
if (bouncedirection == 1) {
idex = idex - 1;
if (idex == 0) {
bouncedirection = 0;
}
}
int iL1 = adjacent_cw(idex);
int iL2 = adjacent_cw(iL1);
int iL3 = adjacent_cw(iL2);
int iR1 = adjacent_ccw(idex);
int iR2 = adjacent_ccw(iR1);
int iR3 = adjacent_ccw(iR2);

for(int i = 0; i < NUM_LEDS; i++ ) {
if (i == idex) {
set_color_led(i, 255, 0, 0);
}
else if (i == iL1) {
set_color_led(i, 100, 0, 0);
}
else if (i == iL2) {
set_color_led(i, 50, 0, 0);
}
else if (i == iL3) {
set_color_led(i, 10, 0, 0);
}
else if (i == iR1) {
set_color_led(i, 100, 0, 0);
}
else if (i == iR2) {
set_color_led(i, 50, 0, 0);
}
else if (i == iR3) {
set_color_led(i, 10, 0, 0);
}
else {
set_color_led(i, 0, 0, 0);
}
}

FastSPI_LED.show();
delay(idelay);
}


void flicker(int thishue, int thissat) {
int random_bright = random(0,255);
int random_delay = random(10,100);
int random_bool = random(0,random_bright);
int thisColor[3];

if (random_bool < 10) {
HSVtoRGB(thishue, thissat, random_bright, thisColor);

for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, thisColor[0], thisColor[1], thisColor[2]);
}

FastSPI_LED.show();
delay(random_delay);
}
}


void pulse_one_color_all(int ahue, int idelay) { //-PULSE BRIGHTNESS ON ALL LEDS TO ONE COLOR

if (bouncedirection == 0) {
ibright++;
if (ibright >= 255) {
bouncedirection = 1;
}
}
if (bouncedirection == 1) {
ibright = ibright - 1;
if (ibright <= 1) {
bouncedirection = 0;
}
}

int acolor[3];
HSVtoRGB(ahue, 255, ibright, acolor);

for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, acolor[0], acolor[1], acolor[2]);
}
FastSPI_LED.show();
delay(idelay);
}


void pulse_one_color_all_rev(int ahue, int idelay) { //-PULSE SATURATION ON ALL LEDS TO ONE COLOR

if (bouncedirection == 0) {
isat++;
if (isat >= 255) {
bouncedirection = 1;
}
}
if (bouncedirection == 1) {
isat = isat - 1;
if (isat <= 1) {
bouncedirection = 0;
}
}

int acolor[3];
HSVtoRGB(ahue, isat, 255, acolor);

for(int i = 0 ; i < NUM_LEDS; i++ ) {
set_color_led(i, acolor[0], acolor[1], acolor[2]);
}
FastSPI_LED.show();
delay(idelay);
}


void white_temps() {
int N9 = int(NUM_LEDS/9);
for (int i = 0; i < NUM_LEDS; i++ ) {
if (i >= 0 && i < N9) {
leds[i].r = 255;
leds[i].g = 147;
leds[i].b = 41;
} //-CANDLE - 1900
if (i >= N9 && i < N9*2) {
leds[i].r = 255;
leds[i].g = 197;
leds[i].b = 143;
} //-40W TUNG - 2600
if (i >= N9*2 && i < N9*3) {
leds[i].r = 255;
leds[i].g = 214;
leds[i].b = 170;
} //-100W TUNG - 2850
if (i >= N9*3 && i < N9*4) {
leds[i].r = 255;
leds[i].g = 241;
leds[i].b = 224;
} //-HALOGEN - 3200
if (i >= N9*4 && i < N9*5) {
leds[i].r = 255;
leds[i].g = 250;
leds[i].b = 244;
} //-CARBON ARC - 5200
if (i >= N9*5 && i < N9*6) {
leds[i].r = 255;
leds[i].g = 255;
leds[i].b = 251;
} //-HIGH NOON SUN - 5400
if (i >= N9*6 && i < N9*7) {
leds[i].r = 255;
leds[i].g = 255;
leds[i].b = 255;
} //-DIRECT SUN - 6000
if (i >= N9*7 && i < N9*8) {
leds[i].r = 201;
leds[i].g = 226;
leds[i].b = 255;
} //-OVERCAST SKY - 7000
if (i >= N9*8 && i < NUM_LEDS) {
leds[i].r = 64;
leds[i].g = 156;
leds[i].b = 255;
} //-CLEAR BLUE SKY - 20000
}
FastSPI_LED.show();
delay(100);
}


void color_loop_vardelay() { //-COLOR LOOP (SINGLE LED) w/ VARIABLE DELAY
idex++;
if (idex > NUM_LEDS) {
idex = 0;
}

int acolor[3];
HSVtoRGB(0, 255, 255, acolor);

int di = abs(TOP_INDEX - idex); //-DISTANCE TO CENTER
int t = constrain((10/di)*10, 10, 500); //-DELAY INCREASE AS INDEX APPROACHES CENTER (WITHIN LIMITS)

for(int i = 0; i < NUM_LEDS; i++ ) {
if (i == idex) {
leds[i].r = acolor[0];
leds[i].g = acolor[1];
leds[i].b = acolor[2];
}
else {
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 0;
}
}

FastSPI_LED.show();
delay(t);
}




void quad_bright_curve(int ahue, int idelay) { //-QUADRATIC BRIGHTNESS CURVER
int acolor[3];
int ax;

for(int x = 0; x < NUM_LEDS; x++ ) {
if (x <= TOP_INDEX) {
ax = x;
}
else if (x > TOP_INDEX) {
ax = NUM_LEDS-x;
}

int a = 1;
int b = 1;
int c = 0;

int iquad = -(ax*ax*a)+(ax*b)+c; //-ax2+bx+c
int hquad = -(TOP_INDEX*TOP_INDEX*a)+(TOP_INDEX*b)+c; //HIGHEST BRIGHTNESS

ibright = int((float(iquad)/float(hquad))*255);

HSVtoRGB(ahue, 255, ibright, acolor);

leds[x].r = acolor[0];
leds[x].g = acolor[1];
leds[x].b = acolor[2];


}
FastSPI_LED.show();
delay(idelay);
}


void flame() {
int acolor[3];
int idelay = random(5,20);

float hmin = 0.1;
float hmax = 45.0;
float hdif = hmax-hmin;
int randtemp = random(0,3);
float hinc = (hdif/float(TOP_INDEX))+randtemp;

int ahue = hmin;
for(int i = 0; i < TOP_INDEX; i++ ) {

ahue = ahue + hinc;

HSVtoRGB(ahue, 255, 255, acolor);

leds[i].r = acolor[0];
leds[i].g = acolor[1];
leds[i].b = acolor[2];
int ih = horizontal_index(i);
leds[ih].r = acolor[0];
leds[ih].g = acolor[1];
leds[ih].b = acolor[2];

leds[TOP_INDEX].r = 255;
leds[TOP_INDEX].g = 255;
leds[TOP_INDEX].b = 255;

FastSPI_LED.show();
delay(idelay);
}
}



void sin_bright_wave(int ahue, int idelay) {
int acolor[3];

for(int i = 0; i < NUM_LEDS; i++ ) {
tcount = tcount + .1;
if (tcount > 3.14) {
tcount = 0.0;
}
ibright = int(sin(tcount)*255);

HSVtoRGB(ahue, 255, ibright, acolor);

leds[i].r = acolor[0];
leds[i].g = acolor[1];
leds[i].b = acolor[2];

FastSPI_LED.show();
delay(idelay);
}
}

///PJG functions
void sin_col_wave(int ahue, int bhue, int idelay) {
int acolor[3];
int range1 = abs(ahue - bhue)/2;
int mid1 = (ahue + bhue)/2;
float step1 = 6.28f/float(NUM_LEDS*2);
tcount = tcount + (step1/10);
if(tcount > 6.28) tcount = 0;
float newcount = tcount;
for(int i = 0; i < NUM_LEDS; i++ ) {
newcount = newcount + step1;
int col1 = mid1 + int(sin(newcount)* range1); //sine fade between colors
HSVtoRGB(col1, 255, 255, acolor);
leds[i].r = acolor[0];
leds[i].g = acolor[1];
leds[i].b = acolor[2];
}
FastSPI_LED.show();
delay(idelay);

}

void rainbow_bright_wave(int ahue, int bhue, int idelay) {
int acolor[3];
int range1 = abs(ahue - bhue)/2;
int mid1 = (ahue + bhue)/2;
float step1 = 6.28f/float(NUM_LEDS);
tcount = tcount + (step1/5);
if(tcount > 6.28) tcount = 0;
float newcount = tcount;
float newcount2 = 0;
for(int i = 0; i < NUM_LEDS; i++ ) {
newcount = newcount + step1;
newcount2 = newcount2 + step1;
int col1 = mid1 + int(sin(newcount2)* range1); //sine fade between colors
int bright1 = 155 + int(sin(newcount)*100.0f); //set brightness
HSVtoRGB(col1, 255, bright1, acolor);
leds[i].r = acolor[0];
leds[i].g = acolor[1];
leds[i].b = acolor[2];

FastSPI_LED.show();
delay(idelay);
}
}



void fade_vertical(int ahue, int idelay) { //-FADE UP THE LOOP
idex++;
if (idex > TOP_INDEX) {
idex = 0;
}
int idexA = idex;
int idexB = horizontal_index(idexA);

ibright = ibright + 10;
if (ibright > 255) {
ibright = 0;
}
int acolor[3];
HSVtoRGB(ahue, 255, ibright, acolor);

set_color_led(idexA, acolor[0], acolor[1], acolor[2]);
set_color_led(idexB, acolor[0], acolor[1], acolor[2]);

FastSPI_LED.show();
delay(idelay);
}


void rainbow_vertical(int istep, int idelay) { //-RAINBOW UP THE LOOP
idex++;
if (idex > TOP_INDEX) {
idex = 0;
}
ihue = ihue + istep;
if (ihue > 359) {
ihue = 0;
}
int idexA = idex;
int idexB = horizontal_index(idexA);

int acolor[3];
HSVtoRGB(ihue, 255, 100, acolor);

set_color_led(idexA, acolor[0], acolor[1], acolor[2]);
set_color_led(idexB, acolor[0], acolor[1], acolor[2]);

FastSPI_LED.show();
delay(idelay);
}








Back to Special Projects

Copyright Olympia Circuits LLC 2014. All Rights Reserved.