CapSense (QTouchADC): Difference between revisions

From SGMK-SSAM-WIKI
Jump to navigation Jump to search
Line 2: Line 2:


This is another CapSense implementation that tries to follow the specifications of Atmels QTouchADC, a version of QTouch that uses the internal Sample & Hold capacitor of the ADC. No external capacitor is needed anymore!
This is another CapSense implementation that tries to follow the specifications of Atmels QTouchADC, a version of QTouch that uses the internal Sample & Hold capacitor of the ADC. No external capacitor is needed anymore!
To make the measurement more stable I used transistors to drive the LEDs (somehow it works much better when there is less current through the chip), and it is recommended to use a stable power source (batteries or add an aditional capacitor between 5V and GND).


[[File:QTouchADC.jpg]]
[[File:QTouchADC.jpg]]
[[File:QTouchADC-schematic.jpg]]
[[File:QTouchADC-schematic.jpg]]


Some links and a video go here soon...
Some links and a video will come soon...


= Snippet =
= Snippet =

Revision as of 00:41, 2 January 2014

Information

This is another CapSense implementation that tries to follow the specifications of Atmels QTouchADC, a version of QTouch that uses the internal Sample & Hold capacitor of the ADC. No external capacitor is needed anymore!

To make the measurement more stable I used transistors to drive the LEDs (somehow it works much better when there is less current through the chip), and it is recommended to use a stable power source (batteries or add an aditional capacitor between 5V and GND).

Some links and a video will come soon...

Snippet

/*
 NC      1   8   +5V
 KEY0    2   7   NC
 KEY1    3   6   LAMP PWM2
 GND     4   5   LAMP PWM1
 
 */

#include <avr/io.h>
#include <avr/delay.h>


//------------------------------------------------------------------------------------------------------------

void init(){
    // ADC
    //DDRB=(0<<PB2)|(0<<PB3)|(0<<PB4); //inputs of ADC-Sensor and ADC-Reference
    ADMUX = (0<<REFS0); //REFS0=0:VCC reference, =1:internal reference 1.1V
    // ADMUX = (0<<REFS0) | (0x00); right two bits select ADC-pin
    ADCSRA = (1<<ADEN)| (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //ADC enable, prescaler 128
 
    // PWM
	DDRB |= (1<<PB0)|(1<<PB1); // PWM-outputs
	// initiate timer for PWM and Timer Overflow Interrupt
	// 8000000/256/8= 3906.25Hz = PWM-rate and OVF-interrupt-rate; 8000000/256=31250Hz
	TCCR0A = (1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00); // fast PWM
	TCCR0B = (1<<CS02); // counter clock divider: 256
	OCR0A = 255;
    OCR0B = 255;
}

// pre: input PB3 (ADC3) and PB4 (ADC2). PB2 (ADC1) is used as reference, PB0 and PB1 for PWM
uint16_t sensePad(uint8_t adcPin){
    int16_t measurement1, measurement2;
    uint8_t portPin;
    if (adcPin == 3) {
        portPin = PB3;
    } else {
        portPin = PB4;
    }

    // first measurement: adcPin low, S/H high
    ADMUX = (0<<REFS0) | 0x01; // set ADC sample+hold condenser to the free PB2 (ADC1) 

    PORTB |= (1<<PB2); //PB2/ADC1 ref/ S/H higt (pullup or output, doesn't matter)
    DDRB |= (1<<portPin) | (1<<PB2); // both output: adcPin low, S/H (ADC1) high
    _delay_us(32);
    DDRB &= ~((1<<portPin) | (1<<PB2));
    PORTB &= ~((1<<portPin) | (1<<PB2));

    ADMUX = (0<<REFS0) | (adcPin & 0x03); // read C-extern from adcPin
    ADCSRA |= (1<<ADSC); // start conversion
    while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
    ADCSRA |= (1 << ADIF); // clear ADCIF
    measurement1=ADC;

    // second measurement: adcPin high, S/H low
    ADMUX = (0<<REFS0) | 0x01; // set ADC sample+hold condenser to the free PB2 (ADC1)

    PORTB |= (1<<portPin); // sensePad/adcPin high
    DDRB |= (1<<portPin) | (1<<PB2); // both output: adcPin high, S/H (ADC1) low
    _delay_us(32);
    DDRB &= ~((1<<portPin) | (1<<PB2));
    PORTB &= ~((1<<portPin) | (1<<PB2));

    ADMUX = (0<<REFS0) | (adcPin & 0x03); // read C-extern from adcPin
    ADCSRA |= (1<<ADSC); // start conversion
    while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
    ADCSRA |= (1 << ADIF); // clear ADCIF
    measurement2=ADC;


    return (measurement2 - measurement1)+1023;
}

uint8_t getMultiplicator(int16_t value, uint16_t maxValue){
    if (maxValue<64){
        value=value*4;
    } else if (maxValue < 86){
        value= value*3;
    } else if (maxValue < 103) {
        value = (value/2)*5;
    } else if (maxValue<128){
        value=value*2;
    } else if (maxValue < 154){
        value = (value/3)*5;
    } else if (maxValue<171){
        value = (value/2)*3;
    } else if (maxValue<205){
        value = (value/4)*5;
    } else {
        value=(value/5)*4;
    }
    return value;
}

//------------------------------------------------------------------------------------------------------------
int main(void) {
	init();
	int16_t senseValue1, senseValue2;
    int16_t refMin1, refMin2;
    uint16_t refMax1, refMax2;
    refMin1 = sensePad(2);
    refMin1 = sensePad(2);
    refMin2 = sensePad(3);
    refMin2 = sensePad(3);

    for(;;){
        PORTB &= ~(1<<PB3);

        senseValue1 = sensePad(2);
        senseValue1 = senseValue1 - refMin1;
        if (senseValue1<0){
            senseValue1=0;
        }
        if (senseValue1>refMax1) {
            refMax1=senseValue1;
        }
        senseValue1 = getMultiplicator((uint8_t) senseValue1, refMax1);

        senseValue2 = sensePad(3);
        senseValue2 = senseValue2 - refMin2;
        if (senseValue2<0){
            senseValue2=0;
        }
        if (senseValue2>refMax2) {
            refMax2=senseValue2;
        }
        senseValue2 = getMultiplicator((uint8_t) senseValue2, refMax2);

        OCR0B = senseValue1;
        OCR0A = senseValue2;
        
    }
    return 0;   /* never reached */
}