If I am not careful my new event handler will be called repeatedly if I get noise on the button input. We have already seen how this can be a problem. Previously we have solved the debounce problem by repeatedly reading the input until we get a number of consistent readings. Because the PICmicro program may run very fast I have to wait for quite a large number of loops before I can pronouce a signal "debounced".
If I want to get a "debounced" version of PORTB
you may think I have to do this again. However, I can use the fact that we are now reading the port on interrupts to provide a debounced version really easily. This is how it works:
I sample the input ports when the timer interrupt goes ping. I have arranged this to happen every 200th of a second. This is a reasonable length of time over which I can debounce a signal. If I get the same reading from a port on two successive interrupts I can regard the signal as debounced and can update my "master" copy.
If you look at the code on the right you will see that I now have three variables which deal with PORTB
. The "master" copy, PORTB
, is the one which will be read by the foreground process. The variable oldPORTB
is a copy of the previous reading from the actual port. Each time I get an interrupt I read a new value into newPORTB
and then compare it with oldPORTB
. If the two are different I assume that we are bouncing and ignore the reading. The the new and old values are the same I copy value into the "master" variable.
This is another example of "animal cunning" in that I am gettings omething for nothing. By linking up the port debouncing with the display update I can get clean, debounced, port readings in my foreground program any time I want them. The only downside is that it takes 2 timer cycles before a value change is recognized.
In the case of the stopwatch, where I am displaying timings to a resolution of 10th of a second and the timer is ticking at 200 Hz. this is not a problem. However, if I started displaying counts to 100th of a second I may have to revise my timings to make sure that the buttons is read often enough to give me good resolution. On the other hand, if you can find me a human with reactions fast enough to press a button to 100th of a second resolution I will be very surprised!
If you run Exercise 4.8 you will find that it works well, providing a nicely debounced version of PORTA
for our edge trigger to work on. We now have a stop watch with a push-on push-off action.
/* new version of PORTB */
unsigned char newPORTB ;
/* old version of PORTB */
unsigned char oldPORTB ;
/* master copy of PORTB */
unsigned char PORTBinputs ;
/* each time refresh is called */
/* it sets the display for a */
/* LED and moves on to the */
/* next */
void refresh ( void ) {
/* turn off all the LEDs */
PORTA = 0 ;
/* now read port b */
/* turn off the outputs first */
PORTB = 0 ;
/* set all of PORTB for input */
TRISB = 0xff ;
/* copy the input pins */
newPORTB = PORTB ;
/* set all of PORTB for output*/
TRISB = 0x00 ;
/* now do the display update */
/* set segments for the led */
PORTB = segments [led_counter] ;
/* turn the led on */
PORTA = enable [led_counter ] ;
/* move on to the next led */
led_counter = led_counter + 1 ;
/* see if we fell off the end */
if ( led_counter == DISPLAY_SIZE )
{
led_counter = 0 ;
}
/* now do the debounce */
if ( newPORTB == oldPORTB )
{
PORTBinputs = newPORTB ;
}
/* store the old value for */
/* next time */
oldPORTB = newPORTB ;
}