sure here's the ASM:
<pre><code>
//******************************************************************************
// 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
// *****************************************************************************
bank1 unsigned int reading; // current reading for each button
bank1 unsigned int average; // 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
/*====================================================================
======================== PROGRAM CODE ==============================
====================================================================*/
//*********************************************************************
// main() ************************************************************
// Main loop. Will turn on the LEDs based on button detected during**
// ISR execution. ***********************************************
// ********************************************************************
void main(void) {
Init();
CLRWDT();
index = 0; // Begin program scanning channel 0
while (1) { // Loop forever
// React to button presses in application main-loop
if (Buttons.BTN0)
DisplayLEDs(0); // Structuring code based off each button takes up
if (Buttons.BTN1) // more application code, but reduces isr code.
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 |
//-------------------------------------------------
TRISA0 = ANSA0 = 0; // Set LED outs as digital outputs
TRISE2 = ANSE2 = 0; // All others remain as inputs (default)
TRISE0 = ANSE0 = 0;
TRISA1 = ANSA1 = 0;
LED0 = OFF; // Init to off state
LED1 = OFF; // ..
LED2 = OFF; // ..
LED3 = OFF; // ..
TRISA |= 0b00110000; // Set as analog inputs
ANSELA |= 0b00110000; // (should be default)
TRISB |= 0b00111111; // "
ANSELB |= 0b00111111; // "
TRISD |= 0b11111111; // "
ANSELD |= 0b11111111; // "
OSCTUNE = 0b00100000;
// *********************************************************************************
// Initialize Cap Module
// *********************************************************************************
// *************************************************************************************
// Function: CapInit()
// Purpose: Initialize the Capacitive Sense Module and Time Base Modules
// *************************************************************************************
void CapInit(void)
{
// Set up variables
for (index=0; index<16; index++) {
average = 0;
reading = 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
//********************************************************************
// 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)
{
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
threshold128 = average >> 7; // avg >> 7 = 1/128 = 0.78% as a threshold value below average
threshold64 = average >> 6; // avg >> 6 = 1/64 = 1.56% as a threshold value below average
threshold32 = average >> 5; // avg >> 5 = 1/32 = 3.12% as a threshold value below average
threshold16 = average >> 4; // avg >> 4 = 1/16 = 6.25% as a threshold value below average
threshold8 = average >> 3; // avg >> 3 = 1/8 = 12.5% as a threshold value below average
threshold4 = average >> 2; // avg >> 2 = 1/4 = 25% as a threshold value below average
threshold2 = average >> 1; // avg >> 1 = 1/2 = 50% as a threshold value below average
if (bigval < average - 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 += bigval/16 - smallavg;
}
SetNextChannel(); // Set up for next channel
RestartTimer1(); // Restart timer1
}
}
//*********************************************************************
//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)
{
// ********************************************************************
// 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) & 0x0F; // 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 **************************************************
// ***********************************************************************
Here is the include.h sorry about markup it goes awry when there are # included.
<pre><code>
//******************************************************************************
// 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: Cap_Sense.h
// Date: Dec. 13, 2007
// Purpose: Defines and Vars for Cap_Sense.c module demo
// *****************************************************************************
#ifndef MAIN727_H
#define MAIN727_H
// Execute contained code ONE-TIME ONLY
// Create FFlag variable type
// Used for application status bit flags
typedef struct {
char SSPBF : 1;
} FFlags;
/** Variables **/
extern bank1 unsigned int reading;
extern bank1 unsigned int average;
extern bank1 unsigned int threshold;
//extern bank1 long percent;
extern unsigned char index;
extern bank2 unsigned int threshold128; // Threshold of 1/128th = 1/128th of the average value
extern bank2 unsigned int threshold64; // … used in computation of threshold variable
extern bank2 unsigned int threshold32; // … threshold is a selection of the sum of these
extern bank2 unsigned int threshold16; // "
extern bank2 unsigned int threshold8; // "
extern bank2 unsigned int threshold4; // "
extern bank2 unsigned int threshold2; // Threshold value for 1/2
And heres the ASM - sorry files had wrong name on em
<pre><code>
;********************************************************
;* file: 10ftouch.asm ver 1.2 *
;* auth: m. flipse *
;* date: *
;*
;* modf: T. Perme
;* date: 24 March 2008
;* desc:
;*
;* 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.
;*
;********************************************************
#chip 10f206,1
radix dec
include <p10f206.inc>
include "Vars.inc"
gatedtime equ .33 ; time in msec that is used to measure the frequency
; For Proximity
triplo_prx equ .16 ; difference between average and current
triphi_prx equ .0 ; frequency value for a key to be detected. (512 counts)
; Smaller values have a more sensitive trip (good for proximity)
; For Touch
triplo_tch equ .50 ; difference between average and current
triphi_tch equ .1 ; frequency value for a key to be detected. (512 counts)
; Smaller values have a more sensitive trip (good for proximity)
hysteresis equ .200 ; constant that is used to lower the averagevalue
; If waking from intentional sleep, return back to post-sleep command
; CWUF = 0, GPWUF = 0, TO = 0, PO = 0 STATUS BITS for wake from WDT
; movf STATUS, w
; andlw b'11111000' ; and off ALU status bits to zero
; btfsc STATUS, Z ; check if all bits are zero, branch accordingly
; goto jumpbackaftersleep ; all zero
; goto jumpinit ; non-zero
jumpbackaftersleep:
; clrwdt ; Clr wdt, resetting PO and TO to 1 in status reg
; goto wake_from_sleep
jumpinit:
call init ; init the device if starting from power-up
goto main
;********************************************************
;* subroutine init *
;********************************************************
;{
init
movlw b'11110111'
; ||||||||_ ps0
; |||||||__ ps1
; ||||||___ ps2 set prescaler to 1:256
; |||||____ psa prescaler assigned to tmr0
; ||||_____ t0se increment on high to low
; |||______ t0cs transition on t0cki
; ||_______ #gppu pull-ups disabled
; |________ #gpwu wake-up on pin change disabled
option
movlw b'00001011'
; ||||||||_ #cwu wake-up on comp change disabled
; |||||||__ cpref pos ref is cin+
; ||||||___ cnref neg ref is internal 0.6V reference
; |||||____ cmpon comparator on
; ||||_____ cmpt0cs comparator output used as tmr0 clock
; |||______ pol output is inverted
; ||_______ #couten output is placed on cout pin
; |________ cmpout -read only bit-
movwf cmcon0
movlw b'11111001' ; set gp1 and gp2 as an output
tris gpio
;********************************************************
;* subroutine delay *
;* descr: causes a timing delay in mSecs *
;* *
;* in: w - value in mSecs *
;********************************************************
;{
delay
movwf temp1
wait
movlw .249
movwf temp2
clrwdt ; instead of nop, use clrwdt to clrwdt while awake
decfsz temp2 ; all other code is much much less than 18ms (WDT timeout) when not delaying
goto $-2
decfsz temp1
goto wait
retlw .0
;}
;********************************************************
;* subroutine: average
;* descr:
;*
;* in: freqhi, freqlo *
;********************************************************
;{
average
movf averagehi,w
movwf avhitemp
movf averagelo,w
movwf avlotemp
clrf temp2 ; make a copy of the original value
call divideby2pwrn ; divide the copy by 2^n
;******
movf temp2,w
subwf averagefraction ; and subtract the result from the original
btfsc status,c
goto hopover
decf averagelo
movlw .255
xorwf averagelo,w
btfsc status,z
decf averagehi
hopover
movf avlotemp,w
subwf averagelo
btfss status,c
decf averagehi
movf avhitemp,w
subwf averagehi ; average - 1/(2^n)
;******
movf freqhi,w
movwf avhitemp
movf freqlo,w
movwf avlotemp ; make a copy of the original value
clrf temp2
btfsc status,c ; is the difference negative?
goto evaldifference ; no positive, check if it exceeds the trip point
movf freqhi,w ; yes, key is released
movwf averagehi ; average should follow actual value
movf freqlo,w
movwf averagelo
clrf differencehi
clrf differencelo
bcf userflag,keydown
retlw .0
evaldifference
bcf userflag,keydown
movlw triphi_tch
btfsc gpio, 3
movlw triphi_prx
subwf differencehi,w
btfss status,z ; are hi bytes equal?
goto results
btfss status,c ; was the difference > trip point?
retlw .0 ; no, return
bsf userflag,keydown ; yes, set the keydown flag
retlw .0
;}
;********************************************************
;* subroutine: getfrequency *
;* descr: converts to binary coded decimal *
;* *
;* out: freqhi:freqlo with frequency *
;********************************************************
;{
getfrequency
movlw b'11110111'
; ||||||||_ ps0
; |||||||__ ps1
; ||||||___ ps2 set prescaler to 1:256
; |||||____ psa prescaler assigned to tmr0
; ||||_____ t0se increment on high to low
; |||______ t0cs transition on t0cki
; ||_______ #gppu pull-ups disabled
; |________ #gpwu wake-up on pin change disabled
option
movlw b'00001011'
; ||||||||_ #cwu wake-up on comp change disabled
; |||||||__ cpref pos ref is cin+
; ||||||___ cnref neg ref is internal 0.6V reference
; |||||____ cmpon comparator on
; ||||_____ cmpt0cs comparator output used as tmr0 clock
; |||______ pol output is inverted
; ||_______ #couten output is placed on cout pin
; |________ cmpout -read only bit-
movwf cmcon0
movlw .255 ; frequency will be stored in freqhi:freqlo
movwf freqlo ; freqlo is pre-initialised here
clrf tmr0 ; clear tmr0 and the 1:256 prescaler
movlw gatedtime
call delay ; wait N mSec for scan time
bcf cmcon0,cmpon ; turn off oscillator
movf tmr0,w ; high byte of value is stored in tmr0
movwf freqhi ; low value is still in the prescaler
; To get the value from the prescaler (which is not directly readable),
; the clock source for tmr0 is changed to Fosc/4.
; Next the value of tmr0 is observed. The time is takes for the next
; increment is an indication of the value of the prescaler.
movlw b'11010111' ; change clock source to Fosc/4
option
measureprescaler
incf freqlo ; was initialised to 255 and set to 0 here
movf tmr0,w ; get the current value of tmr0
xorwf freqhi,w ; compare it with the original value of tmr0
btfsc status,z ; did tmr0 increment?
goto measureprescaler ; no, loop and increment freqlo
; Now freqlo ranges from 0 to 43. The next section will muliply it
; with 6 and clipped to 255, to get the lobyte of the frequency count.
bcf status,c ; clear the carry bit
rlf freqlo ; muliply by 2
rlf freqlo ,w ; and muliply by 2 again, but put the result in w
addwf freqlo ; add it to the doubled value (multiplied by 6)
btfss status,c ; did it overflow (6 x 43 = 258)
goto nooverflow ; no, go on
movlw .255 ; yes, clip it to 255
movwf freqlo
nooverflow
comf freqlo ; the time for the prescaler to roll over was measured,
; so its value was 255 - prescaler value
; Because of the way the prescaler rollover time was measured (6 Tcy in measureprescaler),
; atleast the 2 least significant bits in freqhi:frequlo are useless.
; Therefore the final result is divided by 4.
mainloop
; Sensing and Detection
call getfrequency
call average
call checkdifference
; Check if Key Was Pressed
btfsc userflag, keydown
goto react_keydown
btfss userflag, keydown
goto react_keyup
; If a press was detected, output low (LED ON) else output high (LED OFF)
react_keydown:
bcf gpio, output ; turn led on
goto finish_loop
react_keyup:
bsf gpio, output ; turn led off
goto finish_loop
; Code below was left in to show possible use of sleeping and waking via WDT
; to significantly reduce power. Requires code on power up (also commented)
; in order to determine that it is a wake from sleep, not power up in order
; to resume normal operation
finish_loop:
; Sleep
; movlw b'11111011' ; Prescalar on 1:8 WDT, assign to WDT
; option
; movlw .1
; call delay ; delay for 1 ms to ensure comparator off, everything settled before sleep
; sleep ; goto sleep for ~144ms (8*18ms)
; nop ; don't pre-fetch anything unintended after sleep instruction
; Sleep Code Commented out
; Sleeping more between scans will reduce avg current
; 33ms on, 144ms off avg draw = ~70uA WDT prescale 1:8 (5.6scan per sec)
; 33ms on, 288ms off avg draw = ~50ua WDT prescale 1:16 (3.1scan per sec)
Hi can anyone contribute some Basic source code for touch sensing a pad? I have ASM or C touch if anyone interested.
I'm interested.
And perhaps the asm code can be easily adapted to GcBasic.
Can you paste the code?
Regards.
sure here's the ASM:
<pre><code>
//******************************************************************************
// 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 <pic.h>
#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; // current reading for each button
bank1 unsigned int average; // 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();
CLRWDT();
index = 0; // Begin program scanning channel 0
while (1) { // Loop forever
// React to button presses in application main-loop
if (Buttons.BTN0)
DisplayLEDs(0); // Structuring code based off each button takes up
if (Buttons.BTN1) // more application code, but reduces isr code.
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 |
//-------------------------------------------------
TRISA0 = ANSA0 = 0; // Set LED outs as digital outputs
TRISE2 = ANSE2 = 0; // All others remain as inputs (default)
TRISE0 = ANSE0 = 0;
TRISA1 = ANSA1 = 0;
LED0 = OFF; // Init to off state
LED1 = OFF; // ..
LED2 = OFF; // ..
LED3 = OFF; // ..
TRISA |= 0b00110000; // Set as analog inputs
ANSELA |= 0b00110000; // (should be default)
TRISB |= 0b00111111; // "
ANSELB |= 0b00111111; // "
TRISD |= 0b11111111; // "
ANSELD |= 0b11111111; // "
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<16; index++) {
average = 0;
reading = 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)
{
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 = bigval;
smallavg = average / 16;
threshold128 = average >> 7; // avg >> 7 = 1/128 = 0.78% as a threshold value below average
threshold64 = average >> 6; // avg >> 6 = 1/64 = 1.56% as a threshold value below average
threshold32 = average >> 5; // avg >> 5 = 1/32 = 3.12% as a threshold value below average
threshold16 = average >> 4; // avg >> 4 = 1/16 = 6.25% as a threshold value below average
threshold8 = average >> 3; // avg >> 3 = 1/8 = 12.5% as a threshold value below average
threshold4 = average >> 2; // avg >> 2 = 1/4 = 25% as a threshold value below average
threshold2 = average >> 1; // avg >> 1 = 1/2 = 50% as a threshold value below average
threshold = threshold4; // ratiometric threshold from avail above (& combinations)
if (bigval < average - 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 += bigval/16 - smallavg;
}
SetNextChannel(); // Set up for next channel
RestartTimer1(); // Restart timer1
}
}
//*********************************************************************
//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) & 0x0F; // 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;
}
}
</code></pre>
Here is the include.h sorry about markup it goes awry when there are # included.
<pre><code>
//******************************************************************************
// 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: Cap_Sense.h
// Date: Dec. 13, 2007
// Purpose: Defines and Vars for Cap_Sense.c module demo
// *****************************************************************************
#ifndef MAIN727_H
#define MAIN727_H
// Execute contained code ONE-TIME ONLY
// Create FFlag variable type
// Used for application status bit flags
typedef struct {
char SSPBF : 1;
} FFlags;
// Create BButton variable type
// Used for bit indicators for button presses
typedef struct {
char BTN0 :1; // {byte 0}
char BTN1 :1;
char BTN2 :1;
char BTN3 :1;
char BTN4 :1;
char BTN5 :1;
char BTN6 :1;
char BTN7 :1;
char BTN8 :1; // {byte 1}
char BTN9 :1;
char BTN10:1;
char BTN11:1;
char BTN12:1;
char BTN13:1;
char BTN14:1;
char BTN15:1; // Create bitfield for sensors 0-15
} BButtons;
#endif /* MAIN727_H */
// Defines
// Pinouts
#define LED0 RA0
#define LED1 RE2
#define LED2 RE0
#define LED3 RA1
#define ON 0 // active low leds
#define OFF 1 //
#define NUM_BTTNS 16
/** Variables **/
extern bank1 unsigned int reading;
extern bank1 unsigned int average;
extern bank1 unsigned int threshold;
//extern bank1 long percent;
extern unsigned char index;
extern bank2 unsigned int threshold128; // Threshold of 1/128th = 1/128th of the average value
extern bank2 unsigned int threshold64; // … used in computation of threshold variable
extern bank2 unsigned int threshold32; // … threshold is a selection of the sum of these
extern bank2 unsigned int threshold16; // "
extern bank2 unsigned int threshold8; // "
extern bank2 unsigned int threshold4; // "
extern bank2 unsigned int threshold2; // Threshold value for 1/2
extern FFlags Flags;
extern BButtons Buttons;
</code></pre>
And heres the ASM - sorry files had wrong name on em
<pre><code>
;********************************************************
;* file: 10ftouch.asm ver 1.2 *
;* auth: m. flipse *
;* date: *
;*
;* modf: T. Perme
;* date: 24 March 2008
;* desc:
;*
;* 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.
;*
;********************************************************
#chip 10f206,1
radix dec
include <p10f206.inc>
include "Vars.inc"
gatedtime equ .33 ; time in msec that is used to measure the frequency
avdepth equ .5 ; averaging depth
; 2 ^ (n-1) x oldvalue + newvalue
; = ----------------------
; (2 ^ n)
; For Proximity
triplo_prx equ .16 ; difference between average and current
triphi_prx equ .0 ; frequency value for a key to be detected. (512 counts)
; Smaller values have a more sensitive trip (good for proximity)
; For Touch
triplo_tch equ .50 ; difference between average and current
triphi_tch equ .1 ; frequency value for a key to be detected. (512 counts)
; Smaller values have a more sensitive trip (good for proximity)
hysteresis equ .200 ; constant that is used to lower the averagevalue
; when continuous touch is enabled
__config _intrc_osc & _wdt_on & _mclre_off & _cp_off
org .0 ; reset vector
reset
movwf osccal ; calibrate internal oscillator
; If waking from intentional sleep, return back to post-sleep command
; CWUF = 0, GPWUF = 0, TO = 0, PO = 0 STATUS BITS for wake from WDT
; movf STATUS, w
; andlw b'11111000' ; and off ALU status bits to zero
; btfsc STATUS, Z ; check if all bits are zero, branch accordingly
; goto jumpbackaftersleep ; all zero
; goto jumpinit ; non-zero
jumpbackaftersleep:
; clrwdt ; Clr wdt, resetting PO and TO to 1 in status reg
; goto wake_from_sleep
jumpinit:
call init ; init the device if starting from power-up
goto main
;********************************************************
;* subroutine init *
;********************************************************
;{
init
movlw b'11110111'
; ||||||||_ ps0
; |||||||__ ps1
; ||||||___ ps2 set prescaler to 1:256
; |||||____ psa prescaler assigned to tmr0
; ||||_____ t0se increment on high to low
; |||______ t0cs transition on t0cki
; ||_______ #gppu pull-ups disabled
; |________ #gpwu wake-up on pin change disabled
option
movlw b'00001011'
; ||||||||_ #cwu wake-up on comp change disabled
; |||||||__ cpref pos ref is cin+
; ||||||___ cnref neg ref is internal 0.6V reference
; |||||____ cmpon comparator on
; ||||_____ cmpt0cs comparator output used as tmr0 clock
; |||______ pol output is inverted
; ||_______ #couten output is placed on cout pin
; |________ cmpout -read only bit-
movwf cmcon0
movlw b'11111001' ; set gp1 and gp2 as an output
tris gpio
clrf averagehi
clrf averagelo
clrf averagefraction
clrf userflag
retlw .0
;}
;********************************************************
;* subroutine delay *
;* descr: causes a timing delay in mSecs *
;* *
;* in: w - value in mSecs *
;********************************************************
;{
delay
movwf temp1
wait
movlw .249
movwf temp2
clrwdt ; instead of nop, use clrwdt to clrwdt while awake
decfsz temp2 ; all other code is much much less than 18ms (WDT timeout) when not delaying
goto $-2
decfsz temp1
goto wait
retlw .0
;}
;********************************************************
;* subroutine: average
;* descr:
;*
;* in: freqhi, freqlo *
;********************************************************
;{
average
movf averagehi,w
movwf avhitemp
movf averagelo,w
movwf avlotemp
clrf temp2 ; make a copy of the original value
call divideby2pwrn ; divide the copy by 2^n
;******
movf temp2,w
subwf averagefraction ; and subtract the result from the original
btfsc status,c
goto hopover
decf averagelo
movlw .255
xorwf averagelo,w
btfsc status,z
decf averagehi
hopover
movf avlotemp,w
subwf averagelo
btfss status,c
decf averagehi
movf avhitemp,w
subwf averagehi ; average - 1/(2^n)
;******
movf freqhi,w
movwf avhitemp
movf freqlo,w
movwf avlotemp ; make a copy of the original value
clrf temp2
call divideby2pwrn ; divide by 2^n
movf temp2,w
addwf averagefraction
btfss status,c
goto hopover2
incf averagelo
btfsc status,z
incf averagehi
hopover2
movf avlotemp,w
addwf averagelo
btfsc status,c
incf averagehi
movf avhitemp,w
addwf averagehi
retlw .0
divideby2pwrn
movlw avdepth
movwf temp1
shift1
bcf status,c
rrf avhitemp
rrf avlotemp
rrf temp2
decfsz temp1
goto shift1
retlw .0
;}
;********************************************************
;* subroutine: checkdifference *
;* descr: subtracts actual value from average *
;* *
;* out: freqhi:freqlo with frequency *
;********************************************************
;{
checkdifference
movf averagehi,w
movwf differencehi
movf averagelo,w
movwf differencelo ; make a copy of the averagevalue
movf freqlo,w
subwf differencelo
btfss status,c
decf differencehi
movf freqhi,w
subwf differencehi ; averagevalue - currentvalue
btfsc status,c ; is the difference negative?
goto evaldifference ; no positive, check if it exceeds the trip point
movf freqhi,w ; yes, key is released
movwf averagehi ; average should follow actual value
movf freqlo,w
movwf averagelo
clrf differencehi
clrf differencelo
bcf userflag,keydown
retlw .0
evaldifference
bcf userflag,keydown
movlw triphi_tch
btfsc gpio, 3
movlw triphi_prx
subwf differencehi,w
btfss status,z ; are hi bytes equal?
goto results
movlw triplo_tch
btfsc gpio, 3
movlw triplo_prx ; yes, compare lower bytes
subwf differencelo,w
results
btfss status,c ; was the difference > trip point?
retlw .0 ; no, return
bsf userflag,keydown ; yes, set the keydown flag
retlw .0
;}
;********************************************************
;* subroutine: getfrequency *
;* descr: converts to binary coded decimal *
;* *
;* out: freqhi:freqlo with frequency *
;********************************************************
;{
getfrequency
movlw b'11110111'
; ||||||||_ ps0
; |||||||__ ps1
; ||||||___ ps2 set prescaler to 1:256
; |||||____ psa prescaler assigned to tmr0
; ||||_____ t0se increment on high to low
; |||______ t0cs transition on t0cki
; ||_______ #gppu pull-ups disabled
; |________ #gpwu wake-up on pin change disabled
option
movlw b'00001011'
; ||||||||_ #cwu wake-up on comp change disabled
; |||||||__ cpref pos ref is cin+
; ||||||___ cnref neg ref is internal 0.6V reference
; |||||____ cmpon comparator on
; ||||_____ cmpt0cs comparator output used as tmr0 clock
; |||______ pol output is inverted
; ||_______ #couten output is placed on cout pin
; |________ cmpout -read only bit-
movwf cmcon0
movlw .255 ; frequency will be stored in freqhi:freqlo
movwf freqlo ; freqlo is pre-initialised here
clrf tmr0 ; clear tmr0 and the 1:256 prescaler
movlw gatedtime
call delay ; wait N mSec for scan time
bcf cmcon0,cmpon ; turn off oscillator
movf tmr0,w ; high byte of value is stored in tmr0
movwf freqhi ; low value is still in the prescaler
; To get the value from the prescaler (which is not directly readable),
; the clock source for tmr0 is changed to Fosc/4.
; Next the value of tmr0 is observed. The time is takes for the next
; increment is an indication of the value of the prescaler.
movlw b'11010111' ; change clock source to Fosc/4
option
measureprescaler
incf freqlo ; was initialised to 255 and set to 0 here
movf tmr0,w ; get the current value of tmr0
xorwf freqhi,w ; compare it with the original value of tmr0
btfsc status,z ; did tmr0 increment?
goto measureprescaler ; no, loop and increment freqlo
; Now freqlo ranges from 0 to 43. The next section will muliply it
; with 6 and clipped to 255, to get the lobyte of the frequency count.
bcf status,c ; clear the carry bit
rlf freqlo ; muliply by 2
rlf freqlo ,w ; and muliply by 2 again, but put the result in w
addwf freqlo ; add it to the doubled value (multiplied by 6)
btfss status,c ; did it overflow (6 x 43 = 258)
goto nooverflow ; no, go on
movlw .255 ; yes, clip it to 255
movwf freqlo
nooverflow
comf freqlo ; the time for the prescaler to roll over was measured,
; so its value was 255 - prescaler value
; Because of the way the prescaler rollover time was measured (6 Tcy in measureprescaler),
; atleast the 2 least significant bits in freqhi:frequlo are useless.
; Therefore the final result is divided by 4.
bcf status,c
rrf freqhi
rrf freqlo
bcf status,c
rrf freqhi
rrf freqlo ; divide by 4
bcf cmcon0, cmpon ; turn comp off to conserve power
retlw .0 ; done
;}
;********************************************************
;* main *
;********************************************************
;{
main
movlw gatedtime
call delay ; wait 30mSec
movlw .49
movwf differencelo
movlw .1
movwf differencehi
call evaldifference
nop
call getfrequency
movf freqhi,w
movwf averagehi
movf freqlo,w
movwf averagelo
mainloop
; Sensing and Detection
call getfrequency
call average
call checkdifference
; Check if Key Was Pressed
btfsc userflag, keydown
goto react_keydown
btfss userflag, keydown
goto react_keyup
; If a press was detected, output low (LED ON) else output high (LED OFF)
react_keydown:
bcf gpio, output ; turn led on
goto finish_loop
react_keyup:
bsf gpio, output ; turn led off
goto finish_loop
; Code below was left in to show possible use of sleeping and waking via WDT
; to significantly reduce power. Requires code on power up (also commented)
; in order to determine that it is a wake from sleep, not power up in order
; to resume normal operation
finish_loop:
; Sleep
; movlw b'11111011' ; Prescalar on 1:8 WDT, assign to WDT
; option
; movlw .1
; call delay ; delay for 1 ms to ensure comparator off, everything settled before sleep
; sleep ; goto sleep for ~144ms (8*18ms)
; nop ; don't pre-fetch anything unintended after sleep instruction
; Sleep Code Commented out
; Sleeping more between scans will reduce avg current
; 33ms on, 144ms off avg draw = ~70uA WDT prescale 1:8 (5.6scan per sec)
; 33ms on, 288ms off avg draw = ~50ua WDT prescale 1:16 (3.1scan per sec)
wake_from_sleep:
; movlw b'11110111' ; Return Prescalar to 1:256 assigned to TMR0
; option ; re-init option reg
; movlw b'00001011'
; movwf cmcon0 ; re-init cmcon0
; movlw b'11111001'
; tris gpio ; re-init gpio
; Sleep code commented
goto mainloop ; stay in main loop
;----------------------------------------------
end
_endasm;
</code></pre>
Thanks.
I was thinking in a touchpad, this looks an example for a capacitive keypad, but interesting anyway.