view history edit print login register

Native Capacitive Sensors without additional Hardware

Sensor key demonstrates how the Arduino can sense a touch sensitive key through digital pins 8 to 13. It requires no special hardware, nevertheless a capacitor of 1nF is recommended in line with the pin to decouple 50Hz noises.

Connect a wire or some metallic plate to a digital pin (digital 8-13).

The program measures the capacity (time to charge) of the given port. If untouched getcap returns a low value e.g. "1" when touched it rises to about 5. By adding some comparision with a threshold you can make it a boolean key input.

DO NOT CONNECT ANY ACTIVE DRIVER TO THE USED PIN !

the pin is toggled to output mode to discharge the port capacity, which would shortcut any chip/transistor which might drive the port high.

Mario Becker, Fraunhofer IGD, 2007 http://www.igd.fhg.de/igd-a4

// sensor key
#define KEYPORT PORTB
#define KEYDDR  DDRB
#define KEYPIN  PINB
#define KEY0    PB0        // capture input - digital 8
#define KEY1    PB1        // capture input - digital 9
#define KEY2    PB2        // capture input - digital 10
#define KEY3    PB3        // capture input - digital 11
#define KEY4    PB4        // capture input - digital 12
#define KEY5    PB5        // capture input - digital 13

void setup()
{
  Serial.begin(9600);      // connect to the serial port
}

// returns capacity on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  KEYDDR &= ~pin;          // input
  KEYPORT |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (KEYPIN & pin) ) break;
  KEYPORT &= ~pin;         // low level
  KEYDDR |= pin;           // discharge
  return i;
}

void loop ()
{
  char capval[6];
  char pinval[6] = {1<<KEY0,1<<KEY1,1<<KEY2,1<<KEY3,1<<KEY4,1<<KEY5};
  delay(1000);
  for(char i = 0; i < 6; i++)
  {
    capval[i] = getcap(pinval[i]);
    Serial.print("digital ");
    Serial.print(i+8, DEC);
    Serial.print(": ");
    Serial.println(capval[i], DEC);
  }
  Serial.println("");
}

Alternative Code for ATMega368 Arduino Duemilanove

For some reason using shorthand such as "PB4" doesn't work when compiling for the newer Duemilanoves, so I've rewritten this code to account for this and tested it on my own.

Great work by Mario, thanks for this simple code for such a potentially useful sensor!


/*Capacitative Sensing Code for ATMega328 Arduinos*/

void setup()
{
  Serial.begin(9600);      // connect to the serial port
}

void loop ()
{
  char capval[6];
  char pinval[6] = {1<<PINB0,1<<PINB1,1<<PINB2,1<<PINB3,1<<PINB4,1<<PINB5};
  delay(1000);
  for(char i = 0; i < 6; i++)
  {
    capval[i] = getcap(pinval[i]);
    Serial.print("digital ");
    Serial.print(i+8, DEC);
    Serial.print(": ");
    Serial.println(capval[i], DEC);
  }
  Serial.println("");
}

// returns capacity on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}