Capacitive sensing, part 2

The obvious next step with the capacitive sensor is to make the sensor actually control something.  This is not essential for the circuits class—for that class it is better to have the students viewing the waveform on the oscilloscope and seeing the frequency of the output vary  as the touch varies.  But I was curious about whether the various grounds (oscilloscope, USB cable, wall wart power supply) were making a difference to the capacitive sensing, so I wanted to redo the capacitive sensor to be a fully battery-based application, with no external ground connections.

To display whether the sensor had been touched or not, I turned on or off the LED on pin 13. I used the same software detection mechanism as in the previous post, counting the number of pulses it takes to get a total time for the signal being low. Touching my laptop (to reduce the resistance to ground) no longer makes a difference in the sensitivity of the switch, now that the battery ground is separated from the laptop ground.

// Capacitive sensor switch
// Mon Jul  9 06:05:54 PDT 2012 Kevin Karplus

// To use, connect the output of the LM555 oscillator to
// pin CAP_PIN on the Arduino.
// The code turns on the LED on pin 13 when a touch is sensed.

// The Arduino measures the number and width of LOW pulses on pin 2 until
//    the sum of the pulse width exceeds TOTAL_PULSE_USEC.
// The LED is turned on if the number of pulses is less than NO_TOUCH_NUM

#define CAP_PIN (2)

#define TOTAL_PULSE_USEC (100)	// total of pulse widths (in  microseconds) before reporting
#define NO_TOUCH_NUM (50)

void setup(void)
{
    pinMode(CAP_PIN,INPUT);
    pinMode(13, OUTPUT);
}

void loop(void)
{
    uint32_t pulse_sum=0;
    uint16_t num_pulses=0;
    while (pulse_sum<TOTAL_PULSE_USEC)
    {   pulse_sum += pulseIn(CAP_PIN,LOW);
        num_pulses++;
    }
    digitalWrite(13, (num_pulses<NO_TOUCH_NUM? HIGH:LOW));
}

I had to set the threshold a bit higher than I expected, indicating that the frequency shift was not as large without all the connections to ground, but the sensor still works with a moderately firm touch. With a light touch, the LED flickers on and off, indicating that the frequency shift is near the threshold. Raising NO_TOUCH_NUM too high has the LED always on. Even raising it from 50 to 55 makes the switch too sensitive—the LED turns on when my finger is still 5mm away from contact. Perhaps the ideal setting is 52, as that detects a light touch fairly reliably, but doesn’t fire until my finger is within about 1mm of the surface.

Note: it might make more sense to leave NO_TOUCH_NUM at 50 and adjust TOTAL_PULSE_USEC down to 96, since the larger number can be adjusted more finely.

If I wanted to avoid the flicker, I would debounce the detection.  I can’t use the Arduino Bounce library for this, as the signal that needs debouncing is in software, not on a pin.  It is a trivial matter to add a delay whenever the output changes, though:

// Capacitive sensor switch
// Mon Jul  9 06:44:33 PDT 2012 Kevin Karplus

// To use, connect the output of the LM555 oscillator to
// pin CAP_PIN on the Arduino.
// The code turns on the LED on pin 13 when a touch is sensed.

// The Arduino measures the number and width of LOW pulses on pin 2 until
//    the sum of the pulse width exceeds TOTAL_PULSE_USEC.
// The LED is turned on if the number of pulses is less than NO_TOUCH_NUM.

// pin that LM555 output connected to
#define CAP_PIN (2)

// total of pulse widths (in  microseconds) before reporting
#define TOTAL_PULSE_USEC (96)

// minimum number of pulses to indicate that sensor is not touched
#define NO_TOUCH_NUM (50)

// time (in milliseconds) to wait after a change in state before
// testing input again
#define DEBOUNCE_MSEC (100)

static uint8_t was_on;

void setup(void)
{
    was_on=0;
    pinMode(CAP_PIN,INPUT);
    pinMode(13, OUTPUT);
}

void loop(void)
{
    uint32_t pulse_sum=0;
    uint16_t num_pulses=0;
    while (pulse_sum<TOTAL_PULSE_USEC)
    {   pulse_sum += pulseIn(CAP_PIN,LOW);
        num_pulses++;
    }
    uint8_t on = num_pulses<NO_TOUCH_NUM? 1:0;
    digitalWrite(13, on);
    if (on!=was_on)
    {   delay(DEBOUNCE_MSEC);
        was_on=on;
    }
}

Debouncing does not completely eliminate multiple flashes. If I hold my finger very steady just touching the sensor or my whole hand flat about 1mm away, the LED will flash on and off about 5 times a second (the speed of the flashing is determined mainly by DEBOUNCE_MSEC).

Really good code would not require fixed NO_TOUCH_NUM and TOTAL_PULSE_USEC, but would learn what values are usual for off and on states and set the thresholds to separate them reliably.  I’ve not figured out a good way to do this as unsupervised learning. It would not be very difficult to have initial settings, gather averages for on and off states, then dynamically adjust the threshold, but I don’t know how stable such threshold setting would be. I suspect that it would end up rather unreliable, and highly dependent on good initial settings.


Filed under: Circuits course Tagged: Arduino, bioengineering, capacitive touch sensor, circuits, course design, LM555, sensors, teaching

[original story: Gas station without pumps]