Capsense with Arduino

From Code Lab Wiki

Jump to: navigation, search

Based on the work done by Paul Badger. Customized Spring of 2008 for use with an arduino with copper wire connected to the sensor port. Sensitivity was adjusted to work through clear heat shrink along an EL wire.

Software shaping and sensing has had calibration and sensitivity issues, dedicated capacitive sensors may be a better alternative moving forward.


/* 
 CapSense.pde
 Paul Badger 2007

 Fun with capacitive sensing and some AVR port manipulation code 
 for the Arduino (or Wiring Boards).
 Note that the AVR code is based on Arduino 
 and will probably require some changes for Wiring Board

 How It Works
 The physical setup includes a high value (1-10M) resistor 
 between an output pin and an input pin. When the output pin changes
 state, it will eventually change the state of the input pin
 in a time constant determined by R * C, where R is the resistor
 and C is the capacitance of the pin, plus any other capacitance 
 (e.g. human body interaction) present at the sensor (input) pin.

 It is possible when using this setup to see some variation in 
 capacitance when one's hand is 3 to 4 inches from the sensors
 Experiment with larger resistor values and large sensor plates for 
 more sensitivity. Lower values of R will probably yield higher reliability.
 Use 1 M resistor (or less maybe) for absolute touch to activate.
 With a 10 M resistor the sensor will start to respond 1-2 inches away

 Setup
 Connect a 10M resistor between pins 8 and 9 on the Arduino Board
 Connect a small piece of aluminum or copper foil to a short wire as a
 sensor and also connect it to pin 9 (the sensor pin). There is nothing
 special about pins 8 & 9 and they can be any Arduino digital pins.

 When using this technique in an installation or device it's going to be
 important to use shielded cable if the wire between the sensor is  
 more than a few inches long, or it runs by anything that is not supposed
 to be sensed. 

 Calibration may be an issue, and may vary somewhat with humidity or other factors.
 Instead of "hard wiring" threshold values - store the "non touched" values
 in a variable on startup - and then compare to a "difference" value.
 If your sensed object is many feet from the Arduino Board 
 you're probably going to be better off using the Quantum cap sensors.

 AVR port-manipulation code from a forum post by ARP
 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1169088394/0#0
*/ 


int  i;
unsigned int x, y;
float accum, fout;  // these are variables for a simple low-pass (smoothing) filter
float fval = .07;         // fval of 1 = no filter - .0001 = max filter
float lastCount;
int hit = 0;

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

  DDRB=B101;     // DDR is the pin direction register - governs inputs and outputs- 1's are outputs
  //  Arduino pin 8 output, pin 9 input, pin 10 output for "guard pin" (this is optional)
  //  preceding line is equivalent to three lines below
  //  pinMode(8, OUTPUT);     // output pin
  //  pinMode(9, INPUT);      // input pin
  //  pinMode(10, OUTPUT);    // guard pin used to shield high impedance input 
      digitalWrite(10, LOW);  // guard pin low
}

void loop() {
  y = 0;        // clear out variables
  x = 0;

  for (i=0; i < 5 ; i++ ){      
    
    // LOW-to-HIGH transition
    PORTB = PORTB | 1;                   // Same as line below - but slightly faster
    // digitalWrite(8, HIGH);    
    // output pin is PortB0 (Arduino 8), sensor pin is PortB1 (Arduino 9)                                    

    while ((PINB & B10) != B10 ) {       // while the sense pin is not high
     //  while (digitalRead(9) != 1)     // same as above port manipulation above - only 20 times slower!                
     x++;
    }
    delay(1);

    //  HIGH-to-LOW transition
    PORTB = PORTB & 0xFE;                // Same as line below - but slightly faster
    //digitalWrite(8, LOW);              
    while((PINB & B10) != 0 ){           // while pin is not low  -- same as below only 20 times faster
     // while(digitalRead(9) != 0 )      // same as above port manipulation - only 20 times slower!
     y++;  
    }

    delay(1);
  }

  fout =  (fval * (float)x) + ((1-fval) * accum);  // Easy smoothing filter "fval" determines amount of new data in fout
  accum = fout;    

  Serial.print((long)x, DEC);    // raw data - Low to High
  Serial.print( "   ");
  Serial.print((long)y, DEC);    // raw data - High to Low
  Serial.print( "   ");
  Serial.println( (long)fout, DEC); // Smoothed Low to High
  
  if((long)fout > 3){
    analogWrite(4,255);
  } else {
    if((long)fout < 2){
      hit++;
      if(hit >= 3){
    analogWrite(4,0);
    hit = 0;
      }
    }
  }
  if((millis() - lastCount >= 75) && hit >= 1){
    hit = hit - 1;
    lastCount = millis();
  }
  Serial.println("___________________________________");
  Serial.print(hit, DEC);
  Serial.println("");
}