On Mon, 2006-02-06 at 23:28 -0500, Josh Koffman wrote: > Well, I'm finally ready to start playing with this code. The boards > are done, The main USB stuff seems to be working ok, and I have the > encoders all up and running. It's not in a case yet, but Spehro will > be helping me with that, and we've both been too busy to connect. So I > guess I have no excuses...I must get on with the debouncing! > > I've been reading over the following routine, and before I implement > it, I just want to be sure of a couple of things. > > 1. At the end of the macro, the changes will be in W and I can save > them out. A 0 bit would mean the corresponding input has changed, > while a 1 bit means it's held steady, correct? This will only happen > when it changes state, right? For example, if I hold down a key for > 100 iterations of the macro, I will get a 0 at the first transition, > then it will all be ones, then a 0 at the end when I release, correct? Josh, There is an error in one of the comments of the debounce routine I wrote. > ;Any bit in W that is clear at this point means that the input > ;has changed and the count has rolled over. Should read: > ;Any bit in W that is set at this point means that the input > ;has changed and the count has rolled over. In other words, at the end of the macro, any set bits in W indicates that a change has occurred. So if you press and hold a key, you will see 4 iterations of the switch bit being zero, then 1 iteration of it being zero, and then N iterations back at 0. When you release the switch you'll see a similar thing. In both cases, the cva field matches the csa field after 4 consecutive samples of the two being different > 2. My inputs have pull ups, so when no buttons are pressed, I should > end up with 0xFF in all the CVA registers. Would a good way to check > if I have a key pressed in that bank (not a transition, one that is > held, depending on the answer to the above question) just be to add > one to the CVA and see if I trip the Z flag? Yes, a good way to see if any switches are pressed is to do something like: incfsz cva,W goto PressedSwitch NoSwitchesPressed: I've written a regression test in gpsim (my simulator) that tests all of the corner cases for the debounce routine. I thought that I had checked this into CVS, but I didn't. At the risk of overloading everyone's mailbox I'll go ahead and include it here (besides, maybe someone will ask how those assertions work). list p=16f873 ; list directive to define processor include ; processor specific variable definitions include ; Grab some useful macros __CONFIG (_CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF) radix dec ;------------------------------------------------------------------------ ; ; debounce.asm - an efficient switch debouncing algorithm. ; ; This program tests a PIC de-bouncing algorithm (see below for a ; description of the algorithm). The test is designed to excercise ; all of the states of the algorithm. gpsim (the GNUPIC simulator) ; style assertions are used to verify that the algorithm works ; properly. ;---------------------------------------------------------------------- ; Global Variables ;---------------------------------------------------------------------- GPR_DATA UDATA cva RES 1 ; Debounced output from debounce routine csa RES 1 ; Unfiltered input to debounce routine count_A RES 1 ; MSB of 2-bit counter. count_B RES 1 ; LSB of 2-bit counter. GLOBAL cva, csa, count_A, count_B GLOBAL start ;---------------------------------------------------------------------- ; ********************* RESET VECTOR LOCATION ******************** ;---------------------------------------------------------------------- RESET_VECTOR CODE 0x000 ; processor reset vector movlw high start ; load upper byte of 'start' label movwf PCLATH ; initialize PCLATH goto start ; go to beginning of program MAIN CODE start: CLRF STATUS ;Point to BANK 0 CLRF count_A CLRF count_B CLRF cva .assert "(count_A == 0) && (count_B==0) && (cva==0)" ;First verify that a 0 input produces a 0 output CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==0)" ;Now set one of the inputs MOVLW 1 MOVWF csa ;Pass through the four debounce states. After the fourth ;state, cva should go from 0 to 1. CALL de_bounce .assert "(count_A == 0) && (count_B==1) && (cva==0) && (W==0)" CALL de_bounce .assert "(count_A == 1) && (count_B==0) && (cva==0) && (W==0)" CALL de_bounce .assert "(count_A == 1) && (count_B==1) && (cva==0) && (W==0)" CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==1) && (W==1)" ;The current value has just changed from a 0 to a 1. Now ;verify that if the input stays at 1 the output doesn't change CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==1) && (W==0)" CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==1) && (W==0)" ;Now check that a 0 input is debounced: CLRF csa CALL de_bounce .assert "(count_A == 0) && (count_B==1) && (cva==1) && (W==0)" CALL de_bounce .assert "(count_A == 1) && (count_B==0) && (cva==1) && (W==0)" CALL de_bounce .assert "(count_A == 1) && (count_B==1) && (cva==1) && (W==0)" CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==0) && (W==1)" ;Now check multiple bit filtering MOVLW 0x0f MOVWF csa MOVLW 0xf0 MOVWF cva CALL de_bounce .assert "(count_A == 0x00) && (count_B==0xff) && (cva==0xf0) && (W==0)" CALL de_bounce .assert "(count_A == 0xff) && (count_B==0x00) && (cva==0xf0) && (W==0)" CALL de_bounce .assert "(count_A == 0xff) && (count_B==0xff) && (cva==0xf0) && (W==0)" CALL de_bounce .assert "(count_A == 0x00) && (count_B==0x00) && (cva==0x0f) && (W==0xff)" ; Now check that glitches are filtered. CLRF cva CLRF csa ; 1-sample glitch BSF csa,0 CALL de_bounce .assert "(count_A == 0) && (count_B==1) && (cva==0) && (W==0)" BCF csa,0 CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==0) && (W==0)" ; 2-sample glitch BSF csa,0 CALL de_bounce .assert "(count_A == 0) && (count_B==1) && (cva==0) && (W==0)" CALL de_bounce .assert "(count_A == 1) && (count_B==0) && (cva==0) && (W==0)" BCF csa,0 CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==0) && (W==0)" ;3-sample glitch BSF csa,0 CALL de_bounce .assert "(count_A == 0) && (count_B==1) && (cva==0) && (W==0)" CALL de_bounce .assert "(count_A == 1) && (count_B==0) && (cva==0) && (W==0)" CALL de_bounce .assert "(count_A == 1) && (count_B==1) && (cva==0) && (W==0)" BCF csa,0 CALL de_bounce .assert "(count_A == 0) && (count_B==0) && (cva==0) && (W==0)" nop .assert "\"*** PASSED debounce test\"" GOTO $ ;************************************************************* ; de_bounce ; ; The purpose of this routine is to debounce, i.e. digitally low pass filter ;inputs. The algorithm handles upto 8 bits at a time. An input is considered ;filtered if it has not changed states in the last 4 samples. ; ; 2-bit cyclic vertical counters count the 4 samples. As long as there is no ;change, the counters are held in the reset state of 00b. When a change is detected ;between the current sample and the filtered or debounced sample, the counters ;are incremented. The counting sequence is 00,01,10,11,00... When the counters ;roll over from 11b to 00b, the debounced state is updated. If the input changes ;back to the filtered state while the counters are counting, then the counters ;are re-initialized to the reset state and the filtered state is unaffected. ;In other words, a glitch or transient input has been filtered. ; ;The algorithm will return in W the state of those inputs that have just ;been filtered. ; ; Here's the C-psuedo code: ; ;static unsigned clock_A,clock_B,debounced_state; ;unsigned debounce(unsigned new_sample) ;{ ; unsigned delta; ; unsigned changes; ; ; delta = new_sample ^ debounced_state; //Find all of the changes ; ; clock_A ^= clock_B; //Increment the counters ; clock_B = ~clock_B; ; ; clock_A &= delta; //Reset the counters if no changes ; clock_B &= delta; //were detected. ; ; changes = ~(~delta | clock_A | clock_B); ; debounced_state ^= changes; ; ; return changes; ;} ; ; The 2-bit counters are arranged "vertically". In other words 8 counters ;are formed with 2 bytes such that the corresponding bits in the bytes are ;paired (e.g. MSBit of each byte is paired to form one counter). ; The counting sequence is 0,1,2,3,0,1,... And the state tables and Karnaugh ;maps are: ; ;State Table: Karnaugh Maps: ;pres next B ; SS SS 0 1 ; AB AB +---+---+ +---+---+ ;-------- A 0| | 1 | | 1 | | ; 00 01 +---+---+ +---+---+ ; 01 10 1| 1 | | | 1 | | ; 10 11 +---+---+ +---+---+ ; 11 00 A+ = A ^ B B+ = ~B ; ; Here's the PIC code that implements the counter: ; MOVF SB,W ;W = B ; XORWF SA,F ;A+ = A ^ B ; COMF SB,F ;B+ = ~B ; ; ; ; 13 instructions ; 14 cycles ; Inputs: ; csa - The current sample ; Outputs ; cva - The current value (filtered version of csa) ; W - Bits that have just been filtered. ; ; RAM used ; count_A, ; count_B - State variables for the 8 2-bit counters ; de_bounce: ;Increment the vertical counter MOVF count_B,W XORWF count_A,F COMF count_B,F ;See if any changes occurred MOVF csa,W XORWF cva,W ;Reset the counter if no change has occurred ANDWF count_B,F ANDWF count_A,F ;If there is a pending change and the count has ;rolled over to 0, then the change has been filtered XORLW 0xff ;Invert the changes IORWF count_A,W ;If count is 0, both A and B IORWF count_B,W ;bits are 0 ;Any bit in W that is set at this point means that the input ;has changed and the count has rolled over. XORLW 0xff XORWF cva,F RETURN END -- http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist