Instructables

Arduino multi-mode lamp with soft touch switch

Featured
Picture of Arduino multi-mode lamp with soft touch switch
090424056a.jpg
090424058a.jpg
090424053a.jpg
3472189132_a6f34593cf.jpg
In this Arduino-based project, we will build a lamp with multiple light displays: color sequencer, dimming light, color chaser, firelight - all selected by a touch bar on the circuit board.

All the functions are done in software, including the touch sensor, which is a unique feature.

Step 1: What is needed?

We will be going the minimalist way for this project, filling the board with just a microchip, the LEDs, a handful of resistors and some capacitors, all for under $10, along with the necessary connecting hardware.

The circuit will be using 3 RGB LEDs. These are common-anode Piranha type available here and contains three LEDs within its body. Each color will need a single dropping resistor (220-ohm for green and blue and 330-ohm for Red). We can also add a small LED with a 1k-ohm as an indicator.

The IC we are using is an ATMega-328 microchip, available for about $5 here You will also need a 16Mhz resonator for about 35c, also available at the same site.

The development and testing of the software is done using the Arduino system, so a suitable 'host' is necessary. I've used an Arduino 'Nano', a Boarduino and a RBBB board and they all work fine.

Step 2: Getting started

It is a very good idea to put the microchip in a socket. Here, I've used 2 x 16-pin sockets end-to-end, because that is what I have available... The ATMel chip only has 28-pins so we'll have a few empty sockets on the end.

In this picture, the LEDs are along the bottom, with a resistor for each of the primary colors.

The little pushbutton on the left is for the Reset, although this is not strictly needed. The yellow blob in the center is the resonator.

After I've done the preliminary wiring, the circuit (and programming) is tested through jumpers connected to the 'host', an RBBB (Really Bare Bones Board), also from Modern Devices. This lets me make sure the wiring is correct before we commit the Microchip.

The process is quite straightforward - run / test with the host, then simply transplant the IC over to the circuit board.

Step 3: A quick test...

Picture of A quick test...
3471378723_c9169a9222.jpg
If you're really impatient, you can actually run the program with just the IC, and the resonator! Just add a 5v source and Presto! There is light!

Step 4: The circuit

The picture clearly shows the point-to-point wiring used.

A major effort-saver is the use of Teflon wire, which does not melt even when routed close to soldered parts. Teflon wire is also available silver-plated which allows me to use thinner wires (#28) and still handle the current. These wires can be found here on eBay.

The 6-pin header in the back is so I can connect a USB-serial port ("USB BUB") and make programming changes directly to the chip.

The wiring at the front is used as the touch sensor. The program measures the voltage drop between the wires and can tell if it is touched. The duration is measured and we can tell if it is a tap, a press or a hold, and the program uses it to control the light patterns.

Step 5: The 'Sketch', or program.

Picture of The 'Sketch', or program.
090424060a.jpg
Currently the lamp cycles through 4 different modes: Sequencing through all 4000 color combinations; different levels of white light; a color chaser where each LED morphs into all possible shades; and a firelight simulator (seen below), where the program tries to emulate the flickering effects of a fireplace.

It's only taking up 5k-bytes of the 32k-byte program space, so there is room for a lot more features.

I'm constantly adding things to it, so send email to: qs (at) quantsuff.com and I'll send you the latest version of the sketch.

Firefly function added (progMode==4): Emulates the courtship behavior of the species. Each LED represents a Male, each with his own flashing sequence. Once in a while, all 3 LEDs go off, which is the Female sequence to get the males excited.

Per your requests, I will post the most current program listing in the following step.


Step 6: The latest sketch.

Picture of The latest sketch.
TriLEDFF02.bmp
TriLEDFF03.bmp
TriLEDFF04.bmp
/*
  • Tri-LED (piranha) matrix & touch test
  • (C) Copyright 2009 qs@quantsuff.com
  • Modules (selected by progMode)
  • 0 - Sequence
  • 1 - White light. Dims while on 'hold'.
  • 2 - Morphing colors. Random lights slowly blending.
  • 3 - Firelight. Flickering flames (hard to do when there's no real yellow!)
  • 4 - Fireflies. Emulate the courting ritual of the species.
*
  • 20mA integrated color LEDs - COMMON anode!!
  • D02 - red (LOW to turn on!)
  • D03 - green
  • D04 - blue
  • D05 - rightmost LED (HIGH to turn on)
  • D06 - center LED
  • D07 - leftmost LED
*/

int matrix[5]={
0660,0626,0466,0,0}
; // Rainbow display
int matrix02[5][2] = { // Morphing routine & firelight
{
511,7 }
,{
511,56 }
,{
511,504 }
,{
511,0 }
,{
511,504 }
};
unsigned int firefly[4]= {
0xdd42, 0xff00, 0x8a00, 0x2200} ;
/* Fireflies:
  • msb - (7:5) Intensity (0-7)
  • (4:2) Delay in 1/2sec units
  • (1:0) Type of bug (1=female, 2,3 = males)
*/

// For adjusting stepping sequences
long bigDelay= 300, bigD;
int fsuitors=0, i,j,val, LED, c0, c1,r0, g0, b0, r1, g1, b1, white=7;

int progMode=0 ; // The switch...case selector (99 is TEST)
int controlPin=12, sw02 = 0; // Switch status on A02
unsigned long dttimer02=0, timer02=0, ffTimer=0; // watchdog timers
int threshold= 100; // milliseconds for a 'touch', triple for 'hold'

void setup() {
for (int i=2; i<=7; i++) {
pinMode(i,OUTPUT);
digitalWrite(i,i<5);
}
randomSeed(analogRead(0));
pinMode(12,OUTPUT); // Our master touch switch control
digitalWrite(12,LOW);
analogReference(INTERNAL); // Boost (touch) sensitivity! Aref is offlimits!

for (i=1; i<4; i++) { // Set up fireflies' routine
j= random(2,4); // Type of male
j+= ((j+i-3)<<2) ; // Stamina (lack of) 0-7
firefly[i]= (j<<8) | (j<<1) |
((i+3)<<13) ; // Energy (brightness)
}
}

void loop() {
bigD= bigDelay+millis(); // Calc timeout

switch (progMode) {
case 0:
do {
for (LED=0; LED<=2; LED++)
writeLED(LED,matrix[LED]);
}
while (bigD>=millis());

if ((sw02&7)==0) { // Hold is HOLD!
matrix[0]= matrix[0]++ & 511 ; // funny math

i= (matrix[1] + 8) ; // Increase green
if (i>511) i=(i&7) + 1 ;
matrix[1]= i;

i= (matrix[2] + 64) ; // Increase blue
if (i>511) i= (i&63) + 1 ;
matrix[2]= i;
}
break ;

case 1:
{
r1= (white<<6)|(white<<3)|white ;
while (bigD>=millis())
for (LED=0; LED<=2; LED++)
writeLED(LED,r1);
if ((sw02&7)!=0) {
white--;
if (white<=0) white=7;
}
break;
}

case 2:
{
for (LED=0; LED<=2; LED++) {
if ((sw02&7)==0) { // Hold is HOLD!
c0= matrix02[LED][0] ;
c1= matrix02[LED][1] ;
if (c0!=c1) {
r0= c0 & 7;
g0= (c0>>3) & 7;
b0= (c0>>6) & 7;
r1= c1 & 7;
g1= (c1>>3) & 7;
b1= (c1>>6) & 7;
r1 -= constrain(r1-r0,-1,1);
g1 -= constrain(g1-g0,-1,1);
b1 -= constrain(b1-b0,-1,1);
matrix02[LED][1]= (b1<<6) | (g1<<3) | r1;
}
else
matrix02[LED][0]= random(0,512) ; // New target lights
}
}
while (bigD>=millis())
for (LED=0; LED<=2; LED++)
writeLED(LED,matrix02[LED][1]);
break;
}

case 3: // Log fire
{
for (LED=0; LED<=2; LED++) {
if ((sw02&7)==0) { // Hold is HOLD!
c0= matrix02[LED][0] ;
c1= matrix02[LED][1] ;
if (c0!=c1) {
r0= c0 & 7;
g0= (c0>>3) & 7;
b0= (c0>>6) & 7;
r1= c1 & 7;
g1= (c1>>3) & 7;
b1= (c1>>6) & 7;
r1 -= constrain(r1-r0,-1,1);
g1 -= constrain(g1-g0,-1,1);
b1 -= constrain(b1-b0,-1,1);
matrix02[LED][1]= (b1<<6) | (g1<<3) | r1;
}
else {
if (LED==1) {
r1=random(4,8);
g1=r1-2;
b1=0;
}
else {
r1= random(2,7);
g1= r1-2;
b1= 0;
}
matrix02[LED][0]= (b1<<6) | (g1<<3) | r1 ; // New target lights reds*greens
}
}
}
bigD= millis()+130;
do{
for (LED=0; LED<=2; LED++)
writeLED(LED,matrix02[LED][1]);
}
while (bigD>=millis()) ;
break;
}

case 4: // Fireflies
{
if (ffTimer<millis()) { // must wait for elapsed time
for (i=0; i<4; i++) {
int ff0= firefly[i];
int ff1= ff0>>8;
ff0= ff0 & 127;
int ff= ff0&7;
if (ff>0) { // Flash on
j= (ff1>>2)&070 ; //Pre-load green
if ((ff1&3)!=1) { //A Male
writeLED(i-1,j);
writeLED(i-1,j);
firefly[i]-- ;
fsuitors++;
}
else // A female!
if (fsuitors==0) {
j+=3;
writeLED(0,j);
writeLED(1,j);
writeLED(2,j);
writeLED(0,j);
writeLED(1,j);
writeLED(2,j); // Females show a longer, yellower pulse
firefly[i]-- ;
i= 99; // Early exit
}
}
else { // No flash
if (i==1) fsuitors=0;
j= (ff0>>3)&15;
if (j==0) //Wait expired
firefly[i]= (firefly[i] & 0xff00) | 0x40 | ((ff1&31)<<1) ;
else
firefly[i]-= 8;
}
}
ffTimer=millis()+450 ;
}
break;
}

case 99: // Test mode...
{
i= ((sw02>1) & 1)<<2 | // check for tap
((sw02>2) & 1)<<6 ;
writeLED(2,i) ; //tap=red + hold=blue
break;
}

default:
progMode=0;
break;
}

/*
  • Check for key pressed
*/
if (readTouch(2)) { // We see something on pin 2!
if ((sw02&1)==0) { // First time 'round
digitalWrite(13,HIGH); // so we SHOW smth.
sw02= 1; // Flag the touch
timer02= millis(); //Clock first touch
}
else { // 1-bit already set: we've been here before.
unsigned long t= millis()-timer02; // but how long ago?
if ((sw02&2)==2) { // Look at 'hold' only if 'press' is set
if (t>750) {
sw02= sw02 | 4;
if (t>8000) progMode=99;
}
}
else if (t>=200) sw02= sw02 | 2; // Set 'Press', more differentiation
}
}
else if (sw02&&1) { // Process key off
if ((millis()-timer02)>100) // Allow some 'give'before calling it quits
{
digitalWrite(13,LOW); // Show it
if ((sw02&6)==2) { //Process a 'tap'
unsigned long t= millis()-dttimer02; //
dttimer02= millis(); // Allows us to keep 'tapping'
if (t<600) { // 2 taps within time limit (600ms)
sw02= 0x10 ; // Turn on double tap'
progMode++ ; // Next Program
}
}
else {
sw02= sw02 & 0xff00 ;
timer02= 0;
}
}
}
}

# define lowThreshold 180 // Low is 180mV
# define highThreshold 450 // 450mV [600] - Skin resistance is 8Meg

boolean readTouch(int pin) {
int i=analogRead(pin);
i=analogRead(pin); //Ignore 1st reading
// if (i<lowThreshold) i=analogRead(pin); // Noise rejection
if (i<lowThreshold) {
digitalWrite(controlPin,HIGH);
if (progMode==99) writeLED(0,02); // Test: octal red
i=analogRead(pin);
digitalWrite(controlPin,LOW);
if (i>highThreshold) {
if (progMode==99) writeLED(0,020); // Test: octal yellow
//return (analogRead(pin)<lowThreshold);
return true;
}
else return false ;
} // Test passed - key pressed
else return false;
}

#define waitFactor 6 // Brightness factor
void writeLED(int LED, int value) { // LED== 0(D7), 1(D6), 2(D5)
//value is 3bits for r[lsb],g,b
digitalWrite(7-LED,HIGH); // Bring anode high
int r= value & 7;
int g= (value>>3) & 7;
int b= (value>>6) & 7;

if (r>0) {
digitalWrite(2,LOW);
delayMicroseconds(waitFactor<<r);
}
digitalWrite(2,HIGH);
delayMicroseconds(waitFactor<<(7-r));

if (g>0) {
digitalWrite(3,LOW);
delayMicroseconds(waitFactor<<g);
}
digitalWrite(3,HIGH);
delayMicroseconds(waitFactor<<(7-g));

if (b>0) {
digitalWrite(4,LOW);
delayMicroseconds(waitFactor<<b);
}
digitalWrite(4,HIGH);
delayMicroseconds(waitFactor<<(7-b));

digitalWrite(7-LED,LOW);
}

 
Remove these adsRemove these ads by Signing Up
MRedmon4 years ago
I made this mood light for my sister's birthday. I followed the instructions above but etched a custom PCB, added a 2xAA or USB power source, fabricated a base out of plexiglass, and found a vase at Goodwill. I have a video at http://www.youtube.com/watch?v=2vbmpzk91vY
qs (author)  MRedmon4 years ago
Great work! She must be very pleased!
remal4 years ago
AmAAAAAzInG
qs (author)  remal4 years ago
Thank you!
YOU GUYS ARE SO COOL DOING THESE IS ONE THING I ALWAYS WANTED TO DO. IN 1980 I SAW MY FIRST TOUCH ACTIVATED LAMP IT WAS A AFICAN VIOLET YOU TOUCHED A LEAF AND THE LIGHT CAME ON. THAT WAS A REGULAR INCADESENT BULB. THERE IS A GREAT BIO OF THOMAS EDISONS LIFE AND WORK ON PROJECT GUTENBERG.COM THE PLAIN TEXT VERESION DEOWNLOAD IN SECONDS BUT ITS A FIVE HUNDRED PAGE DOC. i USE A READER I GOT FROM NCH SOFTWARE ITS A FREE TRIAL IT CAN READ PDG FILES TOO THAT COOL LISTEENING TO YOUR COMPUTER GO ALL DAY READING WHILE YOU WORK ON OTHER STUFF.
Since it still has the data lines intact, why not create a music visualizer out of it? Use Processing and the minim audio library to capture audio from your sound card (you have to have a "Stereo Mix" recording device though) and then output some data to the serial port. I did this with a bunch of RGB LED's and it looked awesome. This code makes a FFT (analyzes audio stream into a frequency spectrum like the Bars visualization). You can just set the LED brightnesses to whatever bar you want to get a flashing effect to the music. http://code.compartmental.net/tools/minim/manual-fft/
qs (author)  CalcProgrammer14 years ago
I know what you mean. I did something similar here: http://www.instructables.com/id/The-LED-Matrix-Panel-or-LMP-for-the-Arduino-micr/ and in fact I've gone even further with a version that has 8 RGB LEDs - you can see a demo here: http://www.youtube.com/watch?v=ZoocFDhX0Cw - I just never got round to writing it up. qs
qs (author)  qs4 years ago
Oops, the version with 8 triLEDs is here: http://www.youtube.com/watch?v=Km-NZDvDG0s. This one uses an electret mic for input and analyses both frequency and beat. There are 4 different display modes. My plan was to make it large enough to mount on a wall, but never found the time.
dunnos5 years ago
i NEED the code (for the touch wire and, who knows, if i can find led's even this lamp!) pm it to me please thanks! Dennis
qs (author)  dunnos5 years ago
Dennis, Just added a step with the full sketch above. Good luck, and keep me informed of your progress!
dunnos qs5 years ago
I love you man
dosadi5 years ago
Nice instructable. Where did you get the terminated jumper wires in the step 2 photo?
They sell them at makerstore.com I believe.
They do, thank you. For anyone else who might be interested, it's makershed.com, not makerstore.com.
qs (author)  dosadi5 years ago
Thanks. They are just jumpers sold for connecting breadboards.