Launchpad Capacitive Sensing

来源:互联网 发布:sql默认实例 编辑:程序博客网 时间:2024/05/24 06:48

Here’s a demo of capacitive proximity sensing on the TI Launchpad. I’m hoping to use this in a project I’m planning.

The circuit (below), uses a 1M resistor and (optionally) a small (<100pF) capacitor connected between ground and a port pin (P1.7). The tin-foil acts as a capacitor. When your body comes near or into contact, the capacitance increases. If your Launchpad isn’t grounded (ie. running from battery power), add a second foil to ground and move your hand between them.

I’ve found that when using a small capacitor alongside the foil I see less background noise.

circuit

By charging the capacitor then timing the discharge with a known resistance, we can determine the capacitance.

t = RC

Several cycles are shown on the trace below. To charge the capacitor, a port pin is driven high (set to an output and set high). A timer is then started and the pin is set to an input with an interupt enabled to detect a high to low edge. The capacitor discharges via the 1M resistor. Once the voltage drops below the input threshold for the pin, the timer is stopped.

scope

In order to detect a meaningful change in capacitance, it’s necessary to filter the values. The background noise is sampled for 1s on startup (pressing the Launchpad button also recalibrates). For a discharge time to indicate a touch, it must exceed the maximum found in the calibration period.

Once a touch is detected, the onboard LED is lit. It’s then turned off a short time later by the tick.

Download source and Makefile.

Source code:

#include <io.h>#include <signal.h>#include <stdbool.h> /****************************************************/ #define     SWITCH_BIT            BIT3  // Launchpad switch on P1.3#define     LED_BIT               BIT0  // Launchpad LED on P1.0#define     CAP_BIT               BIT7  // RC circuit on P1.7 /****************************************************/ // WDT Timer providing a system tick#define TICKS_PER_SEC (1000/32) // Time to sample background noise level#define SAMPLING_PERIOD (TICKS_PER_SEC * 1) /****************************************************/ typedef enum{    TRIGGER_RECALIBRATE,  // start sampling background noise level    TRIGGER_SAMPLING,     // sampling background noise    TRIGGER_RUNNING,      // running normally} state_t; static state_t state = TRIGGER_RECALIBRATE;       // trigger statestatic uint32_t min_sample;         // low noise valuestatic uint32_t max_sample;         // high noise valuestatic uint32_t sampling_timeout;   // tick counter for stopping sampling (SAMPLING_PERIOD) /****************************************************/ static volatile uint32_t sys_ticks = 0; // global tick counter static volatile uint32_t rc_discharge_time = 0; // last discharge timestatic volatile bool measuring = false;         // is discharge being measured /****************************************************/ static void cpu_init(void){    // configure watchdog timer as 32ms interval timer    IFG1 &=~WDTIFG;    IE1 &=~WDTIE;    WDTCTL = WDTPW + WDTHOLD;    WDTCTL = WDT_MDLY_32;    IE1 |= WDTIE;     // configure system clock    BCSCTL1 = CALBC1_1MHZ; // Set range    DCOCTL = CALDCO_1MHZ; // SMCLK = DCO = 1MHz} // Watchdog interval timerinterrupt(WDT_VECTOR) WDT_ISR(void){    sys_ticks++;}  // Port1 ISRinterrupt(PORT1_VECTOR) P1_ISR(void){    uint32_t tar = TAR; // store TAR as early as possible     if((P1IFG & CAP_BIT) == CAP_BIT)    // cap discharged    {        rc_discharge_time = tar - rc_discharge_time;        measuring = false;        P1IE &= ~CAP_BIT;    // interrupt disable    }    else    if((P1IFG & SWITCH_BIT) == SWITCH_BIT)    // switch pressed    {        state = TRIGGER_RECALIBRATE;    }     P1IFG = 0x00;   // clear interrupt flags} // wait a short time (for cap to charge)void wait(void){    volatile int i;    for(i=0;i<32;i++);} // test if an RC discharge time looks like a trigger or notstatic bool isTrigger(uint32_t sample){    switch(state)    {        case TRIGGER_RECALIBRATE:            // Sample background noise for SAMPLING_PERIOD            sampling_timeout = sys_ticks + SAMPLING_PERIOD;            min_sample = 0xFFFFFFFF;            max_sample = 0x00000000;            state = TRIGGER_SAMPLING;         // DROP THROUGH         case TRIGGER_SAMPLING:            if (sample < min_sample)                min_sample = sample-1;            if (sample > max_sample)                max_sample = sample+1;             if (sys_ticks >= sampling_timeout)  // sampling time over                state = TRIGGER_RUNNING;        break;         case TRIGGER_RUNNING:            if (sample < min_sample)                state = TRIGGER_RECALIBRATE;     // the environment has changed, recalibrate            else            {                if (sample > max_sample)                    return true;            }        break;    }     return false;} // Begin measuring RC discharge timestatic void start_measuring(void){    measuring = true;     // SMCLK continuous    TACTL = TASSEL_2 | MC_2;    TACCR0 = 0x00;     // drive capacitor high, charge it up    P1DIR |= CAP_BIT;    P1OUT |= CAP_BIT;    wait(); // wait for cap to charge     // store start count    TAR = 0;    rc_discharge_time = TAR;     // interrupt when capacitor drops below pin's "high" voltage    P1IES |= CAP_BIT;   // interrupt on hi to lo edge    P1IE |= CAP_BIT;    // interrupt enable     // flip pin to input, capacitor will begin discharging    P1DIR &= ~CAP_BIT; // set to input} int main(void){    uint32_t led_timer = 0; // timed latch for LED     cpu_init();     // setup LED pins    P1DIR |= LED_BIT;   // All LED pins as outputs    P1OUT &= ~LED_BIT;  // Turn off LED     // setup switch interrupt    P1DIR &= ~SWITCH_BIT;  // as input    P1IES |= 0x01;          // interrupt on falling edge    P1IE |= SWITCH_BIT;    // interrupt enable     // start measuring discharge time    start_measuring();    eint();     while(1)    {        if (!measuring)        {            // test discharge time to see if it looks like a trigger            if (isTrigger(rc_discharge_time))            {                P1OUT |= LED_BIT;       // turn on LED                led_timer = sys_ticks;  // record current time            }            start_measuring();  // measure again        }        // if 0.5s has elapsed since trigger, turn off LED        if (led_timer != 0 && sys_ticks > led_timer + (TICKS_PER_SEC/2))        {            P1OUT &= ~LED_BIT;          // turn off LED            led_timer = 0;              // clear timer        }    }}

Makefile:

TARGET=captouch CC=msp430-gccSIZE=msp430-sizeSTRIP=msp430-strip CFLAGS=-Os -Wall -g -mmcu=msp430x2013 -ffunction-sections -fdata-sections -fno-inline-small-functions LDFLAGS = -Wl,-Map=$(TARGET).map,--crefLDFLAGS += -Wl,--relaxLDFLAGS += -Wl,--gc-sections OBJS=$(TARGET).o all: $(TARGET).elf $(TARGET).elf: $(OBJS)$(CC) $(CFLAGS) -o $(TARGET).elf $(OBJS) $(LDFLAGS)$(STRIP) $(TARGET).elf$(SIZE) --format=sysv $(TARGET).elf program: $(TARGET).elfmspdebug rf2500 "prog $(TARGET).elf" %.o: %.c$(CC) $(CFLAGS) -c $&lt; clean:rm -rf $(TARGET).elf $(OBJS) $(TARGET).map
原创粉丝点击