#### ke5nnt

Joined Mar 1, 2009
384
Hey guys,

I wanted to build a circuit and a program to test switch debouncing routines to see how well each one works. The general idea was that I would build a small circuit with a 7-segment display that starts at the number 0. Each time the button is pressed it generates an interrupt that increments the number, and after a delay of 6 seconds, writes the number to eeprom so that after a reset, the 7-segment would return to that number. This would indicate whether the button press was incrementing the desired loop by more than 1 in order to see how stable the debounce routine is.

The problem in my code is, that after a button press, the number doesn't increment on the display until after the 6 seconds has expired and the eeprom write completes. Before that, it continues to display the previous number. For instance, if the 7-segment is showing a 0 and I press a button, the display continues to show 0 for 6 seconds and then increments to 1, rather than going to 1 immediately after the button press like I want.

You can find the program and a schematic of the circuit below. One other thing I would like to know is whether the way I've programmed the display is the best way (flashing 1 segment at a time rapidly in order to keep current from exceeding device limits). Thanks for the help.

Rich (BB code):
//        CONFIGURATION

#include <htc.h>
#define _XTAL_FREQ 4000000
__CONFIG(BOREN_OFF & MCLRE_OFF & PWRTE_ON & WDTE_OFF & FOSC_INTOSCIO & LVP_OFF);

/*****************************************************/

//        GLOBAL VARIABLS

unsigned char fpnum;        //FLASH PATTERN NUMBER
unsigned char dlycnt;        //COUNTER FOR DELAY
unsigned char count;        //GENERAL COUNTER VARIABLE
unsigned char dbnce;        //SWITCH DEBOUNCE COUNTER
unsigned char tcnt;            //COUNTER FOR TIMER 0
bit ewrit;                    //SETS READY TO WRITE EEPROM
/*****************************************************/

//        MAIN PROGRAM

void main()
{
//        OPTIONS
T0CS = 0;                    //TMR0 SOURCE IS INTERNAL CLOCK
PSA = 0;                    //PRESCALER IS ASSIGNED TO TMR0
PS2 = 1;
PS1 = 1;
PS0 = 1;                    //PRESCALER IS 1:256
//        INTCON
INTE = 1;                    //ENABLE EXTERNAL INTERRUPT ON RB0/INT
GIE = 1;                    //ENABLE GLOBAL INTERRUPTS

//        GPIO PORT
TRISA=0X3C;                    //TRISA <7:6>OUT <5:2>IN <1:0>OUT
TRISB=0XF;                    //TRISB <7:4>OUT <3:0>IN

PORTA=0;
PORTB=0;                    //CLEAR PORTS

for (count=0; count<4; count++)
{
RB5=1;
__delay_ms(250);
RB5=0;
__delay_ms(250);        //FLASH THE DECIMAL POINT 4 TIMES
}

while(1)                    //BEGIN MAIN LOOP
{
/******************DISPLAY A "1"**********************/

if (fpnum==1)
{
while (ewrit!=0)        //IF EEPROM FLAG IS SET
{
eeprom_write(address, fpnum);        //WRITE FPNUM TO THE EEPROM
ewrit=0;                //AND CLEAR THE EEPROM FLAG
}
while (ewrit==0)        //IF EEPROM FLAG IS CLEAR
{
RB6=1;
__delay_us(100);
RB6=0;
RB4=1;
__delay_us(100);
RB4=0;
}
}
/*****************DISPLAY A "2"***********************/

else if (fpnum==2)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RB6=1;
__delay_us(100);
RB6=0;
RA0=1;
__delay_us(100);
RA0=0;
RA7=1;
__delay_us(100);
RA7=0;
RA6=1;
__delay_us(100);
RA6=0;
}
}
/****************DISPLAY A "3"************************/

else if (fpnum==3)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RB6=1;
__delay_us(100);
RB6=0;
RA0=1;
__delay_us(100);
RA0=0;
RB4=1;
__delay_us(100);
RB4=0;
RA6=1;
__delay_us(100);
RA6=0;
}
}
/***************DISPLAY A "4"*************************/

else if (fpnum==4)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RA1=1;
__delay_us(100);
RA1=0;
RB6=1;
__delay_us(100);
RB6=0;
RA0=1;
__delay_us(100);
RA0=0;
RB4=1;
__delay_us(100);
RB4=0;
}
}
/***************DISPLAY A "5"*************************/

else if (fpnum==5)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RA1=1;
__delay_us(100);
RA1=0;
RA0=1;
__delay_us(100);
RA0=0;
RB4=1;
__delay_us(100);
RB4=0;
RA6=1;
__delay_us(100);
RA6=0;
}
}
/***************DISPLAY A "6"*************************/

else if (fpnum==6)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RA1=1;
__delay_us(100);
RA1=0;
RA0=1;
__delay_us(100);
RA0=0;
RA7=1;
__delay_us(100);
RA7=0;
RB4=1;
__delay_us(100);
RB4=0;
RA6=1;
__delay_us(100);
RA6=0;
}
}
/*****************DISPLAY A "7"***********************/

else if (fpnum==7)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RB6=1;
__delay_us(100);
RB6=0;
RB4=1;
__delay_us(100);
RB4=0;
}
}
/*****************DISPLAY A "8"***********************/

else if (fpnum==8)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RA1=1;
__delay_us(100);
RA1=0;
RB6=1;
__delay_us(100);
RB6=0;
RA0=1;
__delay_us(100);
RA0=0;
RA7=1;
__delay_us(100);
RA7=0;
RB4=1;
__delay_us(100);
RB4=0;
RA6=1;
__delay_us(100);
RA6=0;
}
}
/******************DISPLAY A "9"**********************/

else if (fpnum==9)
{
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RA1=1;
__delay_us(100);
RA1=0;
RB6=1;
__delay_us(100);
RB6=0;
RA0=1;
__delay_us(100);
RA0=0;
RB4=1;
__delay_us(100);
RB4=0;
}
}
/******************DISPLAY A "0"**********************/

else
{
fpnum=0;
while (ewrit!=0)
{
ewrit=0;
}
while (ewrit==0)
{
RB7=1;
__delay_us(100);
RB7=0;
RA1=1;
__delay_us(100);
RA1=0;
RB6=1;
__delay_us(100);
RB6=0;
RA7=1;
__delay_us(100);
RA7=0;
RB4=1;
__delay_us(100);
RB4=0;
RA6=1;
__delay_us(100);
RA6=0;
}
}
}//main program loop
}//main program end
/*************INTERRUPT SERVICE ROUTINE***************/
void interrupt isr(void)
{
/*************BUTTON PRESS INTERRUPT******************/
if(INTF==1)                //IF INTF FLAG SET
{
for(dbnce=0; dbnce<20; dbnce++)     //DEBOUNCE SWITCH
{
__delay_ms(5);
}
TMR0=0;                //CLEAR TIMER 0
T0IE=1;                //ENABLE TMR0 INTERRUPTS
fpnum++;                //INCREMENT LOOP NUMBER
tcnt=0;                //CLEAR THE TIMER COUNTER VARIABLE
INTF=0;                //CLEAR THE INTERRUPT FLAG
PORTA=0;                //CLEAR PORT A
PORTB=0;                //CLEAR PORT B
}
/************TIMER 0 OVERFLOW INTERRUPT***************/
if(T0IF==1)                //IF TIMER 0 OVERFLOWED
{
if(tcnt<92)            //TIMER COUNTER HAS NOT REACHED 6 SECONDS
{
tcnt++;                //INCREMENT THE TIMER COUNTER VARIABLE
T0IF=0;                //CLEAR THE TIMER 0 OVERFLOW INTERRUPT FLAG
}
if(tcnt>=92)            //TIMER COUNTER HAS REACHED 6 SECONDS
{
T0IF=0;                //CLEAR TIMER 0 INTERRUPT FLAG
T0IE=0;                //DISABLE TIMER 0 INTERRUPTS
ewrit=1;                //SET THE EEPROM WRITE NOTIFIER
}
}
}

#### Attachments

• 12.4 KB Views: 50
Last edited:

#### thatoneguy

Joined Feb 19, 2009
6,359
#1: NEVER Put a delay loop in an interrupt. (unless you know exactly what you are doing)

#2: For interrupt on change, when interrupt is entered, one way to debounce is test the state of the button in a for loop 10 times, if there is a majority of 1's, it bounced, but now time has passed, set a flag variable to indicate input received and exit interrupt.

in main loop, Keep looking at flag for key pressed (which is set in interrupt), if one is positive, then do the EEEPROM write, by the time you are done writing to EEPROM, the bouncing should be over. The worse switches will bounce for maybe 10mS (most are done in 1 or 2mS), so the only times debouncing is critical is when entering numbers or similar, so as not to double up on numbers or actions. In many cases, debouncing isn't needed.

http://www.best-microcontroller-projects.com/switch-debounce.html
http://www.rentron.com/Myke6.htm
http://www.dattalo.com/technical/software/pic/debounce.html

The rest of your code is a bit hard to read. Try aliasing some ports using #define

Such as
#define portb.4 LED1
#define portb.5 button1
etc..

Makes code FAR easier to read and understand what you are trying to do. A global search and replace with the editor can do this for you pretty quickly.

#### MMcLaren

Joined Feb 14, 2010
855
Ryan (ke5nnt),

What's the purpose of your 6 second timer, please? I'm not trying to criticize. I'm just trying to figure out your logic...

Also, are RB5 and RB4 connected to the "common anode" of a common-anode 7-segment display?

Last edited:

#### ke5nnt

Joined Mar 1, 2009
384
Okay, my apologies for leaving this thread hanging, been busy on account of it being Christmas and all, and I've been working on this code.

Basically, the whole point of this little project was simply to test various debounce routines just to see how well each one worked. The 7-segment display was connected to the pins of the MCU (common cathode was connected to ground).

The code contains 10 separate loops that display the numbers 0 through 9 on the display. Each time the button is pressed, the interrupt increments the variable "fpnum" by 1. If I press the button, and the display increments by more than 1, I can tell that my debounce routine isn't working. I found the problem with my code today, and everything works quite well.

The 6 second timer was mostly a learning experiment on my part. I've never used timer 0 before, and since this "project" doesn't serve any real purpose other than testing debounce software, I figured it was a good time to check out timer 0 as well.

Always appreciate the help and feedback guys, thank you.

#### MrChips

Joined Oct 2, 2009
25,932
Please use a title that explains a bit more of your problem.

#### AlexR

Joined Jan 16, 2008
732
As it stands your code is unreadable and I have no idea of what you are doing or why you are doing it.

Try breaking up your code into separate logical functions with clear comments telling us what each function is supposed to do and why.
Also unless you have a VERY GOOD reason to do otherwise keep the interrupt function free from delay loops. Interrupts should be serviced and exited as quickly as possible. Any delays should be done in the main loop.

If you are testing debounce routines I would have thought that a program to measure how long the switch contacts bounce would be much more useful than one that simply tells you that your debounce has failed (if that is what it does). Once you know how long you must wait for the bouncing to stop then writing the actual debounce routine is a pretty trivial exercise.