Author Topic: Improved Capacitive Touch Code  (Read 1454 times)

ChemE

  • Sr. Member
  • ****
  • Posts: 402
  • Country: us
Improved Capacitive Touch Code
« on: January 05, 2017, 10:00:07 AM »
I'm not sure there will be too much interest in this but it belongs here so I'm adding it to our repository.  One of my projects is LED under-cabinet lights and in a kitchen with messy hands I don't want to be touching things.  My favorite solution is to tape a strip of aluminum foil (could be copper tape) to the very bottom inside lip of the upper cabinets.  With things tuned properly, I can activate the sensor by placing the back of my hand or elbow or whatever on the outside of the cabinet.  This has the added benefit of making a sensor that is 12"x2" so I don't have to find a precise spot up underneath the cabinet which is a pain so why bother?

In a previous house I had just ripped off this code and sprinkled in a little bit of sleep here and there but basically ignored duty cycle since this is plugged into AC power.  Well, I've picked the code back up and tightened it up considerably with an eye towards keeping very high sensitivity while keeping duty cycle as low as possible.  I can now take 100 readings in 26ms and then sleep for 250ms and it feels as if the sensor is always active.  This is a vastly lower duty cycle than the default code and could be useful in battery scenarios with such a low duty cycle (should be able to squeeze 4 years from a pair of AAs with a low clock_div and no LDO).

Video of Code Running

Schematic and demo video from original page:





EDIT: Changed the LED pin to 9 to use the Moteino's LED and to avoid conflicts with the radio.  I was using pin 11 since I was developing on an UNO.

Code: [Select]
// If using a laptop, make sure it is plugged in as being on battery can result in *very* different timings!
//
// ======================================== USER-SET DEFINITIONS ========================================
#define   sPin                PD7    // 1MOhm resistor between sPin and rPin
#define   rPin                PD4    // 18pF capacitor between rPin and GND; Sensor connected to rPin
#define   TIME_OUT_MAX        350ul  // Set calls to 1 and this to 50,000 and observe the natural threshold, then set this to much less than natural
#define   CALLS               100    // At very short timeouts the number of calls needs to be increased
#define   THRESHOLD           0.92*CALLS*TIME_OUT_MAX    // At very short timeouts, the coefficient gets close to 1
#define   LOOP_DELAY          250        // in ms
#define   ON_INTENSITY        100    // LED brightness using PWM; select values between 0 and 255 - Must be on Pin 9
#define   DEBUG               0    // Toggle serial output on/off - Baud speed is 115,200 when on
//
// ================================= FAST PORT MANIPULATION DEFINITIONS =================================
#define   sPin_WRITE_HIGH     PORTD |= _BV(sPin)
#define   sPin_WRITE_LOW      PORTD &= ~_BV(sPin)
#define   rPin_MODE_INPUT     DDRD &= ~_BV(rPin)
#define   rPin_WRITE_LOW      PORTD &= ~_BV(rPin)
#define   rPin_READ           PIND & _BV(rPin)
// ======================================================================================================

static inline unsigned long SenseOneCycle(void) {
  uint16_t total=0;
 
  rPin_WRITE_LOW;    // Measure low-to-high transition
  sPin_WRITE_HIGH;
  while (!(rPin_READ) && (total<TIME_OUT_MAX)) total++;
  if (total>TIME_OUT_MAX) return TIME_OUT_MAX;
   
  rPin_WRITE_LOW;  // Measure high-to-low transition
  sPin_WRITE_LOW;
  while (rPin_READ && total<TIME_OUT_MAX) total++;
  return total;
}

int main(void) {  // =============== Setup code goes here ===============
  rPin_MODE_INPUT;
  interrupts();
  DDRB |= _BV(PB1);  // Allow pin 9 to control the LED's brightness 
 
  // Timer 0 initialization from wiring.c for a ATmega 328P (Arduino Uno rev 3) + 12 bytes to sketch size
  TCCR0A = _BV(WGM01) | _BV(WGM00);     // set timer 0 prescale factor to 64
  TCCR0B = _BV(CS01) | _BV(CS00);       // set timer 0 prescale factor to 64
 
  // Timer 1 initialization from wiring.c for an ATmega 328P (Arduino Uno rev 3) + 12 bytes to sketch size
  TCCR1A = _BV(COM2A1) | _BV(WGM20);    // Enable timer 2 to _delay_ms() works properly
  TCCR1B = _BV(CS22);                   // set clkT2S/64 (From prescaler)

  #if DEBUG    // Initialize the UART if DEBUGging
    uint16_t start, elapsed;
    TIMSK0 = _BV(TOIE0);                 // enable timer 0 overflow interrupt
    Serial.begin(115200);
  #endif
 
  for (;;) {  // =================================== Loop Forever ===================================
    uint16_t total=0;
    #if DEBUG
      start = micros();
    #endif
   
    total = 0;
    for (uint8_t i=0; i<CALLS; i++) total += SenseOneCycle();  // Make successive quick calls and display the total
    OCR1A = (total<THRESHOLD) ? ON_INTENSITY : 0;  // Set the LED's brightness based on total (using macro expansion)
   
    #if DEBUG
      Serial.print(total);
      Serial.print("\t\tCycle took ");
      elapsed = micros() - start;
      Serial.print(elapsed);
      Serial.print(" us\n");
    #endif
    _delay_ms(LOOP_DELAY);
  }    // =================================== End Loop Forever ===================================
}
« Last Edit: January 05, 2017, 12:52:30 PM by ChemE »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 5994
  • Country: us
    • LowPowerLab
Re: Improved Capacitive Touch Code
« Reply #1 on: January 05, 2017, 11:22:32 AM »
ChemE,

Thank you very much for sharing this, it's very much welcome since I was planning to do a color LED strip project in the kitchen sometime!

FWIW I added the schematic and video from the original source to your post.

ChemE

  • Sr. Member
  • ****
  • Posts: 402
  • Country: us
Re: Improved Capacitive Touch Code
« Reply #2 on: January 05, 2017, 12:13:26 PM »
Glad you may find it useful Felix.  I also added a quick video of my posted code running on a Moteino which also shows the example circuit using an 18pF capacitor and a 1MOhm resistor.

vincenet

  • Newbie
  • *
  • Posts: 2
  • Country: fr
Re: Improved Capacitive Touch Code
« Reply #3 on: March 10, 2017, 05:05:47 AM »
Hello,
Nice project.
Have you got some measurement of consumption ?
I ordered moteino boards to play with a mpr121 breakout board. It is a proximity capacitive touch sensor controller that draw only 11uA @ 256 ms response time for the 12 inputs (if my understanding is correct selecting 64ms sampling period and 4 samples). The shame is mpr121 become hard to buy. I also see Jeelabs sell a breakout with mpr084 chip with 8 inputs and maybe more consumption but the chip is still available.
My goal is to design a rf piano.
I will try to use 3 saft LS14500 Lithium-Thionyl Chloride (Li-SOCI 2) cells (3x2200mAh) as it is outdoor application with many push and I hope to reach 2 years before replacement.
Next step for me will be to measure small currents to estimate battery life.
Regards,
Vincent
« Last Edit: March 10, 2017, 05:15:31 AM by vincenet »

WhiteHare

  • Hero Member
  • *****
  • Posts: 1298
  • Country: us
Re: Improved Capacitive Touch Code
« Reply #4 on: March 10, 2017, 06:49:01 AM »
Vincent,
For the proximity detector, how close do you need to get before it detects you?  At our house, we have a touch sensor water faucet in our kitchen (our model is called "Touch2O," not homemade), but upgrading it to turn on/off based on proximity detection to the surface would be even better.  My wife wanted it, and although I was skeptical about how useful it would be when we bought it, I'm sold on the idea now.  It really is a nice feature!  We've been using it now for 7 years.  When it's something you use everyday all the time, upgrades can be really worth it.
« Last Edit: March 10, 2017, 07:06:15 AM by WhiteHare »

vincenet

  • Newbie
  • *
  • Posts: 2
  • Country: fr
Re: Improved Capacitive Touch Code
« Reply #5 on: March 10, 2017, 07:08:37 AM »
I need to detect to about 5 cm from the sensor but I am not worry concerning this requirement.