petes-brain

Bottle Cap Capacitive Touch Button for Arduino April 18, 2013

bottle-cap-capacitive-switch

Here’s a cool trick that I picked up a few months back.  We’re all familiar with the capacitive touch tech that enables our mobile devices.  Come to find out, integrating basic touch functionality into your Arduino projects may not be as tricky as it looks.

This article out on the Playground outlines a function that does all of the hard work and can be used to measure capacitance across a conductive surface.  The function returns an unsigned int that represents the relative capacitance of that surface.  Touch the surface and you change that representation.  Now all that’s left is to look for a change in the value of the function’s return and you have a capacitive touch button!

First off attach a conductive surface to your Arduino’s digital pin 2; say an unwound paper clip or a bottle cap soldered to the end of a short piece of hookup wire., try using the Serial.println() function to look at the change in the function’s return value:

void setup() {
Serial.begin(9600);
}

void loop() {
uint8_t pinRead;
pinRead = readCapacitivePin(2);
Serial.println(pinRead);
delay(100);
}

//  — readCapPin found at http://www.arduino.cc/playground/Code/CapacitiveSensor
//  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
#include “pins_arduino.h” // Arduino pre-1.0 needs this
uint8_t readCapacitivePin(int pinToMeasure) {

// Variables used to translate from Arduino to AVR pin naming
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;
port = portOutputRegister(digitalPinToPort(pinToMeasure));
ddr = portModeRegister(digitalPinToPort(pinToMeasure));
bitmask = digitalPinToBitMask(pinToMeasure);
pin = portInputRegister(digitalPinToPort(pinToMeasure));
// Discharge the pin first by setting it low and output
*port &= ~(bitmask);
*ddr  |= bitmask;
delay(1);
// Make the pin an input with the internal pull-up on
*ddr &= ~(bitmask);
*port |= bitmask;

// Now see how long the pin to get pulled up. This manual unrolling of the loop
// decreases the number of hardware cycles between each read of the pin,
// thus increasing sensitivity.
uint8_t cycles = 17;
if (*pin & bitmask) { cycles =  0;}
else if (*pin & bitmask) { cycles =  1;}
else if (*pin & bitmask) { cycles =  2;}
else if (*pin & bitmask) { cycles =  3;}
else if (*pin & bitmask) { cycles =  4;}
else if (*pin & bitmask) { cycles =  5;}
else if (*pin & bitmask) { cycles =  6;}
else if (*pin & bitmask) { cycles =  7;}
else if (*pin & bitmask) { cycles =  8;}
else if (*pin & bitmask) { cycles =  9;}
else if (*pin & bitmask) { cycles = 10;}
else if (*pin & bitmask) { cycles = 11;}
else if (*pin & bitmask) { cycles = 12;}
else if (*pin & bitmask) { cycles = 13;}
else if (*pin & bitmask) { cycles = 14;}
else if (*pin & bitmask) { cycles = 15;}
else if (*pin & bitmask) { cycles = 16;}

// 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;
}

And you’re off!  Try comparing the return value to something a threshold in order to trigger a change.  For instance:  if the return value seems to sit at “2” without anything touching, and rises to “5” when you do, you can tell your Arduino to blink an LED if the return value is higher than 4.  Amend your code like so, borrowing from the blink scretch (I dropped the additional function here for brevity, hold on to yours!):


void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
}

void loop() {
uint8_t pinRead;
pinRead = readCapacitivePin(2);
Serial.println(pinRead);
delay(100);

if (pinRead > 4) {
digitalWrite(led, HIGH);
} else {
digitalWrite(led, LOW);
}
}

Try different materials or lengths of wire to see how the change the capacitance reading.  Use your imagination.  There’s no shortage of ways you can use this.  Have fun.


Categories Uncategorized

Leave a Reply