//****************************************************************************** // Software License Agreement // // The software supplied herewith by Microchip Technology // Incorporated (the "Company") is intended and supplied to you, the // Company’s customer, for use solely and exclusively on Microchip // products. The software is owned by the Company and/or its supplier, // and is protected under applicable copyright laws. All rights are // reserved. Any use in violation of the foregoing restrictions may // subject the user to criminal sanctions under applicable laws, as // well as to civil liability for the breach of the terms and // conditions of this license. // // THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, // WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED // TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, // IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR // CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. // //****************************************************************************** // ***************************************************************************** // Filename: Main727.c // Date: Dec. 13, 2007 // Purpose: Illustrate the use of the Capacitive Sensing Module // This program scans 16 pads on a PCB. Each pad is sensed by the Capacitive // Sensing Module at a fixed interval. The frequency of each pad at rest is averaged.l // When a pad is touched, the frequency on the Cap. sensing module changes due to the // extra capacitance from the finger. The change in frequency is noted and the LEDs // light up to indicate which button was pressed. // ***************************************************************************** // // Compiler: Hi-Tech PIC-C v.9.60 // ***************************************************************************** #include #include "Cap_Sense.h" #define METHOD 4 // 1= Timer0 Base; 2= Timer2 Base; 3= WDT base; 4=WDT Sleep Base #if METHOD == 4 __CONFIG(INTIO & WDTEN & PWRTEN & MCLRDIS & UNPROTECT); #else __CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & UNPROTECT); #endif /** Variables **/ bank1 unsigned int reading[NUM_BTTNS]; // current reading for each button bank1 unsigned int average[NUM_BTTNS]; // running average for each button bank1 unsigned int threshold; // threshold value is req'd # counts decrease from avg unsigned char index; // index value relates ea. button and scanning sequence bank2 unsigned int threshold128; // Threshold of 1/128th = 1/128th of the average value bank2 unsigned int threshold64; // ... used in computation of threshold variable bank2 unsigned int threshold32; // ... threshold is a selection of the sum of these bank2 unsigned int threshold16; // " bank2 unsigned int threshold8; // " bank2 unsigned int threshold4; // " bank2 unsigned int threshold2; // Threshold value for 1/2 FFlags Flags; // Flags struct variable contains application status BButtons Buttons; // Buttons struct variable indicates button presses unsigned int bigval; // current button bigval - for averaging technique unsigned int smallavg; // current button smallavg - for averaging technique /** Constants **/ /** Prototypes **/ void Init(void); void RestartTimers(void); void RestartTimer1(void); void SetNextChannel(void); void CapInit(void); void DisplayLEDs(char i); void interrupt isr(void); void SLEEP_NOP(void); /*==================================================================== ======================== PROGRAM CODE ============================== ====================================================================*/ //********************************************************************* // main() ************************************************************ // Main loop. Will turn on the LEDs based on button detected during** // ISR execution. *********************************************** // ******************************************************************** void main(void) { Init(); // unsigned int x; // // while(1) // { // CLRWDT(); // // while (x < 60000) // { // x++; // } // // LED0 = ON; // // x = 0; // // while (x < 60000) // { // x++; // } // // LED0 = OFF; // LED1 = ON; // // x = 0; // // while (x < 60000) // { // x++; // } // // LED1 = OFF; // } index = 0; // Begin program scanning channel 0 while (1) { // Loop forever // React to button presses in application main-loop if (Buttons.BTN0) LED0 = ON;//DisplayLEDs(0); // Structuring code based off each button takes up if (Buttons.BTN1) // more application code, but reduces isr code. LED1 = ON;//DisplayLEDs(1); // It also allows reaction to different buttons at if (Buttons.BTN2) // the same time. DisplayLEDs(2); if (Buttons.BTN3) // ALTERNATIVE: DisplayLEDs(3); // For ea. case in the isr, create and set a variable if (Buttons.BTN4) // called 'button_pressed' s.t. button_pressed=index. DisplayLEDs(4); // Then, main loop code would simply require: /* if (Buttons.BTN5) // DisplayLEDs(button_pressed); DisplayLEDs(5); if (Buttons.BTN6) DisplayLEDs(6); if (Buttons.BTN7) DisplayLEDs(7); if (Buttons.BTN8) DisplayLEDs(8); if (Buttons.BTN9) DisplayLEDs(9); if (Buttons.BTN10) DisplayLEDs(10); if (Buttons.BTN11) DisplayLEDs(11); if (Buttons.BTN12) DisplayLEDs(12); if (Buttons.BTN13) DisplayLEDs(13); if (Buttons.BTN14) DisplayLEDs(14); if (Buttons.BTN15) DisplayLEDs(15); */ #if METHOD == 4 SLEEP_NOP(); #endif } } // ************************************************************************************ // Function: Init() ******************************************************************* // Purpose: Initialize PORTS, Capacitive Sensing Module and Selected Time Base // ************************************************************************************ void Init(void) { // ********************************************************************************* // PORT and LED Setup ************************************************************** //********************************************************************************** // Pin usage for this sample application //-------------------------------------------------------------------------- // 7 6 5 4 3 2 1 0 | // PORTA . . CPS7 CPS6 . . LED LED | // PORTB . . CPS5 CPS4 CPS3 CPS2 CPS1 CPS0 | // PORTC . . . . . . . . | // PORTD CPS15 CPS14 CPS13 CPS12 CPS11 CPS10 CPS9 CPS8 | // PORTE X X X X . LED . LED | //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // 7 6 5 4 3 2 1 0 | // PORTA . . . LED LED LED LED LED | // PORTB . . . CPS4 CPS3 CPS2 CPS1 CPS0 | //-------------------------------------------------------------------------- TRISA0 = ANSA0 = 0; // Set LED outs as digital outputs TRISA1 = ANSA1 = 0; TRISA2 = ANSA2 = 0; // All others remain as inputs (default) TRISA3 = ANSA3 = 0; TRISA4 = ANSA4 = 0; TRISA5 = ANSA5 = 0; TRISA |= 0b00000000; // Set as analog inputs ANSELA |= 0b00000000; // (should be default) TRISB |= 0b00011111; // " ANSELB |= 0b00011111; // " LED0 = OFF; // Init to off state LED1 = OFF; // .. LED2 = OFF; // .. LED3 = OFF; // .. LED4 = OFF; LED5 = OFF; OSCTUNE = 0b00100000; // ********************************************************************************* // Initialize Cap Module // ********************************************************************************* CapInit(); GIE = 1; } //// ************************************************************************************* //// Function: SLEEP_NOP() //// Purpose: Sleep function with NOP //// ************************************************************************************* void SLEEP_NOP(void) { SLEEP(); #asm NOP #endasm SLEEP(); #asm NOP #endasm } // ************************************************************************************* // Function: CapInit() // Purpose: Initialize the Capacitive Sense Module and Time Base Modules // ************************************************************************************* void CapInit(void) { // Set up variables for (index=0; index<5; index++) { average[index] = 0; reading[index] = 0; } // ******************************************************************************** // Initialize for Timer0 time base ************************************************ // ******************************************************************************** #if METHOD==1 // Timer0 set as time base OPTION = 0b11000100; // Timer0 init TMR0IF = 0; // enable tmr0 intpt TMR0IE = 1; T1CON = 0b01000101; // Timer1 enable, system clock, 1:1 prescale, T1GCON = 0b11100001; // Timer1 gate init #endif // ******************************************************************************** // Inititialize for Timer2 time base ********************************************** // ******************************************************************************** #if METHOD==2 // Timer2 set as time base // Tmr2 setup // module setup T2CON = 0b00000100; // T2ON, prescale & postscale = 1:1 T2CON |=0b00000001; // adjust prescalar T1CON = 0b01000101; // Timer1 enable, system clock, 1:1 prescale, T1GCON = 0b11100001; // Timer1 gate init T1GCON &=0b11111100; // clr T1GSS bits T1GCON |=0b00000010; // set T1GSS for Timer2 match PR2 PR2 = 0xB4; // pr2 for use w/timer2 .. w/pres.1:4, 0xB4 sets 500us scan rate. TMR2IF = 0; TMR2IE = 1; #endif // ********************************************************************************** // Initialize for WDT time base ***************************************************** // ********************************************************************************** #if (METHOD==3 | METHOD==4) OPTION = 0b11001000; // Assign Prescaler to WDT T1CON = 0b01000101; // Timer1 enable, system clock, 1:1 prescale, T1GCON = 0b11100011; // Set T1GSS for WDT gate #endif // ********************************************************************************** // Cap Sense Module ***************************************************************** // ********************************************************************************** CPSCON0 = 0b10001100; // control settings CPSCON1 = 0x00; // init to channel select = 0 (4 LSb's) index = CPSCON1; // Start program ready to scan first channel // ********************************************************************************** // Gate Setup *********************************************************************** // ********************************************************************************** TMR1GIF = 0; // clear gate intpt flag TMR1GIE = 1; // enable gate intpt PEIE = 1; // enable peripheral intpts } //******************************************************************** // ISR() ************************************************************* // Interrupt Service Routine // Reads values of TMR1 corresponding to each button/sensor // and makes decision if button/sensor has been touched. //******************************************************************** //******************************************************************** void interrupt isr(void) { LED5 = ON; CLRWDT(); // Timer0 Interrupt // ... if (T0IE && T0IF) { T0IF = 0; // Clear T0IF every time } // Timer2 Interrupt // ... if (TMR2IE && TMR2IF) { TMR2IF = 0; // Clear T2IF every time } // Timer1 Gate Interrupt if (TMR1GIF && TMR1GIE) { // Perform touch reading TMR1GIF = 0; // clear intpt flag TMR1ON = 0; // Timer1 off bigval = TMR1L + (unsigned int)(TMR1H << 8); bigval = bigval * 16; reading[index] = bigval; smallavg = average[index] / 16; threshold128 = average[index] >> 7; // avg >> 7 = 1/128 = 0.78% as a threshold value below average threshold64 = average[index] >> 6; // avg >> 6 = 1/64 = 1.56% as a threshold value below average threshold32 = average[index] >> 5; // avg >> 5 = 1/32 = 3.12% as a threshold value below average threshold16 = average[index] >> 4; // avg >> 4 = 1/16 = 6.25% as a threshold value below average threshold8 = average[index] >> 3; // avg >> 3 = 1/8 = 12.5% as a threshold value below average threshold4 = average[index] >> 2; // avg >> 2 = 1/4 = 25% as a threshold value below average threshold2 = average[index] >> 1; // avg >> 1 = 1/2 = 50% as a threshold value below average threshold = threshold4; // ratiometric threshold from avail above (& combinations) if (bigval < average[index] - threshold) { switch (index) { case 0: Buttons.BTN0 = 1; break; // The current button is pressed case 1: Buttons.BTN1 = 1; break; // Relay button pressed information to application case 2: Buttons.BTN2 = 1; break; case 3: Buttons.BTN3 = 1; break; case 4: Buttons.BTN4 = 1; break; /* case 5: Buttons.BTN5 = 1; break; case 6: Buttons.BTN6 = 1; break; case 7: Buttons.BTN7 = 1; break; case 8: Buttons.BTN8 = 1; break; case 9: Buttons.BTN9 = 1; break; case 10: Buttons.BTN10 = 1; break; case 11: Buttons.BTN11 = 1; break; case 12: Buttons.BTN12 = 1; break; case 13: Buttons.BTN13 = 1; break; case 14: Buttons.BTN14 = 1; break; case 15: Buttons.BTN15 = 1; break; */ default: break; } } else { // Button unpressed (no hysteresis provided) switch (index) { case 0: Buttons.BTN0 = 0; break; // The current button is unpressed case 1: Buttons.BTN1 = 0; break; // Relay button pressed information to application case 2: Buttons.BTN2 = 0; break; case 3: Buttons.BTN3 = 0; break; case 4: Buttons.BTN4 = 0; break; /* case 5: Buttons.BTN5 = 0; break; case 6: Buttons.BTN6 = 0; break; case 7: Buttons.BTN7 = 0; break; case 8: Buttons.BTN8 = 0; break; case 9: Buttons.BTN9 = 0; break; case 10: Buttons.BTN11 = 0; break; case 12: Buttons.BTN10 = 0; break; case 11: Buttons.BTN12 = 0; break; case 13: Buttons.BTN13 = 0; break; case 14: Buttons.BTN14 = 0; break; case 15: Buttons.BTN15 = 0; break; */ default: break; } // Perform average after detection comparison average[index] += bigval/16 - smallavg; } SetNextChannel(); // Set up for next channel RestartTimer1(); // Restart timer1 } LED5 = OFF; } //********************************************************************* //Function: RestartTimers() ******************************************* // Purpose: Resets and restarts timers 0 & 1 used for capacitive sensing. // Based on original method before Timer1 Gate peripheral features //. added to 72x. ***************************************************** //********************************************************************* void RestartTimers(void) { TMR1L = 0; // reset Timer1 TMR1H = 0; // " " TMR1ON = 1; // restart Timer1 TMR0 = 0; // reset Timer0 T0IF = 0; // clear the interrupt } // ******************************************************************** // RestartTimer1() **************************************************** // Resets and restarts timer 1 (used for capacitive sensing). // Used for Timer0 and T1GCON in toggle mode for automatic shutoff // of Timer1 (better for consistent and repeated measurements). // Also has same use with toggle & single pulse mode Tmr1 gate. // ******************************************************************** void RestartTimer1(void) { TMR1L = 0; // Reset Timer1 TMR1H = 0; // " " TMR1ON = 1; // Restart Timer1 CLRWDT(); } //********************************************************************** // SetNextChannel() ************************************************** // Sets the next channel for the oscillator to measure, *********** // configures all hardware appropriately, internal, and if ************ // applicable external. *********************************************** // ********************************************************************* void SetNextChannel(void) { index = (++index) & 0x04; // cycle index state 0-15 w/rollover // if (index >> 0x0E) // index = 0; CPSCON1 = index; // Select external pin CPS0..CPS15 } //************************************************************************ // Function: DisplayLEDs() *********************************************** // Display ouput button on LEDS based ************************************ // binary button number ************************************************** // *********************************************************************** void DisplayLEDs(char i) { // Display the switch (i) { case 0xFF: // 0xFF is special value for off (same as 0). case 0: LED0 = OFF; LED1 = OFF; LED2 = OFF; LED3 = OFF; break; // Binary counting case 1: LED0 = ON; LED1 = OFF; LED2 = OFF; LED3 = OFF; break; // for LEDs case 2: LED0 = OFF; LED1 = ON; LED2 = OFF; LED3 = OFF; break; case 3: LED0 = ON; LED1 = ON; LED2 = OFF; LED3 = OFF; break; case 4: LED0 = OFF; LED1 = OFF; LED2 = ON; LED3 = OFF; break; case 5: LED0 = ON; LED1 = OFF; LED2 = ON; LED3 = OFF; break; case 6: LED0 = OFF; LED1 = ON; LED2 = ON; LED3 = OFF; break; case 7: LED0 = ON; LED1 = ON; LED2 = ON; LED3 = OFF; break; case 8: LED0 = OFF; LED1 = OFF; LED2 = OFF; LED3 = ON; break; case 9: LED0 = ON; LED1 = OFF; LED2 = OFF; LED3 = ON; break; case 10: LED0 = OFF; LED1 = ON; LED2 = OFF; LED3 = ON; break; case 11: LED0 = ON; LED1 = ON; LED2 = OFF; LED3 = ON; break; case 12: LED0 = OFF; LED1 = OFF; LED2 = ON; LED3 = ON; break; case 13: LED0 = ON; LED1 = OFF; LED2 = ON; LED3 = ON; break; case 14: LED0 = OFF; LED1 = ON; LED2 = ON; LED3 = ON; break; case 15: LED0 = ON; LED1 = ON; LED2 = ON; LED3 = ON; break; default: break; } }