CapSense (QTouchADC)
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! Just make some small sensor pads, or even sliders and wheels (see Atmel Design referece).
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 additional capacitor between 5V and GND).
Not like in the pseudo schematic, there should be a 1k Ohm resistor between the microcontroller an the sensor pad!
{{#widget:Vimeo|id=83185877}}
QTouchADC Library for Arduino
forked from jgeisler0303 on Github
dusjagr converted the code from jgeisler0303 into a library "QTouchADCduino" and tested it again and again.
download here: https://github.com/dusjagr/QTouchADCArduino
It's the first time I tried to write a library, so please don't be too hard on me :-)
More examples
see Hackteria Wiki for some Fruit-Synthesizers
Notes on the QTouchADC library
Overview and functionalities
- up to 5 touch sensors can be attached to the AnalogIn pins, one is reserved as referencePin
- allows averaging over many measurements
- reading is very fast, ca 150µs for 1 reading. Averaging will increase to measurement time
- baseline is stable, especially if it runs alone and on battery.
- when the arduino is plugged into a laptop that is on the mains power, noise increases a lot and the measurement is very succeptible to how your body is connected to the room.
Still needs to be checked / optimized
- playing around with the CHARGE_DELAY and TRANSFER_DELAY (in the library) impacts the noise. needs optimization
- do the reference measurement in the .init? how to use that result in the other part of the library?
Example measurements and tests
Usage
QTouchADCduino.init();
// initializez the analog registers. put it in the void setup() of your code.
QTouchADCduino.sense("sensePin", "refPin", "samples");
//this will give you back the result comparing the ADC measurements from the reference pin and the sensepin, and it will take a number "samples" of measurement and averages them. The resulting difference might go from a negative number to positive, up to values of 600-700 when touched.
A single and averaged reference measurement during the void setup() can be later substracted from the measured values to create positive values only.
Code Example
find more examples on github
#include <QTouchADCduino.h> void setup() { Serial.begin(9600); QTouchADCduino.init(); int ref1 = QTouchADCduino.sense(0, 1, 64); } void loop() { int value1 = (QTouchADCduino.sense(0, 1, 16) - ref1); Serial.println(value1); delay(10); }
Links
More on QTouchADC
discussion on mikrocontroller.net
How to make Buttons, Sliders and Wheels
Nice description and implementation on ATMega32u4
https://www.youtube.com/watch?v=Ncu2GZJbluI
http://playground.arduino.cc/Code/ADCTouch
QTouch on Attiny and Arduino
Very smoothly working implementation for Arduino ->> can someone translate it to the attiny register-ports? (dusjagr tried and failed...) or even make it into a library?
Library for Arduino for ADC Touch, noisy...
TinyTouch library for attiny (I can't get this to run from the arduino IDE), looks very nice!!!
Programming the attiny85 with arduino IDE
Code for attiny85 - Urban
/* 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 ADMUX = (0<<REFS0); //VCC reference ADCSRA = (1<<ADEN)| (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //ADC enable, prescaler 128 // PWM DDRB |= (1<<PB0)|(1<<PB1); // PWM-outputs 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 condensator to the free PB2 (ADC1) PORTB |= (1<<PB2); //PB2/ADC1 ref/ S/H higt 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 extern condensator from adcPin ADCSRA |= (1<<ADSC); // start conversion while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete ADCSRA |= (1 << ADIF); // clear ADIF measurement1=ADC; // second measurement: adcPin high, S/H low ADMUX = (0<<REFS0) | 0x01; // set ADC sample+hold condensator 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 extern condensator 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 */ }