The CTMU module available on some newer PIC18 chips is a bag full of tricks.
http://ww1.microchip.com/downloads/en/AppNotes/01375a.pdf
This simple C18 PIC18F46K22 demo only uses the capacitive touch function to read a single touch pad, return a button pressed flag and a proximity value.
First image:
The basic application is in this Microchip app-note.
http://ww1.microchip.com/downloads/en/AppNotes/01250a.pdf
This version uses timer0 interrupts instead of delay loops and the ADC interrupt to signal the conversion so it runs as a background process updating a 'button pressed' flag and result variables.
Device setup:
isr code (with debug code flags and leds on outputs) :
Timer0 is set to send a interrupt when the count is done, a small 'charge' value is set/counter started and the CTMU constant current device is enabled. When the timer0 interrupt happens the CTMU current device is stopped and a ADC conversion to read the touch-pad/finger capacitor charge voltage value is started. The ADC has been configured to send a interrupt when the conversion is done. The ADC section of the ISR code reads the ADC value, sets the CTMU discharge flag, shorts the touch-pad ADC input to ground to zero the voltage and sets timer0 again with a longer 'discharge' value. When timer0 again sends a interrupt the ISR looks at the CTMU discharge flag, opens the ground to the touch-pad and reloads timer0 with the 'charge' value and enables the current device again to restart the process.
The o-scope trace below explains the sequence.
Second image:
The demo 'rgbled template code' just reads the touch-pad values and flashes the random RGB outputs as the pad is touched. I'll post a few pictures later.
http://ww1.microchip.com/downloads/en/AppNotes/01375a.pdf
This simple C18 PIC18F46K22 demo only uses the capacitive touch function to read a single touch pad, return a button pressed flag and a proximity value.
First image:
The basic application is in this Microchip app-note.
http://ww1.microchip.com/downloads/en/AppNotes/01250a.pdf
This version uses timer0 interrupts instead of delay loops and the ADC interrupt to signal the conversion so it runs as a background process updating a 'button pressed' flag and result variables.
Device setup:
Rich (BB code):
int ctmu_setup(unsigned char current)
{
//CTMUCONH/1 - CTMU Control registers
CTMUCONH = 0x00; //make sure CTMU is disabled
CTMUCONL = 0x90;
//CTMU continues to run when emulator is stopped,CTMU continues
//to run in idle mode,Time Generation mode disabled, Edges are blocked
//No edge sequence order, Analog current source not grounded, trigger
//output disabled, Edge2 polarity = positive level, Edge2 source =
//source 0, Edge1 polarity = positive level, Edge1 source = source 0,
//CTMUICON - CTMU Current Control Register
CTMUICON = 0x01; //.55uA, Nominal - No Adjustment default
charge_time=TIMERCHARGE_BASE; // slower
if (current == 0x02) {
CTMUICON = 0x02; //5.5uA, Nominal - No Adjustment
charge_time=TIMERCHARGE_BASE_X10; // faster
}
/**************************************************************************/
//Set up AD converter;
/**************************************************************************/
// Configure AN0 as an analog channel
ANSELAbits.ANSA0=1;
TRISAbits.TRISA0=1;
// ADCON2
ADCON2bits.ADFM=1; // Results format 1= Right justified
ADCON2bits.ACQT=1; // Acquition time 7 = 20TAD 2 = 4TAD 1=2TAD
ADCON2bits.ADCS=2; // Clock conversion bits 6= FOSC/64 2=FOSC/32
// ADCON1
ADCON1bits.PVCFG0 =0; // Vref+ = AVdd
ADCON1bits.NVCFG1 =0; // Vref- = AVss
// ADCON0
ADCON0bits.CHS=0; // Select ADC channel
ADCON0bits.ADON=1; // Turn on ADC
PIE1bits.ADIE=1; // enable ADC int
return 0;
}
Rich (BB code):
#pragma interrupt high_handler
void high_handler (void)
{
if ( INTCONbits.TMR0IF ) { // check timer0 irq
if (!CTMUCONHbits.IDISSEN) { // charge cycle timer0 int, because not shorting the CTMU voltage.
CTMUCONLbits.EDG1STAT = 0; // Stop charging touch circuit
TIME_CHARGE=FALSE; // clear charging flag
CTMU_WORKING=TRUE; // set working flag, doing touch ADC conversion
// configure ADC for next reading
ADCON0bits.CHS=0; // Select ADC channel
ADCON0bits.ADON=1; // Turn on ADC
ADCON0bits.GO=1; // and begin A/D conv, will set adc int flag when done.
// LATCbits.LATC7=!LATCbits.LATC7; // blink led
} else { // discharge cycle timer0 int, because CTMU voltage is shorted
// LATCbits.LATC6=!LATCbits.LATC6; // blink led
CTMUCONHbits.IDISSEN = 0; // end drain of touch circuit
TIME_CHARGE=TRUE; // set charging flag
CTMU_WORKING=TRUE; // set working flag, doing
WriteTimer0 ( charge_time ); // set timer to charge rate time
CTMUCONLbits.EDG1STAT = 1; // Begin charging the touch circuit
}
// clr TMR0 int flag
INTCONbits.TMR0IF = 0; //clear interrupt flag
}
if (PIR1bits.ADIF) { // check ADC irq
PIR1bits.ADIF = 0; // clear ADC int flag
// LATCbits.LATC5=!LATCbits.LATC5; // blink led
Vread = ADRES; // Get the value from the A/D
Vread= (Vread >>3)&0x007f; // toss lower bit noise and mask
if(Vread < (touch_base - TRIP)) { // see if we have a pressed button
switchState = PRESSED;
LATCbits.LATC4=OFF;
} else if(Vread > (touch_base - TRIP + HYST)) {
switchState = UNPRESSED;
LATCbits.LATC4=ON;
}
CTMU_ADC_UPDATED=TRUE; // New data is in Vread, set to FALSE in main program flow
CTMU_WORKING=FALSE; // clear working flag, ok to read Vread.
// config CTMU for next reading
CTMUCONHbits.CTMUEN = 1; // Enable the CTMU
CTMUCONLbits.EDG1STAT = 0; // Set Edge status bits to zero
CTMUCONLbits.EDG2STAT = 0;
CTMUCONHbits.IDISSEN = 1; // drain charge on the circuit
WriteTimer0 ( TIMERDISCHARGE ); // set timer to discharge rate
}
if ( PIR1bits.TMR2IF ) {
PIR1bits.TMR2IF = 0; // clear TMR2 int flag
}
}
The o-scope trace below explains the sequence.
Second image:
The demo 'rgbled template code' just reads the touch-pad values and flashes the random RGB outputs as the pad is touched. I'll post a few pictures later.
Attachments
-
25.3 KB Views: 173
-
133.6 KB Views: 162
-
26.1 KB Views: 179
Last edited: