Menu

Touch software for PIC10 etc

2009-12-03
2013-05-30
  • Alistair George

    Alistair George - 2009-12-03

    Hi can anyone contribute some Basic source code for touch sensing a pad? I have ASM or C touch if anyone interested.

     
  • Nobody/Anonymous

    I'm interested.

    And perhaps the asm code can be easily adapted to GcBasic.

    Can you paste the code?

    Regards.

     
  • Alistair George

    Alistair George - 2009-12-03

    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>

     
  • Alistair George

    Alistair George - 2009-12-03

    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>

     
  • Alistair George

    Alistair George - 2009-12-03

    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>

     
  • Nobody/Anonymous

    Thanks.

    I was thinking in a touchpad, this looks an example for a capacitive keypad,  but interesting anyway.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.