loading
Picture of Capacitive Touch Arduino Lamp
EDIT: I made another one of these, and hacked an ikea lamp with it. You can see the 'ible overe HERE

The Problem


It is late night, and your cellphone rings. You can't see where it is, you blindly grope around your nightstand, trying in vain to find that illusive switch that will illuminate your side of the bed. You clumsily turn on the lamp, locate your cellphone...and you miss the call. Damn. If only your light was easier to turn on.

The solution

What if all you had to do to turn on your lamp...was to touch anywhere metal on your bedside table? That sounds complicated though, and I AM a strong believer in keeping things simple whenever possible. I wonder if there are any open-source solutions that would allow such a thing to happen? Enter ARDUINO. A cheap, easy to use micro-controller that is dead simple to program and implement.  This sounds like it might just work!

Since I am inherently thrifty (an HVAC-R apprentice, AND a Mennonite) I don't want to commit my only $35 arduino board to the project. This means i'll have to build my own Arduino, which will save me some money.  Additionally, I'm only using a couple of pins, and not doing any serial communications, so I really don't want to bother using an external oscillator. That means I'll have to figure out how to enable the internal oscillator on an atmega 168.

Scope

This 'ible will show you how to do the following (without a lot of hand-holding);

How to burn a bootloader to a standalone atmega168 using an Arduino UNO SMD edition.
How to enable the internal oscillator, so you can save $0.50 and not use a crystal.
How to program a standalone chip using an Arduino board and the Arduino IDE.
How capacitive touch objects work.

What is NOT covered
How to read a schematic diagram
How to solder
How to layout a protoboard

Since there are literally hundred of guides on how to solder, how to use schematic diagrams, and basics of digital electronics...I'm not going to go there. You'll notice that there is a search bar in the upper right hand corner of this wonderful site. I'm sure if you try using it, you'll find what you need. That said, if you are having troubles implementing THIS particular project, and it doesn't involve such things as "How do I solder a resistor" then please feel free to ask.

***WARNING***
I am curmudgeonly, so my responses to questions that are not included in the scope of this 'ible may or may not include some lighthearted mocking. You have been warned.


This is a proof of concept i'd put together before building the standalone.

 
 
Remove these adsRemove these ads by Signing Up

Step 1: Materials

- An arduino (I'm using an Arduino Uno SMD, which brings a set of challenges)
- An LED Strip
- Either a mosfet and transistor that your arduino can switch or a small DC Solid State Relay (SSR)
- Atmega168 DIP
- (1) 10k resistor
- (1) 1M resistor
- (1) 16 mHz crystal (might not be required)
- (1) solderless breadboard
- (1) protoboard/strip board.
- Wire
- Wire Nuts
- Wire Strippers, screwdrivers.
- Nuts and bolts
- Small electrical junction box
- (1) power supply that can supply both 12V and 5V. (Or 12V only, and use an 1805IC with a couple of capacitors to smooth it out) 

The total cost on the project was about $20-$30. The most expensive part of the project was the electrical junction box and lid, which came to about $6.00. Home Despot is such a rip-off.

I troll ebay looking for electrical componenet from Thailand. There are some vendors that offer free shipping on a lot of stuff. The SSR I am using was $3 with free shipping. Same goes with the protoboard, get it for cheap on ebay.

The total cost on the project was about $20-$30.

Step 2: Burn the bootloader

Picture of Burn the bootloader
The first thing we are going to need to do is upload the Arduino bootloader to our Atmega168 chip. Since I don't want to use an external crystal, we are going to have to be sneaky.  The only Arduino board that uses the internal crystal is the Lilypad. Thus, we are going to upload the LILYPAD bootloader into the Atmega168. There is a downside to this, in that the Lilypad bootloader takes about 10 seconds to initialize on power. 

Depending on where you get your atmega168's from, they may or may not have the internal crystal enabled. When programming an atmega168 for the first time, you'll often need to provide the crystal before you can turn on the internal one. The crystal being used on the breadboard will not actually be included in the final project assembly.

In this step, we are going to program an arduino board to act like an ISP (In System Programmer).  This will allow us to upload programs into a standalone atmega168 chip without having to purchase a dedicated ISP (I'm cheap, remember?).

1) Open the Arduino IDE software, and click on File>Examples>ArduinoISP.
2) Connect your arduino board to the computer, and click on "Upload"
3) Disconnect your arduino board.
4) Carefully insert your atmega168 chip into a solderless breadboard and connect it like the picture shows. Pin 1(RESET) has the DOT right next to it.  Pin 1, in the diagram below is on the bottom left hand side of the Atmega168 chip. Before plugging the usb cord into your arduino, please double check that you haven't attached +5VDC to the GND pin and the GND to the +5VDC pin on your standalone chip. If you do this, you'll most likely let the smoke out of the chip. I speak from experience when I say it is very difficult to get the smoke back inside ;)



5) In the arduino IDE software, click on tools>Programmer>Arduino as ISP. (This tells the arduino IDE that you are going to be    transmitting data from the arduino to an external chip.)
6) Now we need to select the bootloader for the standalone chip. Click tools>Board>LilyPad Arduino w/ Atmega 168.  This bootloader will enable the internal oscillator, thus allowing us to forgo the external one in our project.
**THIS PROBABLY WILL NOT WORK IF YOU DO NOT HAVE A CRYSTAL ATTACHED DURING THE BOOTLOADER UPLOAD PROCESS**

7) Time to burn the bootloader! Click on tools> Burn Bootloader. The TX and RX lights on the arduino board should be flickering on and off, just like the video shows.


IF the arduino IDE gives you an error code that mentions 'not in synch', check your breadboard connections. There is probably a loose wire somewhere.

 

Step 3: Program your Standalone Chip

Picture of Program your Standalone Chip
programmer.png
upload.png
Programming a standalone chip can be confusing the first time you do it. There really aren't that many instructions around on how to do it. This is doubly true with the Arduino UNO SMD version. Most instructions tell you to remove the atmega168 chip from the board. If you have the SMD chip, you are out of luck. If you have the DIP version, I would caution you against repeatedly removing the chip from the DIP socket.Remove the chip enough times, and you are likely to break off a couple of legs from your arduino chip, which would be rather inconvenient.

The reason you are meant to remove the chip from the arduino board is because when the programming TX/RX begins, the arduino chip resets. This reset desynchronizes the standalone chip from the programming board, which then causes an upload failure. The work around is simple.

 Programming a Standalone Chip
1) Wire up the standalone chip, as per the last step.
2) Attach a 20uF capacitor between the RESET and GND pin on the Arduino board. Make sure the positive leg of the capacitor is connected to the RESET pin and the negative leg is connected to a ground pin. This step prevents the arduino from resetting during the upload process.
3) Make sure LilyPad arduino w/ atmega 168 is selected under tools>Board. Make sure Arduino as ISP is selected under Tools>Programmer.
4) Copy and paste the arduino code into the Arduino IDE
5) Click File>Upload Using Programmer.
6) Cross your fingers and pray to the breadboard Gods that you don't have a loose wire.
7) Dance with jubilation because you now have a standalone atmega chip programmed to do what you want it to do.


I used the capsense example found in the arduino libraries and modified it to respond to multiple touches. I included fade, because I don't like sudden brightness changes (and it just looks much cooler)

THE CODE//Just Copy and paste it.

byte LEDPin = 11;       //PWM Output pin for LED
byte capSensePin = 2;   //Pin to attach to capacitive sensor
byte mode = 0;         //Determines LED brightness. 0 is off. Varies between 0 and 255.
byte touchThreshold = 100; //Minimum capacitive touch value  in order to trigger next  mode
byte targetBrightness = 0; // Set power on brightness
byte currentBrightness = 0; //variable to compare brightness

void setup(){
    Serial.begin(9600);
    pinMode(LEDPin, OUTPUT);  //Set LEDPin to output mode
}

void loop(){

    if (readCapacitivePin(capSensePin) > touchThreshold) {  //If the value of capSensePin exceeds touchThreshold then do...
        delay(250);    
        //Button Debounce. How would I remove this break using millis()??
        mode++; //If the above threshold is exceeded, then increase the value of mode by 1

        //This next section outlines the different LED brightness levels. 255 is all the way one. 128 is half brightness.
        if (mode > 3) mode = 0;  //If the value for mode is > 3 then set value of mode to 0.
        if (mode == 0) targetBrightness = 0;
        if (mode == 1) targetBrightness = 255;
        if (mode == 2) targetBrightness = 128;
        if (mode == 3) targetBrightness = 64;
       
        Serial.print("The current mode is..."); //Serial monitor to bebug mode increases
        Serial.println(mode);  //print value of mode to seial monitor

    }
//Fade control
    if (targetBrightness > currentBrightness) currentBrightness++;
    if (targetBrightness < currentBrightness) currentBrightness--;
    analogWrite(LEDPin, currentBrightness);
    delay(3); //determines how rapidly the fade occurs.
    //Serial.println(currentBrightness);

    // THIS POINT ONWARD I DIDN'T WRITE.
    // Every 500 ms, print the value of the capacitive sensor
    if ( (millis() % 500) == 0){
        Serial.print("Capacitive Sensor on Pin 2 reads: ");
        Serial.println(readCapacitivePin(capSensePin));
    }
}

// readCapacitivePin
//  Input: Arduino pin number
//  Output: A number, from 0 to 17 expressing
//          how much capacitance is on the pin
//  When you touch the pin, or whatever you have
//  attached to it, the number will get higher
//  In order for this to work now,
// The pin should have a 1+Megaohm resistor pulling
//  it up to +5v.
uint8_t readCapacitivePin(int pinToMeasure){
    // This is how you declare a variable which
    //  will hold the PORT, PIN, and DDR registers
    //  on an AVR
    volatile uint8_t* port;
    volatile uint8_t* ddr;
    volatile uint8_t* pin;
    // Here we translate the input pin number from
    //  Arduino pin number to the AVR PORT, PIN, DDR,
    //  and which bit of those registers we care about.
    byte bitmask;
    if ((pinToMeasure >= 0) && (pinToMeasure <= 7)){
        port = &PORTD;
        ddr = &DDRD;
        bitmask = 1 << pinToMeasure;
        pin = &PIND;
    }
    if ((pinToMeasure > 7) && (pinToMeasure <= 13)){
        port = &PORTB;
        ddr = &DDRB;
        bitmask = 1 << (pinToMeasure - 8);
        pin = &PINB;
    }
    if ((pinToMeasure > 13) && (pinToMeasure <= 19)){
        port = &PORTC;
        ddr = &DDRC;
        bitmask = 1 << (pinToMeasure - 13);
        pin = &PINC;
    }
    // Discharge the pin first by setting it low and output
    *port &= ~(bitmask);
    *ddr  |= bitmask;
    delay(1);
    // Make the pin an input WITHOUT the internal pull-up on
    *ddr &= ~(bitmask);
    // Now see how long the pin to get pulled up
    int cycles = 16000;
    for(int i = 0; i < cycles; i++){
        if (*pin & bitmask){
            cycles = i;
            break;
        }
    }
    // Discharge the pin again by setting it low and output
    //  It's important to leave the pins low if you want to
    //  be able to touch more than 1 sensor at a time - if
    //  the sensor is left pulled high, when you touch
    //  two sensors, your body will transfer the charge between
    //  sensors.
    *port &= ~(bitmask);
    *ddr  |= bitmask;

    return cycles;
}

Step 4: CODE discussion

This section outlines the various variables and constants we are going to be using. Please note that I have used const byte instead of int. The reason is, is that micro-controllers have very limited storage space. Int values can take up to 28 bytes, where as a byte value can store a number between 1 and 255 and only takes up...1 byte.  I used the int tag for touchThreshold because I was getting values larger than 255 returned.

Const byte is used, because it tells the compiler to optimizer storage use.  



const byte LEDPin = 11;       //PWM Output pin for LED
const byte capSensePin = 2;   //Pin to attach to capacitive sensor
byte mode = 0;         //Determines LED brightness. 0 is off. Varies between 0 and 255.
int touchThreshold = 100; //Minimum capacitive touch value  in order to trigger next  mode
byte targetBrightness = 0; // Set power on brightness
byte currentBrightness = 0;


Void setup runs once, and assign pinModes etc. I start the serial monitor here because I was using it to trouble shoot.

void setup(){
    Serial.begin(9600);
    pinMode(LEDPin, OUTPUT);  //Set LEDPin to output mode
}

void loop(){

This is the main program loop. It keeps on repeating and going through the various lines of code.

    if (readCapacitivePin(capSensePin) > touchThreshold) {  //If the value of capSensePin exceeds touchThreshold then do...
        delay(250);    
        //Button Debounce. How would I remove this break using millis()??
        mode++; // If the touch threshold is exceeded, increase value of mode by 1

        //This next section outlines the different LED brightness levels. Two == in a row tells the processor to compare two values.
        if (mode > 3) mode = 0;  //If the value for mode is > 3 then set value of mode to 0.
        if (mode == 0) targetBrightness = 0;
        if (mode == 1) targetBrightness = 255;
        if (mode == 2) targetBrightness = 128;
        if (mode == 3) targetBrightness = 64;
       
        Serial.print("The current mode is..."); //Serial monitor to bebug mode increases
        Serial.println(mode);  //print value of mode to seial monitor

    }
//Fade portion

    if (targetBrightness > currentBrightness) currentBrightness++; //If the target brightness is less than current brightness, then +1 to //current brightness
    if (targetBrightness < currentBrightness) currentBrightness--;
    analogWrite(LEDPin, currentBrightness); //PWM output to LEDPin. This changes the brightness of the light
    delay(3);
    //Serial.println(currentBrightness);

    // THIS POINT ONWARD I DIDN'T WRITE. It was iincluded in the example from arduino.
    // Every 500 ms, print the value of the capacitive sensor
    if ( (millis() % 500) == 0){
        Serial.print("Capacitive Sensor on Pin 2 reads: ");
        Serial.println(readCapacitivePin(capSensePin));
    }
}

// readCapacitivePin
//  Input: Arduino pin number
//  Output: A number, from 0 to 17 expressing
//          how much capacitance is on the pin
//  When you touch the pin, or whatever you have
//  attached to it, the number will get higher
//  In order for this to work now,
// The pin should have a 1+Megaohm resistor pulling
//  it up to +5v.
uint8_t readCapacitivePin(int pinToMeasure){
    // This is how you declare a variable which
    //  will hold the PORT, PIN, and DDR registers
    //  on an AVR
    volatile uint8_t* port;
    volatile uint8_t* ddr;
    volatile uint8_t* pin;
    // Here we translate the input pin number from
    //  Arduino pin number to the AVR PORT, PIN, DDR,
    //  and which bit of those registers we care about.
    byte bitmask;
    if ((pinToMeasure >= 0) && (pinToMeasure <= 7)){
        port = &PORTD;
        ddr = &DDRD;
        bitmask = 1 << pinToMeasure;
        pin = &PIND;
    }
    if ((pinToMeasure > 7) && (pinToMeasure <= 13)){
        port = &PORTB;
        ddr = &DDRB;
        bitmask = 1 << (pinToMeasure - 8);
        pin = &PINB;
    }
    if ((pinToMeasure > 13) && (pinToMeasure <= 19)){
        port = &PORTC;
        ddr = &DDRC;
        bitmask = 1 << (pinToMeasure - 13);
        pin = &PINC;
    }
    // Discharge the pin first by setting it low and output
    *port &= ~(bitmask);
    *ddr  |= bitmask;
    delay(1);
    // Make the pin an input WITHOUT the internal pull-up on
    *ddr &= ~(bitmask);
    // Now see how long the pin to get pulled up
    int cycles = 16000;
    for(int i = 0; i < cycles; i++){
        if (*pin & bitmask){
            cycles = i;
            break;
        }
    }
    // Discharge the pin again by setting it low and output
    //  It's important to leave the pins low if you want to
    //  be able to touch more than 1 sensor at a time - if
    //  the sensor is left pulled high, when you touch
    //  two sensors, your body will transfer the charge between
    //  sensors.
    *port &= ~(bitmask);
    *ddr  |= bitmask;

    return cycles;
}

Step 5: Build the Protoboard and mount it.

Picture of Build the Protoboard and mount it.
IMG_1777[1].JPG
Build the circuit on a proto-board.

TIPS:
1) Make sure you solder the DIP socket in before you insert the atmega168 chip. Microcontrollers are very sensitive to heat.
2) Clean your soldering iron between joints.
3) Take your time, and double check your work.
4) If using an SSR, solder that in last.
5) Use a third-hand apparatus if you have it!
6) Don't forget to add some strain relief.

I managed to find a power supply from an old scanner at the local dump. It provides two output voltages. +12VDC and +5VDC, it very much simplified the project. If you aren't so fortunate, then you'll need to use a power supply that outputs 12VDC and then use an LM7805 or something similar to provide the +5VDC. There are a lot of tutorials on how to do this, so you are on your own ;).

For the touch sensor, any metal object will work. In the final build, I extended a piece of wire outside of the project box. This wire just needs to be attached to the touch sensor of choice.  I didn't have any panel mount plugs left, otherwise I would have gone the extra mile and installed one of those.

Whenever you have wire passing through sheet metal, you should always include some sort of protection for the wire. Be it a cable gland, or an insert. This prevents a sharp edge from cutting through the wire and causing a short. In my case, the box isn't going to be moved around, so I didn't bother. Even if there IS a short, my powersupply has short-circuit detection build it and it shuts off.  If I had 110V AC running to the junction box, I would definitely use the inserts, as a short to the case could be lethal. Since i'm only using 12VDC, I really am not concerned. If you build it, please include the inserts ;)

As for mounting the board, I just used a bolt with some nuts. I used a couple of the holes already present in the junction box.

Step 6: Watch it work!


 

Step 7: COMING SOON

I have to add some form of light diffusion onto the LED, as the light shoots straight up. Once I have that figured out, i'll update it here.
timbit1985 (author) 2 years ago
"This is most likely a stupid question, but how does the intensity of the LED change when it's getting 12 volts straight from the power supply?"

This isn't a stupid question at all. I believe I touched briefly in a previous section about PWM, but I might be mistaken. PWM stands for pulse width modulation. PWM allows you to vary the duty cycle of a digital pin. This means that you are switching the digital pin on and off very rapidly. This rapid switching results in a decrease in brightness. If you look at the following code

if (mode == 0) targetBrightness = 0;
if (mode == 1) targetBrightness = 255;
if (mode == 2) targetBrightness = 128;
if (mode == 3) targetBrightness = 64;

targetBrightness = 0; means off.
255 is a 100% duty cycle. 128(half of 256) is a 50% duty cycle, 64 (1/4 of 256) is a 25% duty cycle.

The value vary between 0 and 255 because the atmega has 16bit address bus, allowing for 2^16 (256) bits.

A 50% duty cycle refers to the fact that the LED (or digital output pin) is HIGH (or turned on) for 50% of the time. This means that in a period of 1 second, the light is off for a total of 0.5 sec and on for a total of 1 second.

http://d32zx1or0t1x0y.cloudfront.net/2011/06/atmega168a_pwm_02_lrg.jpg This is a nice picture that graphically shows what different duty cycles look like. Notice how the pulse width size changes between the different duty cycles. Modulation means to change something.



What this means is
timbit1985 (author)  timbit19852 years ago
**EDIT: On for 0.5 second, off for 0.5 second in the last paragraph.
gregjd50004 months ago
Hey! Awesome ible but the name is a tad misleading. Cap Touch uses changing time constants because of an approaching ground (person) to detect touch without contacting any metal. This uses a resistor to pull high then the human to directly pull to ground. I really enjoyed reading the Instructable but wanted to mention that.
zootalaws6 months ago

Being curmudgeonly myself, I was tempted to correct your 'ible' to 'able', but - funkit, if we spent our time correcting silly grammar we wouldn't have time to make cool stuff :)

Good 'able, btw ;) I have about 50x $3 Arduino Nanos hanging around and a box full of addressable LEDs - this will come in handy for gesture switching.

solaron992 years ago
Hi Timbit1985, fantastic project!

another crazy question:

Can I use an ATmega328P chip instead of the ATmega168 chip for use in this project
using : Tools/Board/LilyPad Arduino w/ ATmega328 ?

timbit1985 (author)  solaron992 years ago
Did you end up using the ATmega328P ? Did it work out okay for you?

Yes, it worked out perfectly! Will attempt using an Attiny 85. Thx again.

timbit1985 (author)  solaron992 years ago
I don't see why not. I believe the lilypad with atmega328 uses an oscillator, where as I chose a firmware that does not. This means that you will have to install a crystal for it to work. Make sure that the pin outs are the same on the atmega328 vs the 168.

Oh thats a realy nice instructable. I was looking for something like this since a long time. Well done!!

I
have one question about this. I have a Arduino Duemilanove which i
dont need anymore and I have enough Place to place it in my Lamp. Can i
upload your skatch and it will work to? Just to skip the Step for
programming the Standalone Chip.

timbit1985 (author)  maestro_dom1 year ago

Oops, sorry I missed this. I don't see why it wouldn't work. Good luck! Thanks for checking out my instructables.

It works perfektly ;) thank you again!

solaron992 years ago
Yes, it worked out. Awesome!
scanning2 years ago
That is a good explain and release my problem.Thank You!
scanning2 years ago
I don't understand how to set control the vary with level of LED in the circuit . I only saw a relay with 12V contact direct connect to LED only.
timbit1985 (author)  scanning2 years ago
The relay is actually an SSR, which has a very rapid switching rate compared to a mechanical relay. You could use a mosfet as well, which would be cheaper. I just used what I had on hand.

Basically the microcontroller turns the SSR on and off rapidly, which in turn switches the LED on and off rapidly. This rapid switching is known as Pulse Width Modulation (PWM), and is a very common way of controlling LED brightness without varying the current or voltage.
iwalton12 years ago
This is most likely a stupid question, but how does the intensity of the LED change when it's getting 12 volts straight from the power supply?
samaddon2 years ago
Nice work man i appreciate it Very well done!
samaddon2 years ago
Nice work man i appreciate it Very well done!
mrmerino2 years ago
...Can't you just look for the light from your cell phone's screen?
timbit1985 (author)  mrmerino2 years ago
you COULD if the cellphone was in sight. I always keep it in my pants, so I don't forget it when I leave the house.
Fair enough. This is still a good Instructable though.
timbit1985 (author)  mrmerino2 years ago
Thanks. I appreciate the comments.
This is a great project - very similar to one I did a while back except I didn't use Arduino at all (primarily because it's unnecessary overhead). Although I used a constant current driver, a simple MOSFET switch is sufficient in controlling the brightness through PWM.

http://www.instructables.com/id/Custom-LED-Touch-Light-Fixture/

The only thing I would really recommend is that you try to use a smaller chip than the ATmega168 - kind of a huge waste of pins and program space (and money) to just read a sensor and turn on/off some lights! I did my whole project with the 8 pin ATtiny25 and still had a few pins and a lot of space left over, but this is the smallest chip that isn't surface mount.

For Light Diffusion:
Try arranging your LED strip(s) in various shapes and angles and placing the light inside a real light fixture or lamp shade.


Schematic-v3.jpgFixture 2.jpg
timbit1985 (author)  Kurt E. Clothier2 years ago
Thanks Kurt. I used what I had on hand, which was the atmega168 ;) I have a bunch of attiny85's on the way, which I actually plan on switching into this project once they arrive.

That's a good idea regarding the light fixture. I did the same thing inside of my car.
Jazzy132 years ago
You got my vote! Nice thinking.
timbit1985 (author)  Jazzy132 years ago
Thank you very much :) I am always trying to come up with little ideas to make my wife's life a bit easier.
That's sweet. Make to check out my instructables. B-)

***WARNING*** I am curmudgeonly, so my responses to questions that are not included in the scope of this 'ible may or may not include some lighthearted mocking. You have been warned.

Ha!

This is an excellent idea, too. Awesome job!

timbit1985 (author)  jessyratfink2 years ago
Thanks! I'm glad you like it :)