PIC Development Board with PK3

JohnInTX

Joined Jun 26, 2012
4,787
Can you point out where exactly the problem is occurring?
It looks to me like it toggles the LED while the button is held then leaves it on or off at random when the button is released.
Think about what you are trying to do. Doing one thing per one press of the button requires that you detect TWO button actions:
1) the closing and debouncing of the switch - you are doing that
2) it also requires detecting when the finger is removed from the button too.
Those two actions make up ONE press of the button.

So after you detect the button pushed (BUTTON_x==1)and toggle the LED you have to next detect the button open again (BUTTON_x==0) before you can test for the button closed again. There are several ways to implement that action but there are some potential problems:
You can not just wait for the switch to open - the goal non-blocking code
Your loop must keep calling Run_Debounce() at 1ms intervals to update the BUTTON_x flag.

Give it some thought and let us know what you are thinking before you code it. The goal right now is to learn about some of the challenges presented by this implementation so far.
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Give it some thought and let us know what you are thinking before you code it. The goal right now is to learn about some of the challenges presented by this implementation so far.
Switch debounce in both ways. when the switch is pressed and when it is released

Check switch is open or close in every 1ms

if the switch is closed and switch is the same state as the last interrupt, Increment counter

if the switch is open and switch is the different state as the last interrupt , Decrement counter

When the counter reaches the maximum value 10 , consider the switch pressed.

When counter reaches zero, consider it release
 

JohnInTX

Joined Jun 26, 2012
4,787
Not really. You have just described a different way to debounce the switch. The switch is debounced already.

What is the key piece of information that you need about the state of the switch that you need to toggle the LED?
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
What is the key piece of information that you need about the state of the switch that you need to toggle the LED?
Look like something

If switch pressed and debounced, Turn ON LED

If switch pressed again and debounced, Turn OFF LED

Repeat

I have tried same logic in #458. I didn't get the result as it should supposed to do
 

JohnInTX

Joined Jun 26, 2012
4,787
If switch pressed and debounced, Turn ON LED
If switch pressed again and debounced, Turn OFF LED
Repeat

I have tried same logic in #458. I didn't get the result as it should supposed to do
Not really. Your logic in #458 is:
Toggle the LED while the switch is pressed and stop when it is released.
if(BUTTON_x == 1) LED =~ LED;
You want to change the LED when the switch is pressed. That means when the value of BUTTON_x changes from 0 to 1. That means you have to detect when the value of BUTTON_x changes from 0 to 1 as you loop through main and ignore ALL other states. How do you detect a that change from 0 to 1 in a system that only samples BUTTON_x periodically?

Consider this:
The switch condition, indicated by BUTTON_x, is sampled periodically. Between samples, BUTTON_x can change or stay the same. There are 4 combinations of the switch state possible.

Example: 0->1 means that BUTTON_x was 0 on the previous sample and is now 1.
  1. 0 -> 0: The button was open and is still open ( no finger on the button)
  2. 0 -> 1: The button was open but has changed to 1 (button has just been pressed)
  3. 1 -> 1: The button was closed and is still closed (finger still on button)
  4. 1 -> 0: The button was closed and is not open (button has just been released).

Of these 4 conditions, you want to detect #2 (0_1) and toggle the LED. Ignore all of the other combinations.
Obviously, you need to 'remember' what the state of the button was on the last sample. I would use a new flag for that (PREVIOUS_BUTTON_x).

With that, how would you do the logic to toggle the LED each time BUTTON_x went from 0 to 1?

Note that this is no longer a debounce problem. The button is debounced. This is a logic problem now. Figure that out, post a valid solution. It can be pseudo-code, it doesn't have to be compiled and tested unless you want to try it.

Good luck!

Edit: name of previous button state
 
Last edited:

trebla

Joined Jun 29, 2019
599
LED ~= LED; // change LED state
This is an unary operator, you can't use it in that way, use LED =~LED;

I tried to trace the logic problem in the code but don't know where exactly the problem is happening. Can you point out where exactly the problem is occurring?
Imagination will help you. Imagine the interrupt occurs every millisecond when you pressed or released the button which debounced during 3 milliseconds on and off. You will never know in which state the button is read during the interrupt. Solution is read the first occurence of button press and then ignore the button during debounce period (20ms) and then read it again to ensure it is released. You _need_ introduce a variable to hold button state and a counter variable for counting this "ignore" time.
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Note that this is no longer a debounce problem. The button is debounced. This is a logic problem now. Figure that out, post a valid solution. It can be pseudo-code, it doesn't have to be compiled and tested unless you want to try it.
You @JohnInTX and @trebla helped me a lot on this topic, but I couldn't understand, so I stopped replying. I invested my time and tried to figure it out myself

My understanding is as following

Toggling LED
1. check if button pressed and stable, Yes
2. Check if button is not hold down, Yes
3. Check if button released and stable, Yes
4. Toggle LED
4. Repeat all.

Button considered pressed and stable If the button is continuously high for 10 times. Button considered released and stable If the button is continuously low for 10 times.

Run_Debounce routine check If the button is continuously high for 10 times, it is considered pressed and stable.

Now we need to check If the button is continuously low for 10 times, it would considered released and stable.
 

trebla

Joined Jun 29, 2019
599
Now we need to check If the button is continuously low for 10 times, it would considered released and stable
If MCU instruction clock is 8 MHz then checking the button for 10 times takes only couple of microseconds, button contact can bounce couple of milliseconds, 1000 times longer.
You better introduce a variable flag to mark button pressed status an then check only timer if the debounce time is passed and you can check the real button state again. You can toggle the LED before debounce timer starting if you like.
 

JohnInTX

Joined Jun 26, 2012
4,787
My understanding is as following

Toggling LED
1. check if button pressed and stable, Yes
2. Check if button is not hold down, Yes
3. Check if button released and stable, Yes
4. Toggle LED
4. Repeat all.

Button considered pressed and stable If the button is continuously high for 10 times. Button considered released and stable If the button is continuously low for 10 times.

Run_Debounce routine check If the button is continuously high for 10 times, it is considered pressed and stable.

Now we need to check If the button is continuously low for 10 times, it would considered released and stable.
No.

The switch is already debounced. This is now a logic problem using the clean switch output from the debouncer. There is no need to count 10 of anything at this level. #465 shows that you need to be detecting the 0->1 transition of the BUTTON_x flag and toggle the LED then. Nothing more.

How would you detect a 0-1 transition?

EDIT: let’s save some time here:

in the main loop:

if((PREVIOUS_BUTTON_x == 0) && (BUTTON_x==1)) { // 0-1 transition
Toggle the LED;
}
PREVIOUS_BUTTON_x = BUTTON_x; // update ‘previous’ condition every time through
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
No.

The switch is already debounced. This is now a logic problem using the clean switch output from the debouncer. There is no need to count 10 of anything at this level. #465 shows that you need to be detecting the 0->1 transition of the BUTTON_x flag and toggle the LED then. Nothing more.
thank you, code work as Press once to turn the LED on continuously. Press again to turn the LED off.
C:
#define _XTAL_FREQ 8000000

#include <xc.h>
// PIC18F45K80 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1L
#pragma config RETEN = OFF      // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF       // Extended Instruction Set (Enabled)
// CONFIG1H
#pragma config FOSC = INTIO2    // Oscillator (Internal RC oscillator)
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = OFF     // Power Up Timer (Disabled)
#pragma config BOREN = SBORDIS  // Brown Out Detect (Enabled in hardware, SBOREN disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)
// CONFIG3H
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)
// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-01FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 02000-03FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 04000-05FFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 06000-07FFF (Disabled)
// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)
// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-01FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 02000-03FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 04000-05FFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 06000-07FFF (Disabled)
// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)
// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-01FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 02000-03FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 04000-05FFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 06000-07FFF (Disabled)
// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)

unsigned char counter;
__bit BUTTON_x;
__bit PREVIOUS_BUTTON_x = 0;
__bit Interrupt_Flag_1ms;

#define Button          PORTBbits.RB0
#define LED             LATDbits.LATD2
#define DEBOUNCE_TIKS  10

void Port_Initialized (void);
void Timer0_Initialized (void);
void __interrupt(high_priority) tcInt(void);

void Port_Initialized (void)
{
    // LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;      // All are output, Unused
    TRISB = 0xFF;      // Button connected to RB0
    TRISC = 0x00;      // all are output, Unused
    TRISD = 0x00;      // LED connected to RD2 pin
    TRISE = 0x00;      // All are output, Unused

    ANCON0 = 0x00;     // set to digital port
    ANCON1 = 0x00;     // Set to digital port
    CM1CON = 0x00;     // Comparator off
    CM2CON = 0x00;     // Comparator off
    ADCON0 = 0x00;     // A/D conversion Disabled
    ADCON1 = 0x00;     // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

void Timer0_Initialized (void)
{
     TMR0L = 250;    //Timer0 Register Low Byte

    //T0CON: TIMER0 CONTROL REGISTER
     TMR0ON = 1; //Timer0 On
     T08BIT = 1; // Timer0 is configured as an 8-bit timer/counter0
     T0CS = 0;   // Internal instruction cycle clock (CLKO)
     T0SE = 1;    //Increments on high-to-low transition on T0CKI pin0
     PSA = 0; //Timer0 prescaler is assigned; Timer0 clock input comes from prescaler output
     //1:8 Prescale value
     T0PS2 = 1;
     T0PS1 = 1;
     T0PS0 = 1;
     //INTCON: INTERRUPT CONTROL

     PEIE = 0;   //Disables all peripheral interrupts
     TMR0IE = 1; //Enables the TMR0 overflow interrupt
     INT0IE = 0; //Disables the INT0 external interrupt
     RBIE = 0; //Disables the RB port change interrupt
     TMR0IF = 0;// cleared timer overflow flag
     INT0IF = 0; // disabled external interrupt
     RBIF = 0; //disabled Port Change Interrupt Flag bit
     GIE = 1;    // Enable Global Interrupt Enable bit
}

void Run_Debounce(void)
{
  if (Button == 0)
  {
    counter = 0;  // button is open, reset everything
    BUTTON_x = 0;
  }
  else
  {
    if(BUTTON_x == 0)
    {
      counter++;
      if(counter == DEBOUNCE_TIKS)
        BUTTON_x = 1;    // fully debounced
    } // else, button TRUE and is already debounced, nothing to do
  }

}

void main(void)
{
    Port_Initialized ();
    Timer0_Initialized ();
    LED = 0;
    while (1)
    {
        if (Interrupt_Flag_1ms == 1)
           {
               Interrupt_Flag_1ms = 0;  // clear the flag for next time
               Run_Debounce();        // process switch
           }
      
        if((PREVIOUS_BUTTON_x == 0) && (BUTTON_x==1))
        {
          LED =~ LED;
         }
        PREVIOUS_BUTTON_x = BUTTON_x; // update ‘previous’ condition every time through
}
}

void __interrupt(high_priority) tcInt(void)
{
  if (TMR0IF == 1) // Timer0 overflow interrupt flag bit
  {
      TMR0IF = 0;
      TMR0L = 250;    //Timer0 Register Low Byte
      Interrupt_Flag_1ms = 1;

  }

  }
 

JohnInTX

Joined Jun 26, 2012
4,787
thank you, code work as Press once to turn the LED on continuously. Press again to turn the LED off.
You should take the time to completely understand it.. not only the code but the logical approach to solving the problem given the tools and functions at hand. If you don’t, you will continue to have trouble solving these simple problems.

But nothing succeeds like success.

Do you want to know my favorite method of doing this kind of thing?
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Do you want to know my favorite method of doing this kind of thing?
i was trying to understand the logic problem so i didn't answer for so many days. I was reading my previous post what I was told to do. I posted whatever I could understand in #467. I tried whatever possible solution was there to solve the problem but I did not get success.

Here's my complete failure I couldn't think of how to solve the problem.
 

JohnInTX

Joined Jun 26, 2012
4,787
why there particular 1ms time interval It could have been anything like 5ms, 10ms, 15ms, 20ms
That’s correct, any of those values would work. I picked 1ms because it is a nice value to work with, does not use too much of the 20MHz processor and is close to the bounce time of a TACT switch so that the number of DEBOUNCE_TIKS can be accumulated relatively quickly after the switch is stable. That improves system response to input changes. Sometimes that is important.
What is your favorite method?
I like detecting and indicating the 0-1 teansition in the debounce routine instead of doing the logical test of current and previous values in the main code like we are currently doing. It is common to use a button or group of buttons for different things in different parts of the code. For example, a digital clock might have a set of buttons that change the display from 12 to 24 hour format, show the date etc. The same buttons could be used for setting the clock and date in a different part of the code. Rather than rewrite the 0-1 test each time for all is the different ways the button could be used, just incorporate the logic in a SINGLE place in the debounce routine.

In our debounce routine, BUTTON_x is set once when the debounce is complete. At that point, also set another flag NEW_BUTTON_x to indicate a new 0-1 transition. Then in main:

if(NEW_BUTTON_x==1)
{
toggle the LED;
NEW_BUTTON_x = 0; // acknowledge the 0-1 transition.
}

Note that you now have two flags for the button. One indicates the current state of the switch and the other indicates the important 0-1 transition. Either or both can be used at the same time.

A useful exercise would be to use the two flags to toggle one LED on each press of the button and use another LED to indicate the whether the button is being held or released.

Have fun.
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
I like detecting and indicating the 0-1 teansition in the debounce routine instead of doing the logical test of current and previous values in the main code like we are currently doing.
I was bit busy due to exam so couldn't update. I would like to bring your attention on #427.. I I have learned to read one switch with timer interrupt. I want to read four switch's with timer interrupt

Code indicating the 0-1 transition in the debounce routine
C:
#define _XTAL_FREQ 8000000

#include <xc.h>
// PIC18F45K80 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1L
#pragma config RETEN = OFF      // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF       // Extended Instruction Set (Enabled)
// CONFIG1H
#pragma config FOSC = INTIO2    // Oscillator (Internal RC oscillator)
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = OFF     // Power Up Timer (Disabled)
#pragma config BOREN = SBORDIS  // Brown Out Detect (Enabled in hardware, SBOREN disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)
// CONFIG3H
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)
// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-01FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 02000-03FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 04000-05FFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 06000-07FFF (Disabled)
// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)
// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-01FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 02000-03FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 04000-05FFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 06000-07FFF (Disabled)
// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)
// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-01FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 02000-03FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 04000-05FFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 06000-07FFF (Disabled)
// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)

unsigned char counter;
__bit BUTTON_x;
__bit PREVIOUS_BUTTON_x = 0;
__bit Interrupt_Flag_1ms;

#define Button          PORTBbits.RB0
#define LED1             LATDbits.LATD2
#define LED2             LATDbits.LATD1
#define DEBOUNCE_TIKS  10

void Port_Initialized (void);
void Timer0_Initialized (void);
void __interrupt(high_priority) tcInt(void);

void Port_Initialized (void)
{
    // LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;      // All are output, Unused
    TRISB = 0xFF;      // Button connected to RB0
    TRISC = 0x00;      // all are output, Unused
    TRISD = 0x00;      // LED connected to RD2 pin
    TRISE = 0x00;      // All are output, Unused

    ANCON0 = 0x00;     // set to digital port
    ANCON1 = 0x00;     // Set to digital port
    CM1CON = 0x00;     // Comparator off
    CM2CON = 0x00;     // Comparator off
    ADCON0 = 0x00;     // A/D conversion Disabled
    ADCON1 = 0x00;     // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

void Timer0_Initialized (void)
{
     TMR0L = 250;    //Timer0 Register Low Byte

    //T0CON: TIMER0 CONTROL REGISTER
     TMR0ON = 1; //Timer0 On
     T08BIT = 1; // Timer0 is configured as an 8-bit timer/counter0
     T0CS = 0;   // Internal instruction cycle clock (CLKO)
     T0SE = 1;    //Increments on high-to-low transition on T0CKI pin0
     PSA = 0; //Timer0 prescaler is assigned; Timer0 clock input comes from prescaler output
     //1:8 Prescale value
     T0PS2 = 1;
     T0PS1 = 1;
     T0PS0 = 1;
     //INTCON: INTERRUPT CONTROL

     PEIE = 0;   //Disables all peripheral interrupts
     TMR0IE = 1; //Enables the TMR0 overflow interrupt
     INT0IE = 0; //Disables the INT0 external interrupt
     RBIE = 0; //Disables the RB port change interrupt
     TMR0IF = 0;// cleared timer overflow flag
     INT0IF = 0; // disabled external interrupt
     RBIF = 0; //disabled Port Change Interrupt Flag bit
     GIE = 1;    // Enable Global Interrupt Enable bit
}

void Run_Debounce(void)
{
  if (Button == 0)
  {
    counter = 0;  // button is open, reset everything
    BUTTON_x = 0;
  }
  else
  {
    if(BUTTON_x == 0)
    {
      counter++;
      if(counter == DEBOUNCE_TIKS)
        BUTTON_x = 1;    // fully debounced
            
        if((PREVIOUS_BUTTON_x == 0) && (BUTTON_x==1))
        {
          LED1 =~ LED1;
         }
      
        PREVIOUS_BUTTON_x = BUTTON_x; // update ?previous? condition every time through
        
 //       PREVIOUS_BUTTON_x = BUTTON_x; // update ?previous? condition every time through
    } // else, button TRUE and is already debounced, nothing to do
  }

}

void main(void)
{
    Port_Initialized ();
    Timer0_Initialized ();
    LED1 = 0;
     LED2 = 0;
    while (1)
    {
        if (Interrupt_Flag_1ms == 1)
           {
               Interrupt_Flag_1ms = 0;  // clear the flag for next time
               Run_Debounce();        // process switch
           }
}
}

void __interrupt(high_priority) tcInt(void)
{
  if (TMR0IF == 1) // Timer0 overflow interrupt flag bit
  {
      TMR0IF = 0;
      TMR0L = 250;    //Timer0 Register Low Byte
      Interrupt_Flag_1ms = 1;

  }

  }
 

JohnInTX

Joined Jun 26, 2012
4,787
I hope you did well on your exams.

There are many ways to expand what you have to process more than one switch.

The easiest way is to just replicate the debounce code 4 times with 4 BUTTON_x flags, BUTTON_0, BUTTON_1 etc. You have plenty of code space and simple is good.

Another way that is popular here is to read all 4 buttons and debounce any change. When a change in any button is detected run the debounce until stable then update the 4 flags.

There are a few more methods that might be more structured, use less code etc. but either of the ones I described would be a good starting point. Give it some thought and see what you might be comfortable with.
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Another way that is popular here is to read all 4 buttons and debounce any change. When a change in any button is detected run the debounce until stable then update the 4 flags.
I will read all 4 buttons and debounce any change algorithm. My planning is that I first check if any switch is closed if any then I test which switch is closed. then I check if flag is set. I don't have idea how each switch will be debounced ?

C:
#define _XTAL_FREQ 8000000

#include <xc.h>
// PIC18F45K80 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1L
#pragma config RETEN = OFF      // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF       // Extended Instruction Set (Enabled)
// CONFIG1H
#pragma config FOSC = INTIO2    // Oscillator (Internal RC oscillator)
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = OFF     // Power Up Timer (Disabled)
#pragma config BOREN = SBORDIS  // Brown Out Detect (Enabled in hardware, SBOREN disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)
// CONFIG3H
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)
// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-01FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 02000-03FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 04000-05FFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 06000-07FFF (Disabled)
// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)
// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-01FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 02000-03FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 04000-05FFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 06000-07FFF (Disabled)
// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)
// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-01FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 02000-03FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 04000-05FFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 06000-07FFF (Disabled)
// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)

unsigned char counter;
__bit BUTTON_x1;
__bit BUTTON_x2;
__bit BUTTON_x3;
__bit BUTTON_x4;

__bit PREVIOUS_BUTTON_x1 = 0;
__bit PREVIOUS_BUTTON_x2 = 0;
__bit PREVIOUS_BUTTON_x3 = 0;
__bit PREVIOUS_BUTTON_x4 = 0;

__bit Interrupt_Flag_1ms;

#define Button_1          PORTBbits.RB0
#define Button_2          PORTBbits.RB1
#define Button_3          PORTBbits.RB2
#define Button_4          PORTBbits.RB3

#define LED_1             LATDbits.LATD0
#define LED_2             LATDbits.LATD1
#define LED_3             LATDbits.LATD2
#define LED_4             LATDbits.LATD3

#define DEBOUNCE_TIKS  10

void Port_Initialized (void);
void Timer0_Initialized (void);
void __interrupt(high_priority) tcInt(void);

void Port_Initialized (void)
{
    // LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;      // All are output, Unused
    TRISB = 0xFF;      // Button connected to RB0
    TRISC = 0x00;      // all are output, Unused
    TRISD = 0x00;      // LED connected to RD2 pin
    TRISE = 0x00;      // All are output, Unused

    ANCON0 = 0x00;     // set to digital port
    ANCON1 = 0x00;     // Set to digital port
    CM1CON = 0x00;     // Comparator off
    CM2CON = 0x00;     // Comparator off
    ADCON0 = 0x00;     // A/D conversion Disabled
    ADCON1 = 0x00;     // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

void Timer0_Initialized (void)
{
     TMR0L = 250;    //Timer0 Register Low Byte

    //T0CON: TIMER0 CONTROL REGISTER
     TMR0ON = 1; //Timer0 On
     T08BIT = 1; // Timer0 is configured as an 8-bit timer/counter0
     T0CS = 0;   // Internal instruction cycle clock (CLKO)
     T0SE = 1;    //Increments on high-to-low transition on T0CKI pin0
     PSA = 0; //Timer0 prescaler is assigned; Timer0 clock input comes from prescaler output
     //1:8 Prescale value
     T0PS2 = 1;
     T0PS1 = 1;
     T0PS0 = 1;
     //INTCON: INTERRUPT CONTROL

     PEIE = 0;   //Disables all peripheral interrupts
     TMR0IE = 1; //Enables the TMR0 overflow interrupt
     INT0IE = 0; //Disables the INT0 external interrupt
     RBIE = 0; //Disables the RB port change interrupt
     TMR0IF = 0;// cleared timer overflow flag
     INT0IF = 0; // disabled external interrupt
     RBIF = 0; //disabled Port Change Interrupt Flag bit
     GIE = 1;    // Enable Global Interrupt Enable bit
}

void Run_Debounce(void)
{
  if ((Button_1 == 0)|| (Button_2 == 0)|| (Button_3 == 0)|| (Button_4 == 0))
  {
    counter = 0;  // button is open, reset everything
    
    BUTTON_x1 = 0;
    BUTTON_x2 = 0;
    BUTTON_x3 = 0;
    BUTTON_x4 = 0;
  }
  else
  {
    if(BUTTON_x1 == 0)
    {
      counter++;
      if(counter == DEBOUNCE_TIKS)
        BUTTON_x1 = 1;    // fully debounced
    } // else, button TRUE and is already debounced, nothing to do 
  }

}

void main(void)
{
    Port_Initialized ();
    Timer0_Initialized ();
    LED_1 = 0;
    LED_2 = 0;
    while (1)
    {
        if (Interrupt_Flag_1ms == 1)
           {
               Interrupt_Flag_1ms = 0;  // clear the flag for next time
               Run_Debounce();        // process switch
           }
      
        if((PREVIOUS_BUTTON_x1 == 0) && (BUTTON_x1==1))
        {
          LED_1 =~ LED_1;
        }
      
        PREVIOUS_BUTTON_x1 = BUTTON_x1; // update ?previous? condition every time through
}
}

void __interrupt(high_priority) tcInt(void)
{
  if (TMR0IF == 1) // Timer0 overflow interrupt flag bit
  {
      TMR0IF = 0;
      TMR0L = 250;    //Timer0 Register Low Byte
      Interrupt_Flag_1ms = 1;

  }

  }
 

trebla

Joined Jun 29, 2019
599
For multiple inputs to read and debounce my approach would be define a structure with a counter and status flags for each input:

C:
struct btn_debounce  {


    unsigned char counter;
    char status :1; //one bit flags
    char prev_status :1;
} Button_x1, Button_x2, Button_x3, Button_x4;
Then you can access the counter like :

Button_x2.counter++; //increment debounce counter

and flags:

Button_3.status = 0; //not pressed


EDIT: If you like, you can use this structure for define a button array like:
struct btn_debounce Buttons[8]; //array for 8 buttons (0 to 7)
 
Last edited:
Top