Debounce Code – one post to rule them all. Last month we asked you to send in your debounce code. ![]() You didn’t disappoint and it’s time to share the code received. There were some guideline for sending in code so if you don’t see yours here, it probably didn’t follow the rules, sorry. We also tried to weed out code that using delay loops for debounce. These tend to be a poor way to handle inputs because they monopolize the processor. We wanted to add upvote/downvote buttons to each set of code to give some idea of a group consensus on code quality but there’s no good system available for multiple up/down vote widgets on one wordpress page. This results in a huge code dump for any one person to go through. If you’ve got any ideas on how to better organize this let us know: debounce@hackaday. We make no guarantees that this code is safe to use, or that it even works. Test it carefully before using for important tasks. Join us after the break for a whirlwind of code examples. Ned’s Debounce Code. Ned sent in a package of debounce code that monitors multiple buttons, debounces them, and detects button hold and release. Main. c: /*****************************************************************************************. Project: Button Code. Version: V1. 0. Client: Pro. Tech. NZ. * Date Created: 2. Date Modified: 2. Author: Neil van Geffen. Company: Pro. Tech NZ. Micro: ATMega. 12. Speed: 8. MHz. * Clock Source: Internal. Defines *******************************************************/. Neds. Standard. Header. C Files\buttons. h". BTN_UP 0x. 01. #define BTN_DOWN 0x. BTN_ENTER 0x. 04. BTN_CLEAR 0x. 08. Structs and Enums *********************************************/. Everything you need to know about building hardware and software for debouncing, part 2.Software Debounce: When using a hardware switch you may want to debounce the input one way or another. Either in hardware or in software so that you don't multiple. Debounce Each time the input pin goes from LOW to HIGH (e.g. because of a push-button press), the output pin is toggled from LOW to HIGH or HIGH to LOW. (KudoZ) English to Portuguese translation of debounce time: tempo de debounce [sistemas de segurança - Computers: Software (Tech/Engineering)]. Debounce Code – one post to rule. This is quick implementation of software debounce with as. DEBOUNCE_TIME is in seconds and SAMPLE. Real Time; Software & Firmware. A Guide to Debouncing, or, How to Debounce a Contact in Two Easy Pages. hardware solutions and then software debouncing code. Function Prototypes *******************************************/. Time. Yet(unsigned int time). Time. Diff(unsigned int past, unsigned int future). USART0. Send. Byte(unsigned char byte. To. Send). void USART1. Send. Byte(unsigned char byte. To. Send). void USART0. Send. Array(unsigned char *array, unsigned char no. Of. Bytes). void USART0. Send. String(unsigned char *string). ![]() USART0. Send. String. F(flash unsigned char *string). Global Variables***********************************************/. Byte. unsigned int temp. Word. unsigned char p. A, p. B, p. C, p. D. unsigned char release. Counter. volatile unsigned int isr. Time. unsigned int current. Time. unsigned int time. Buttons. unsigned int clear. Pressed. /************************* Setup Code ****************************************************/. Setup. Ports (void) {. PORTA = 0x. 00. PORTB = 0x. PORTC = 0x. 00. PORTD = 0x. RXD1 (2). PORTE = 0x. RXD0 (0). PORTF = 0x. DDRA = 0x. F0. DDRB = 0x. FF. DDRC = 0x. FF. DDRD = 0x. FF; // TXD1 (3). DDRE = 0x. 02; // TXD0 (1). DDRF = 0x. FF. void Setup. Timers (void) {. TCCR0 = (0 < < FOC0) | (0 < < WGM0. COM0. 1) | (0 < < COM0. WGM0. 1) | (1 < < CS0. ![]() Understanding interrupts and software. You can write non-blocking routines that debounce the switch. The cardinal rule is that you don't spend any more time. Software Debounce. Debouncing a switch in software is very simple. The basic idea is to sample the switch signal at a regular interval and filter out any glitches. ![]() CS0. 1) | (0 < < CS0. CTC 8e. 6/6. 4/1. KHz. TIMSK |= (1 < < OCIE0). Main Code *****************************************************/. Setup. Timers(). SREG. Atomic Time Keeping. Time = isr. Time. C & = 0x. 07; // keep p. C to a max of 7. p. D & = 0x. 07; // keep p. D to a max of 7. PORTB = btn. Status. last. Count; // output number of buttons pressed to LEDs on Port. B. PORTC = (0x. 80 > > p. C); // output a counter to Port. C. PORTD = (0x. 80 > > p. D); // output a counter to Port. D. if (Time. Yet(time. Buttons)) { // Time to run this bit of code yet. Buttons += 5; // Set the next time to 5m. S away (can be any value really). Update. Buttons(current. Time); // Update the buttons. If any button is held. PORTF & = 0x. F; // clear the high nibble off Port. F. PORTF |= (buttons. Port. F high nibble. Pressed = current. Time + 2. 0; // set the clear. Pressed time to 2. LEDs after 2. 0ms). BTN_UP | BTN_DOWN: " if you wanted to as well). BTN_UP: p. D++; break. BTN_DOWN: p. D- -; break. BTN_ENTER: p. C++; break. BTN_CLEAR: p. C- -; break. B++. buttons. held = 0; // Clear the buttons held flags. PORTF & = 0x. F0; // clear the low nibble. PORTF |= buttons. Pressed = current. Time + 2. 00; // set the clear. Pressed time to 2. LEDs after 2. 00ms. BTN_UP: p. D++; break. BTN_DOWN: p. D- -; break. BTN_ENTER: p. C++; break. BTN_CLEAR: p. C- -; break. B++. buttons. pressed = 0; // clear the buttons pressed flags. Counter++; // increment the release counter. PORTF = 0x. 00; // clear Port. F LEDs. PORTA & = 0x. F; // clear the Port. A high nibble. PORTA |= (release. Counter < < 4); // and set what buttons were released to tht Port. A LEDs. switch (buttons. BTN_UP: p. D = 0; break. BTN_DOWN: p. D = 7; break. BTN_ENTER: p. C = 0; break. BTN_CLEAR: p. C = 7; break. B++. buttons. released = 0; // clear the button released flags. Time. Yet(clear. Pressed)) { // if we should clear the LEDs. Pressed = current. Time; // stop the time from wrapping- over. PORTF = 0x. 00; // clear the LEDs. Functions *****************************************************/. Time. Yet(unsigned int time) {. Time) > 0x. F0. Interrupts ****************************************************/. TIM0_COMP] void Timer. Zero. Compare (void) {. Time++; // Keep Time. Buttons. h: /************************************* START OF LIBRARY COMMENTS *******************************. Library Name: Neds Button Code. Version: V1. 0. Created: 2. 2/0. Last Mod: 2. 3/0. CV Version: 2. 0. Author: Neil van Geffen. Company: Pro. Tech. NZ. * Purpose: Read 4 buttons and return button presses, helds and releases. KNOWN BUGS **********************************************. NOTES ***************************************************. The code will decode the button presses into presses, holds and releases. A press is a press AND release before a hold is registered. A hold is a press held long enough to register as a hold. A hold will automatically repeat itself at an increasing rate. BUTTONS (PINA & 0x. F) // Make the buttons the lower nibble active high (use ~ to get active low buttons to appear as active high). REPEAT_MAX 2. 50 // The start value of repeat debouncing when first pressing a button. REPEAT_MIN 2. 5 // The lowest value of repeat debouncing when first holding a button. SPEED_SHIFT 3 // The repeat value decreases by the current repeat value > > by this value (aka 4 means it decreases by 1/1. DEBOUNCE_PRESS 2. The debounce for a single press. DEBOUNCE_HOLD 6. 00 // The debounce for a button hold. DEBOUNCE_HOLD. unsigned int released: 4; // holds which buttons have been released after a button was held. Update. Buttons. * Read 4 buttons (defined as BUTTONS above). Best if called on a regulat basis like every 1. S. * Calling more often will give better resolution on button presses. Time, the current time to compare the last press too to calculate debounce and press held length. Update. Buttons(unsigned int current. Time). #include "buttons. Buttons. c: /************************************* START OF LIBRARY COMMENTS *******************************. Library Name: Neds Button Code. Version: V1. 0. Created: 2. 2/0. Last Mod: 2. 3/0. CV Version: 2. 0. Author: Neil van Geffen. Company: Pro. Tech. NZ. * Purpose: Read 4 buttons and return button presses, helds and releases. KNOWN BUGS **********************************************. NOTES ***************************************************. BUTTON_COUNT ((BUTTONS & & (BUTTONS & (1 < < 0))) + (BUTTONS & & (BUTTONS & (1 < < 1))) + (BUTTONS & & (BUTTONS & (1 < < 2))) + (BUTTONS & & (BUTTONS & (1 < < 3)))). By compiling Neds button code, you acknowledge he is the man! Flag: 1; // used by neds code, never change. Flag: 1; // used by neds code, never change. Status: 4; // used by neds code, never change. The last valid combination of buttons pressed. Count: 4; // used by neds code, never change. The number of buttons held at one time. The time the button press was changed. The time between button held repeats. Time. Diff(unsigned int past, unsigned int future) {. F0. 00) return 0. Update. Buttons(unsigned int current. Time) {. if (Time. Diff(btn. Status. Time) > = DEBOUNCE_HOLD) { // If a button has been held. Status. decrease. Flag) { // if the button count was lowered earlier but they have remained the same for the length of a hold time. Status. decrease. Flag = FALSE; // clear the flag that states it was lowered. Status. last. Status = BUTTONS; // and set the button status to the currently pressed buttons. Status. last. Status; // Set what buttons were held. Status. time += btn. Status. repeat; // and set the time to repeat the next press. Status. repeat = MAX(REPEAT_MIN, btn. Status. repeat - MAX(1,(btn. Status. repeat > > SPEED_SHIFT))); // and lower the repeat value to increase the button held repeat rate. Status. held. Flag = TRUE; // and set the flag that states a button was held. BUTTONS) {. if (btn. Status. held. Flag) { // If the buttons were previously held. Status. held. Flag = FALSE; // Clear the flag so it doesnt set buttons pressed continously. Status. last. Status; // Set what buttons were pressed previously. Time. Diff(btn. Status. Time) > = DEBOUNCE_PRESS) { // but if the buttons werent held, but pressed for long enough to pass as a debounce. Status. last. Status; // Set what buttons were pressed. Status. last. Count = 0; // Clear the last count. Status. last. Status = 0; // Clear the last Status. Status. time = current. Time; // clear the last press time. BUTTON_COUNT > btn. Status. last. Count) { // if the number of buttons pressed has changed. Status. last. Count = BUTTON_COUNT; // save it for next time. Status. last. Status = BUTTONS; // and save what buttons were pressed. Status. decrease. Debouncing Contacts Part 2. A Guide to Debouncing - Part 2, or, How to Debounce a Contact in Two Easy Pages. This report is divided into two parts: Part 1 describes the problem of debouncing and gives emperical data. Part 2 (which you're reading) shows, first, hardware solutions and then software debouncing code. Hardware Debouncers. Figure 1 shows the classic debounce circuit. Two cross- coupled NAND gates form a very simple Set- Reset (SR) latch. The design requires a double- throw switch. Two pull- up resistors generate a logic one for the gates; the switch pulls one of the inputs to ground. The SR latch is a rather funky beast, as confusing to non- EEs as recursion is to, well, just about everyone. With the switch in the position shown the upper gate's output will be a one, regardless of the value of the other input. That and the one created by the bottom pull- up resistor drives the lower NAND to a zero . If the switch moves between contacts, and is for a while suspended in the nether region between terminals, the latch maintains its state because of the looped back zero from the bottom gate. The switch moves a rather long way between contacts. It may bounce around a bit, but will never bang all the way back to the other contact. Thus, the latch's output is guaranteed bounce- free. The circuit suggests an alternative approach, a software version of the same idea. Why not skip the NAND pair and run the two contracts, with pull- ups, directly to input pins on the CPU? Sure, the computer will see plenty of bounciness, but write a trivial bit of code that detects any assertion of either contact. ON. if(switch_lo())state=OFF; switch_hi and switch_lo each reads one of the two throws. Other functions in the program examine variable state to determine the switch's position. This saves two gates but costs one extra input pin on the processor. And, it requires a double- throw switch. But it's the simplest - and most reliable - debounce code possible. The MC1. 40. 43/1. SR flip flops, so might be an attractive solution for debouncing multiple switches. An RC Debouncer. The SR circuit is the most effective of all debouncing approaches. Double- throw switches are bulkier and more expensive than the simpler single- throw versions. An awful lot of us use switches that are plated onto the circuit board, and it's impossible to make DP versions of these. So EEs prefer alternative designs that work with cheap single- throw switches. Though complex circuits using counters and smart logic satisfy our longing for pure digital solutions to all problems, from signal processing to divorce, it's easier and cheaper to exploit the peculiar nature of a resistor- capacitor (RC) network. Charge or discharge a capacitor through a resistor and you'll find the voltage across the cap rises slowly; it doesn't snap to a new value like a sweet little logic circuit. Increase the value of either component and the time lag ("time constant" in EE lingo) increases. Figure 2 shows a typical RC debouncer. A simple circuit, surely, yet one that hides a surprising amount of complexity. Suppose our fearless flipper opens the switch. The voltage across the cap is zero, but it starts to climb at a rate determined by the values of R1, R2 and C. Bouncing contacts pull the voltage down and slow the cap's charge accumulation. If we're very clever in selecting the values of the components the voltage stays below a gate's logic one level till all of the whacking and thudding ceases. If the time constant is too long, of course, the system won't be responsive to fast switch actuations). The gate's output is thus a pristine bounce- free logic level. Now suppose the switch has been open for a while. The cap is fully charged. Snap! The user closes the switch, which discharges the cap through R2. Slowly, again, the voltage drools down and the gate continues to see a logic one at its input for a time. Perhaps the contacts open and close a bit during the bouncing. While open, even if only for short periods, the two resistors start to recharge the cap, reinforcing the logic one to the gate. Again, the clever designer selects component values that guarantee the gate sees a one until the clacking contacts settle. Squalid taverns are filled with grizzled veterans of the bounce wars recounting their circuits and tales of battles in the analog trenches. Most will puzzle over R2, and that's not entirely due to the effects of the cheap booze. The classic RC debouncer doesn't use this resistor, yet it's critically important to getting a thwack- free output from the gate. R2 serves no useful purpose when the switch opens. R1 and C effectively remove those bounces. But strange things can happen when suddenly discharging a capacitor. The early bouncing might be short, lasting microseconds or less. Though a dead short should instantly discharge the cap, there are no pristine conditions in the analog world. The switch has some resistance, as do the wires and PCB tracks that interconnect everything. Every wire is actually a complex circuit at high speeds. You wouldn't think a dull- headed customer flipping the switch a few times a second would be generating high- speed signals, but sub- microsecond bounces, which may have very sharp rise times, have frequency components in the tens of MHz or more. Inductance and stray capacitance raises the impedance (AC resistance) of the closed switch. The cap won't instantly discharge. Worse, depending on the physical arrangement of the components, the input to the gate might go to a logic zero while the voltage across the cap is still one- ish. When the contacts bounce open the gate now sees a one. The output is a train of ones and zeroes - bounces. R2 insures the cap discharges slowly, giving a clean logic level regardless of the storm of bounces. The resistor also limits current flowing through the switch's contacts, so they aren't burned up by a momentary major surge of electrons from the capacitor. Another trick lurks in the design. The inverter cannot be a standard logic gate. TTL, for instance, defines a zero as an input between 0. A one starts at 2. In between is a DMZ which we're required to avoid. Feed 1. 2 volts to such a gate and the output is unpredictable. But this is exactly what will happen as the cap charges and discharges. Instead use a device with "Schmitt Trigger" inputs. These devices have hysteresis; the inputs can dither yet the output remains in a stable, known state. Never run the cap directly to the input on a microprocessor, or to pretty much any I/O device. Few of these have any input hysteresis. Doing The Math. The equation for discharging a cap is: The trick is to select values that insure the cap's voltage stays above Vth, the threshold at which the gate switches, till the switch stops bouncing. It's surprising how many of those derelicts hanging out at the waterfront bars pick an almost random time constant. The boys `n me, we jest figger sumpin like 5 msec". Shortchanging a real analysis starts even a clean- cut engineer down the slippery slope to the wastrel vagabond's life. Most of the switches I examined had bounce times well under 1. Use 2. 0 to be conservative. Rearranging the time constant formula to solve for R (the cost and size of caps vary widely so it's best to select a value for C and then compute R) yields: Though it's an ancient part, the 7. Schmitt Trigger with great input hysteresis. Some AHCT versions have worst case Vthfor a signal going low of 1. Let's try 0. 1 µF for the capacitor since those are small and cheap, and solve for the condition where the switch just closes. The cap discharges through R2. If the power supply is 5 volts (so Vinitialis 5), then R2 is 1. K. Of course, you can't actually buy that kind of resistor, so use 1. K. But. the analysis ignores the gate's input leakage current. A CMOS device like the 7. AHCT1. 4 dribbles about a microamp from the inputs. That 1. 80. K resistor will bias the input up to . Change C to 1 µF and R2 is now 1. K. R1 + R2 controls the cap's charge time, and so sets the debounce period for the condition where the switch opens. The equation for charging is: Vfinal is the final charged value - the 5 volt power supply. Vth is now the worst- case transition point for a high- going signal, which for our 7. AHCT1. 4 a peachy 0. R1 + R2 works out to 1. K. Figure on 8. 2K (a standard part) for R1. The diode is an optional part needed only when the math goes haywire. It's possible, with the wrong sort of gate where the hysteresis voltages assume other values, for the formulas to pop out a value for R1 + R2 which is less than that of R2. In this case the diode forms a short cut that removes R2 from the charging circuit. All of the charge flows through R1. The previous equation still applies, except we have to account for drop across the diode. Change Vfinal to 4. R1 pops out. Be wary of the components' tolerances. Standard resistors are usually ±5%. Capacitors vary wildly - +8. Even small ceramics might vary ±3. Other Thoughts. Don't neglect to account for the closed resistance of oddball switches. Some conductive elastomer devices exceed 2. Two of the elastomer switches I examined didn't bounce at all; their output smoothly ramped from zero to +5 volts. The SR and RC debounce circuits are neither necessary nor effective. Better: run the switch directly into a Schmitt Trigger's input. Never connect an undebounced switch to the clock of a flip- flop. The random bounce hash is sure to confuse the device. A 7. 4HCT7. 4 has a max rise and fall time spec of 6 nsec - easily exceeded by some of the data I acquired from the 1. The 7. 4HC1. 09 requires a minimum clock width of 1. I found pulses shorter than this in my experiments. Some of these parts, like from Philips, have a Schmitt Trigger clock input - it's a much safer part to use when connected to real- world events. Similarly, don't tie undebounced switches, even if Schmitt Triggered, to interrupt inputs on the CPU. Usually the interrupt pin goes to the clock input of an internal flip flop.
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. Archives
March 2019
Categories |