12F683 ISR switch debounce

Discussion in 'Embedded Systems and Microcontrollers' started by dayv3, Jun 5, 2014.

  1. dayv3

    Thread Starter Member

    May 22, 2014
    31
    0
    Hi,

    I have been trying to write an ISR switch de-bouncing program that will turn a LED either on or off as a result of each button press. I got my code to compile but once the hex file was loaded the led turns on and off with the button press and not as a result of it.

    I am using MikroC and the target device is a 12F683.

    I tried to look at the code in the debugger things seem okay but I can not get the MikroC to step into the interrupt function so that I can see that it is working properly. I set the debugger up to watch TMRO so that I can see it count up and then overflow but, the variable does not increment.
    The debugger acts as though the interrupt function does not even exist.
    Is there a way to get the debugger to walk thru an interrupt function?

    I will gladly email or post the code if needed.
    Any help would be greatly appreciated.

    Dave
     
  2. pwdixon

    Member

    Oct 11, 2012
    488
    56
    You will need to actually post the code for anyone to comment.
     
  3. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    That sounds like the problem. Go thru the data sheets again and see if you use the T0CKI pin or the internal instruction cycle clock to drive TMR0.

    Sorry I don't use that compiler. I would expect there to be such a way, but also if your TMR0 never increments then the TMR0 rollover ISR is never called.
     
  4. BobTPH

    Active Member

    Jun 5, 2013
    782
    114
    Set a breakpoint in the interrupt handler.


    Bob
     
  5. dayv3

    Thread Starter Member

    May 22, 2014
    31
    0
    Sure, here is the code


    Code ( (Unknown Language)):
    1.  
    2. /* ******   variable declartions     ****** */
    3. int i;
    4.  
    5.  
    6. /* ****** pin assigments     ****** */
    7. #define LED         GPIO.B2     // LED attached to pin 5
    8. #define FT_SWITCH   GPIO.B3     // the physical switch (active low),  pin 4
    9.  
    10. /* ******  constants   ****** */
    11. #define deb_peroid 30         // 30ms - time for the switch to be considered debounced
    12. #define smpl_rate  1          // 1ms - per sample @ 1MHZ CPU clock /4 /TMR0 (sample rate)
    13. #define count_needed (deb_peroid/smpl_rate)  // interations needed for test
    14.  
    15.  /* ******    Global Variables      ****** */
    16. volatile  bit  swt_state;      //  believed  switch state     (0 = pressed)
    17. volatile  bit  swt_changed;    //  switch state change flag   (1 = changed)
    18.   // The above variables are initilized in main()
    19.  
    20.  
    21.  
    22.   void init(void){    //  Initialize 12F683 PIC
    23.  
    24.               TRISIO = 0b00001000;  // configure input/ output pins
    25.                       // pin 4 is an input, the rest are outputs
    26.  
    27.        // configure the pins as digital I/O make sure all i/o pins are
    28.        // digital by turning off the compatitor and a/d
    29.  
    30.                 CMCON0 = 0x07;    // Disable the comparator
    31.                 ANSEL = 0;        // Disable the A/D - Make pins digital i/o
    32.                 ADCON0 = 0;       // A/D converter off
    33.                 CCP1CON = 0;      // compare/ capture/ PWM off
    34.                
    35.        // configure oscillator
    36.                 OSCCON = 0x41;    // select internal clock
    37.                                   // select internal oscillator = 1MHZ
    38.                                   //  -> 4us / instruction cycle
    39.      
    40.          // configure Timer0
    41.                 OPTION_REG = 0x08;   //  select timer mode
    42.                                      //  no prescaling   PSA = 1, WDT = 1
    43.                                      //  -> increment TMR0 every 4us
    44.  
    45.       // initialize i/o ports
    46.           GPIO.B2 = 0;         // make sure that pin 5 output led is off
    47.    
    48.    
    49.                 INTCON = 0xA0;    // global interrupt enable enabled
    50.                                   // timer0 interrupt enable bit enabled
    51.   }  // end initialize PIC
    52.  
    53.  
    54.  
    55. void interrupt(void){   // ISR - interrupt service routine
    56.                         // see data sheet section 12.4 and figure 12-7
    57.    
    58.    static unsigned char  debounce_cnt = 0;       //  debounce counter
    59.      
    60.   if(INTCON.T0IF){    // if timer0 overflows
    61.                        
    62.     INTCON.T0IF = 0;   // clear interupt flag
    63.  
    64.     TMR0 += (256-250-3);     // offset added to timer0 so that it overflows
    65.                              // after 250 counts (ie: overflows every 1ms).
    66.                              // It takes 3 cycles to load the data.
    67.                              
    68.    if(FT_SWITCH == swt_state)       //  Are the physical switch and the switch
    69.           debounce_cnt = 0;         //  state flag the same?  If so reset the
    70.                                     //  counter.
    71.    else{
    72.           ++debounce_cnt;
    73.      if(debounce_cnt == count_needed){  // is the switch is pressed for >= 30ms?
    74.      
    75.           swt_state = FT_SWITCH;  // update debounced state
    76.           debounce_cnt = 0;       // reset debounce count
    77.           swt_changed = 1;        // set switch pressed/ released is valid flag
    78.       }  // end if
    79.     }  // end if
    80.    } // end if
    81.   }  // end ISR
    82.  
    83.  
    84. void main() {
    85.  
    86.    init(void);
    87.    
    88.              / * ******    Initialize Global Variables      ****** */
    89.       swt_state = 1;      //  debounced switch state   (1 = not pressed)
    90.       swt_changed = 0;    //  clear switch state changed flag   (0 = changed)
    91.   // The above variables are declared in the variable declartions section but
    92.   // the compiler requiers them to be initilized here
    93.  
    94. while(1){
    95.  
    96.         // check for and handle debounced switch press
    97.       if(swt_changed && !swt_state){
    98.  
    99.            LED = ~LED;
    100.           swt_changed = 0;
    101.        }   // enf if
    102.      }   // end while
    103.   }   // end maim
    104.  
     
    Last edited by a moderator: Jun 5, 2014
  6. dayv3

    Thread Starter Member

    May 22, 2014
    31
    0
    I spent a lot of time looking at the data sheet and I think that everything is in order but, I am a newbe at this. I am using a momentary switch that is normally open. Pressing the button makes the voltage on pin 4 go low (active low).

    The code is in the above post.

    Thanks,
    Dave
     
  7. BobTPH

    Active Member

    Jun 5, 2013
    782
    114
    The only problem is see is that, in the code below, FT_SWICH might have changed beteeen the first and last statement, which results in sw_state being set incorrectly.

    Code ( (Unknown Language)):
    1.  
    2. if(FT_SWITCH == swt_state) // Are the physical switch and the switch
    3. debounce_cnt = 0; // state flag the same? If so reset the
    4. // counter.
    5. else{
    6. ++debounce_cnt;
    7. if(debounce_cnt == count_needed){ // is the switch is pressed for >= 30ms?
    8.  
    9. swt_state = FT_SWITCH; // update debounced state
    10. debounce_cnt = 0; // reset debounce count
    11. swt_changed = 1; // set switch pressed/ released is valid flag
    12.  
    13.  
    However, this probably is not the whole problem since it should occur very infrequently.

    Bob
     
    Last edited: Jun 5, 2014
  8. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,025
    Are you using the software debugger? From Chapter 2 of the MicroC manual:
    I don't know about the hardware MicroICD.
     
  9. BobTPH

    Active Member

    Jun 5, 2013
    782
    114
    That is a good reason to use MPLAB. It's simulator actually does simulate things like timers and interrupts.

    Bob
     
  10. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,025
    Agreed. You can use MPLAB to sim/debug MicroC by creating a parallel project (same PIC and file list etc.) and importing the .COFF file generated by MicroC into MPLAB 8.x. It will do source level simulation/debugging on code generated by MicroC.

    I haven't tried it in MPLABX - maybe problematic since they are moving away from .COFF.

    I also don't know about hardware debugging (PK2, RealICE) with this approach. Maybe I'll give it a try.
     
  11. dayv3

    Thread Starter Member

    May 22, 2014
    31
    0
    @JohnInTX, Bob, or others, could you please give me more details on how to import the project into mplab ide. I have version 8.92. I have already generated the .cof file.
     
    Last edited: Jun 5, 2014
  12. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    BobTPH caught one serious bug, that you are re-testing the port pin.

    I don't like the way your interrupt is doing the button test and debouncing but then you need to check swt_state again later in main() and do more processing! That's bad form.

    You should have ONE flag sent from int to main, that indicates the button first-press transisiton (1-0 transistion of the port pin).

    You can fix both issues by changing these two code chunks;

    Code ( (Unknown Language)):
    1.  
    2.    // (in interrupt!)
    3.    else
    4.    {
    5.      debounce_cnt++;
    6.      if(debounce_cnt == count_needed)  // is the switch is pressed for >= 30ms?
    7.      {  
    8.           if(swt_state)        // if 1-0 transition
    9.           {
    10.             swt_state = 0;     // update debounced state
    11.             swt_changed = 1;   // set flag for main
    12.           }
    13.           else swt_state = 1;
    14.           debounce_cnt = 0;       // reset debounce count
    15.      }  // end if
    16.    }  
    The above chunk is changed to only set the flag on 1-0 transition (button going down press).

    Code ( (Unknown Language)):
    1.  
    2.       // (in main!)
    3.       // check for and handle debounced switch press
    4.       if(swt_changed)
    5.       {
    6.         swt_changed = 0;
    7.         LED = ~LED;
    8.       }  
    9.  
    That should hopefully fix it. If not, try a test by adding Delay_mS(500) after LED = ~LED.

    And PLEASE use upper case for constants!
    ie it should be;
    if(debounce_cnt == COUNT_NEEDED)
     
  13. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,025
    Sure.
    First, compile your code in MicroC. No Errors. No Warnings.

    Open MPLAB (I'm using 8.63 but yours should be the same).
    Click Project-> New and specify the name and folder for your project. You can use the one that the MicroC is in.
    Click Configure->Select Device and select your PIC.
    Click Debugger->Select Tool and select MPLAB Simulator.
    Click File->Import, navigate to your MicroC folder and select your .COF file.
    Click File->Open and open your MicroC .C source file.
    Click Edit->Properties->Other and checkmark Debugger PC Location - Highlight Full Line.
    Click Configure->Configuration Bits and manually set the PIC config bits (uncheck 'Configuration Bits set in code'). They don't seem to be in the .COF file. There might be a way to include them from MicroC but my efforts so far have been messing with code and sim'ing it in MPLAB due to the limitations of MicroC's sim.
    Save the workspace.

    On the toolbar, click the RESET icon (next to the red circle B(reakpoint). The MPLAB cursor should show up on the first line in main.
    Click View->Watch and watch away as you step through the code. Even interrupt and timer code. Stunning.

    When you modify your code in MicroC then go back to MPLAB, it should prompt you to reload the .C source. Say Yes. BUT, you'll have to File->Import the .COF file each time.

    This is for MPSIM. I haven't tried a hardware debugger - but since its here on the bench......
    EDIT: ...and.. it does NOT work. I can program with RealICE (and presumably PK2/3 et. al.) but NOT use RealICE debug. It makes sense since when you build for debug in MPLAB with RealICE (or PK2 et al) set as the debugger, it adds links to the chip's onboard debugging hardware. MicroC's debugger is different. So.. there you go.

    Haven't looked at your actual code but between Mike and Roman, you're in good hands.
    Have fun!

    +1!
     
    Last edited: Jun 5, 2014
  14. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    I agree with RB... Filter out the "new release" state and toggle the flag on the "new press" state.

    I ported the code over to BoostC running in MPLAB 8.92 and the interrupts are simulating fine, though your constant for reloading TMR0 is off (see listing below). It'll take me a few minutes to setup a hardware test.

    Good luck.

    Cheerful regards, Mike

    Code ( (Unknown Language)):
    1.   /******************************************************************
    2.    *                                                                *
    3.    *  Project: 12F683 Debounce Test                                 *
    4.    *   Source: 12F683_Debounce_Test.c                               *
    5.    *   Author: Mike McLaren, K8LH                                   *
    6.    *     Date: 05-Jun-2014                                          *
    7.    *                                                                *
    8.    *  12F683 Debounce Test Code (AAC Forum)                         *
    9.    *                                                                *
    10.    *                                                                *
    11.    *      IDE: MPLAB 8.92 (tabs = 4)                                *
    12.    *     Lang: Sourceboost BoostC v7.05, Lite/Free version          *
    13.    *                                                                *
    14.    ******************************************************************/
    15.  
    16.    #include <system.h>
    17.  
    18.    #pragma DATA _CONFIG, _MCLRE_OFF & _WDT_OFF & _INTOSCIO
    19.  
    20.    #pragma CLOCK_FREQ 1000000   // 1-MHz INTOSC
    21.  
    22.   /******************************************************************
    23.    *  variables                                                     *
    24.    ******************************************************************/
    25.  
    26.    int i;
    27.  
    28.  
    29.    #define LED         gpio.2   // LED attached to pin 5
    30.    #define FT_SWITCH   gpio.3   // the physical switch (active low),  pin 4
    31.  
    32.   /* ******  constants   ****** */
    33.    #define deb_peroid 30        // 30ms - time for the switch to be considered debounced
    34.    #define smpl_rate  1         // 1ms - per sample @ 1MHZ CPU clock /4 /TMR0 (sample rate)
    35.    #define count_needed (deb_peroid/smpl_rate)  // interations needed for test
    36.  
    37.   /* ******    Global Variables      ****** */
    38.    volatile  bit  swt_state;    // believed  switch state     (0 = pressed)
    39.    volatile  bit  swt_changed;  // switch state change flag   (1 = changed)
    40.  
    41.  
    42.  
    43.    void init()                  // Initialize 12F683 PIC
    44.    { trisio = 0b00001000;       // RA3 (pin 4) input, others outputs
    45.  
    46.      cmcon0 = 0x07;             // Disable the comparator
    47.      ansel = 0;                 // Disable the A/D - Make pins digital i/o
    48.      adcon0 = 0;                // A/D converter off
    49.      ccp1con = 0;               // compare/ capture/ PWM off
    50.                
    51.      osccon = 0x41;             // setup INTOSC = 1-MHz
    52.      
    53.      option_reg = 0x08;         // TMR0 prescaler 1 (4-us ticks)
    54.  
    55.      gpio.2 = 0;                // make sure that pin 5 output led is off
    56.    
    57.      intcon = 1<<GIE|1<<T0IE;   // global & tmr0 interrupts enabled
    58.    }
    59.  
    60.  
    61.    void interrupt()             // ISR - interrupt service routine
    62.    { static unsigned char debounce_cnt = 0;  //  debounce counter
    63.      if(intcon.T0IF)            // if timer0 overflows
    64.      { intcon.T0IF = 0;         // clear interupt flag
    65.        tmr0 += (256-250+3);     // reset for 250 * 4 = 1000 usecs
    66.        if(FT_SWITCH == swt_state)  // Are the physical switch and the switch
    67.          debounce_cnt = 0;         // state flag the same?  If so reset counter
    68.        else
    69.        { ++debounce_cnt;
    70.          if(debounce_cnt == count_needed)  // is the switch is pressed for >= 30ms?
    71.          { swt_state ^= 1;      // update switch state latch
    72.            if(swt_state == 0)   // if "new press"
    73.              swt_changed = 1;   // flag "new press" for main
    74.            debounce_cnt = 0;    // reset debounce count
    75.          }  // end if
    76.        }  // end if
    77.      }  // end if
    78.    }  // end ISR
    79.  
    80.  
    81.    void main()  
    82.    { init();                    //
    83.      swt_state = 1;             // debounced switch state   (1 = not pressed)
    84.      swt_changed = 0;           // clear switch state changed flag   (0 = changed)
    85.  
    86.      while(1)
    87.      { if(swt_changed)          // if "new press" flag
    88.        { LED = ~LED;            // toggle LED and
    89.          swt_changed = 0;       // clear "new press" flag
    90.        }   // enf if
    91.      }   // end while
    92.    }   // end main
    93.  
     
    Last edited: Jun 5, 2014
  15. dayv3

    Thread Starter Member

    May 22, 2014
    31
    0
    First of all, thank you all for the help that everyone gave me with this. I made the corrections suggested and made the constants UPPER CASE. The directions for using MPLAB were better, to me, then what I found in the help section. Once again, thanks everyone. The program works fine. I was able to one step thru the code using MPLAB, (why don't the MikroC people fix this.) and it works as written being that the LED follows the state of the momentary switch.

    However, I was trying to have the LED to change states as a result of the button being pressed. For example, press (and release) the button once the LED turns on. Press the button again and the LED turns off. Could someone please give me some suggestions on the best path to follow to work thru this second piece of the puzzle?

    Thanks,
    Dave
     
  16. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Yep, that's how it works on real hardware. I just modified the BoostC code below to use GP0 (pin 7) instead of GP3 (pin 4) with WPU (weak pull-up) so I didn't have to goof around with a physical pull-up resistor for GP3.

    Code ( (Unknown Language)):
    1.  
    2.   /******************************************************************
    3.    *                                                                *
    4.    *  Project: 12F683 Debounce Test                                 *
    5.    *   Source: 12F683_Debounce_Test.c                               *
    6.    *   Author: Mike McLaren, K8LH                                   *
    7.    *  (C)2012: Micro Application Consultants                        *
    8.    *     Date: 05-Jun-2014                                          *
    9.    *                                                                *
    10.    *  12F683 Debounce Test Code (AAC Forum)                         *
    11.    *                                                                *
    12.    *                                                                *
    13.    *      IDE: MPLAB 8.92 (tabs = 4)                                *
    14.    *     Lang: Sourceboost BoostC v7.05, Lite/Free version          *
    15.    *                                                                *
    16.    ******************************************************************/
    17.  
    18.    #include <system.h>
    19.  
    20.    #pragma DATA _CONFIG, _MCLRE_OFF & _WDT_OFF & _INTOSCIO
    21.  
    22.    #pragma CLOCK_FREQ 1000000   // 1-MHz INTOSC
    23.  
    24.   /******************************************************************
    25.    *  variables                                                     *
    26.    ******************************************************************/
    27.  
    28.    int i;
    29.  
    30.  
    31.    #define LED         gpio.2   // LED attached to pin 5
    32.    #define FT_SWITCH   gpio.0   // active lo switch on RA0  pin 4
    33.  
    34.   /* ******  constants   ****** */
    35.    #define deb_peroid 30        // 30ms - time for the switch to be considered debounced
    36.    #define smpl_rate  1         // 1ms - per sample @ 1MHZ CPU clock /4 /TMR0 (sample rate)
    37.    #define count_needed (deb_peroid/smpl_rate)  // interations needed for test
    38.  
    39.   /* ******    Global Variables      ****** */
    40.    volatile  bit  swt_state;    // believed  switch state     (0 = pressed)
    41.    volatile  bit  swt_changed;  // switch state change flag   (1 = changed)
    42.  
    43.  
    44.  
    45.    void init()                  // Initialize 12F683 PIC
    46.    { trisio = 0b00001001;       // RAo (pin 7) input, others outputs
    47.  
    48.      cmcon0 = 0x07;             // Disable the comparator
    49.      ansel = 0;                 // Disable the A/D - Make pins digital i/o
    50.      adcon0 = 0;                // A/D converter off
    51.      ccp1con = 0;               // compare/ capture/ PWM off
    52.                
    53.      osccon = 0x41;             // setup INTOSC = 1-MHz
    54.      
    55.      option_reg = 0x08;         // TMR0 prescaler 1 (4-us ticks)
    56.                                 // weak pull-ups enabled
    57.      wpu.0 = 1;                 // RA0 pull-up
    58.      gpio.2 = 0;                // make sure that pin 5 output led is off
    59.    
    60.      intcon = 1<<GIE|1<<T0IE;   // global & tmr0 interrupts enabled
    61.    }
    62.  
    63.  
    64.    void interrupt()             // ISR - interrupt service routine
    65.    { static unsigned char debounce_cnt = 0;  //  debounce counter
    66.      if(intcon.T0IF)            // if timer0 overflows
    67.      { intcon.T0IF = 0;         // clear interupt flag
    68.        tmr0 += (256-250+3);     // reset for 250 * 4 = 1000 usecs
    69.        if(FT_SWITCH == swt_state)  // Are the physical switch and the switch
    70.          debounce_cnt = 0;         // state flag the same?  If so reset counter
    71.        else
    72.        { ++debounce_cnt;
    73.          if(debounce_cnt == count_needed)  // is the switch is pressed for >= 30ms?
    74.          { swt_state ^= 1;      // update switch state latch
    75.            if(swt_state == 0)   // if "new press"
    76.              swt_changed = 1;   // flag "new press" for main
    77.            debounce_cnt = 0;         // reset debounce count
    78.          }  // end if
    79.        }  // end if
    80.      }  // end if
    81.    }  // end ISR
    82.  
    83.  
    84.    void main()  
    85.    { init();                    //
    86.      swt_state = 1;             // 1 = not pressed
    87.      swt_changed = 0;           // clear "new press" flag
    88.  
    89.      while(1)
    90.      { if(swt_changed)          // if "new press" flag
    91.        { LED = ~LED;            // toggle LED and
    92.          swt_changed = 0;       // clear flag
    93.        }   // enf if
    94.      }   // end while
    95.    }   // end maim
    96.  
     
    Last edited: Jun 7, 2014
  17. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
  18. dayv3

    Thread Starter Member

    May 22, 2014
    31
    0
    @MMcLaren, WOW!! Thanks, even a video.

    Was the switch you used normally open or closed?
    The one I have is normally open.
    For these types of projects which kind better?

    Dave
     
    Last edited: Jun 7, 2014
  19. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    T'is a standard "normally open" momentary push button switch...

    My name is Mike. Nice to meet you...
     
  20. dayv3

    Thread Starter Member

    May 22, 2014
    31
    0
    Mike, pleased to meet you too... I have friends that I play guitar with in Monroe.

    I am confused. In the code above (post# 16) the only thing you did was change the
    #define FT_SWITCH and TRISO and then added the line WPU.0 = 1.

    How did this (WPU) make it change states as a result of the button press verse follow the push button like it did before?

    My button circuit has 5v thru a 10K resistor and then thru a 1k to pin 4. My push button in then connected between the junction of the 10K and 1K resistor to ground.

    Being that you went back to the original and there is not a WPU for pin 4 how is your switch wired? If there was a WPU setting for a given pin I can see 5V -> resistor -> switch -> pin X but...

    Now I am confused twice because, to me, the WPU acts like a software enabled physical resistor to get rid of floating pins without having to use a physical resistor, but pin 4 (GP3) does not have a WPU enable bit in the WPU register.

    Something is just not making sense.

    Dave
     
    Last edited: Jun 7, 2014
Loading...