![]() | ![]() | ![]() |
| | |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
| | LinkBack | Thread Tools | Display Modes |
| | (permalink) |
| I was just wondering how everybody interfaces push-buttons to PICs? I'm just trying to choose between a normal digital I/O interface, an interrupt (INTn) pin, or an interrupt-on-change pin (KBIn). I'm using a PIC18F4520. I was thinking of using the KBI pins purely because they're useful for scroll-type buttons which may be pressed for long periods of time since the RBIF bit continues to stay set as long as a key is pressed. Also theres the issue of debouncing which I am yet to address. But I'm open to suggestions so this is why I'm here!
__________________ www.myspace.com/crimsonroadmap | |
| |
| | (permalink) |
| Interupt on change can work, but on the first interupt you have to disable further interupts for a debounce period, which means you'll need to use a timer. Or you could just use a timer to run a poleing routine to pole an entire I/O port and a few variables to only change the state of the button variable if the button state has been stable for 2 or more readings (the more readings you integrate the less chance you'll have bounce problems)
__________________ "Because I be what I be. I would tell you what you want to know if I could, mum, but I be a cat, and no cat anywhere ever gave anyone a straight answer, har har." | |
| |
| | (permalink) |
| Debouncing is the least of your problems because it is the easiest to solve. I always use software debouncing. Once a change is detected, call a debounce delay and when it returns check if the state is the same prior to calling the debouce delay. If same state, then button is valid, else ignore button. The debounce delay can range from 1 to 50 milliseconds and is button dependent, for instance, tact switches give damn the a super clean 1 microsecond raise and no noise but other switches can look like ekg signals. In all my apps, I can afford to not use buttons in interrupts because I call my magical CHECK_BUTTON routine inside all major routines. CHECK_BUTTON returns within 4 to 6 clock cycles if no button is press, so you see its not a big overhead. I use interrupts for more important things instead like keeping track of operation time and external hardware interface monitoring, basically things not available to users. Last edited by donniedj; 29th March 2007 at 02:29 AM. | |
| |
| | (permalink) |
| I use polling to read buttons. I find a 10mS interrupt is good enough to do prefect debounce. If I was reading keys on PORTB, I would do the following to debounce, ; this assumes that keys are active high. Temp = Port Keys = Temp xor PreviousValue ; any bit that is 1 has changed since last time. Keys = Keys and Temp ; get rid of key releases ; any bit that is one is a new key press PreviousValue = Temp In code this would be, Code: movfw PORTB ;read port movwf Temp ;Save it xorwf Previous,W ;Keys that have changed will be 1 andwf Temp,W ;Get rid of keys that were released = 1 to 0 movwf Keys ;Save the value for use elsewhere movfw Temp ;Copy port value to previous movwf Previous ;for next time around. Code: comf PORTB,W ;read port and invert it. movwf Temp ;Save it xorwf Previous,W ;Keys that have changed will be 1 andwf Temp,W ;Get rid of keys that were released = 1 to 0 movwf Keys ;Save the value for use elsewhere movfw Temp ;Copy port value to previous movwf Previous ;for next time around. Edit, changed the comment and added the active low code. Last edited by Pommie; 31st March 2007 at 03:19 AM. | |
| |
| | (permalink) |
| Using timer based interrupts to poll and process multiple switches in parallel is a very viable method. I would build on Mike's (Pommie's) example 10-msec interrupt code by using a slightly modified version of Scott Dattalo's debounce vertical counter sample code. This code provides eight independent 30-msec debounce counters which debounce on both the "press" and "release" switch states and it's so small (13 words) that it should be considered even if you only have one or two switches in the project. Code: ;
; <> process up to eight switches in parallel
; <> eight independent 2-bit 30.0-msec "debounce" vertical counters
; <> momentary switch operation (test then clear a SWITCH bit
; in Main)
; <> toggle switch emulation (push to toggle a SWITCH bit from
; off-to-on or from on-to-off) perfect for lighted switches
;
; a switch is "debounced" or "filtered" after it's sampled four
; times at the same level spanning a 30-msec period.
;
; execute this code every 10.0-msec interrupt cycle
;
; 13 instructions/13 words
;
ISR_Debounce
;
; get new press, release, or bounce state "change" bits in W
;
comf PORTB,W ; read active low switches |B0
movwf SWKEYS ; save live switch press data |B0
xorwf SLATCH,W ; get delta 'live' and 'latch' |B0
;
; reset vertical counters for bouncing or inactive switches
;
andwf VCBIT0,f ; |B0
andwf VCBIT1,f ; |B0
;
; get timed-out counter bits in W
;
andwf VCBIT0,W ; |B0
andwf VCBIT1,W ; |B0
;
; update debounced switch state latch (each '1' represents
; a 30.0-msec debounced switch press)
;
xorwf SLATCH,f ; update debounced state latch |B0
;
andwf SWKEYS,W ; get "new" switch press bits |B0
;
; toggle SWITCH pressed flags for processing by MAIN program
;
; MAIN should test SWITCH flags for emulated "toggle" switches
; or test then clear SWITCH flags for "momentary" switches
;
xorwf SWITCH,f ; toggle SWITCH flags for MAIN |B0
;
; increment the 2-bit vertical counters (unconditionally)
;
movf VCBIT0,W ; |B0
xorwf VCBIT1,f ; b1 ^= b0 |B0
comf VCBIT0,f ; b0 = ~b0 |B0
; Last edited by Mike, K8LH; 31st March 2007 at 05:14 AM. | |
| |
| | (permalink) | |
| Quote:
| ||
| |
| | (permalink) | |
| Quote:
I have not encountered the lost key problem as I normally have a bit of code after the above which implements a key delay and key repeat. This causes the value to be copied into another variable. Mike. | ||
| |
| | (permalink) |
| I didn't mean to nit-pick Mike (Pommie). That's a very good example of code to parallel process up to 8 switches. The switch state latch is essential for producing "new" press or release data and ignoring the opposite state change. Here are my versions of the same algorithm but I fully debounce the switches before performing this logic; Code: ;
; detect "new" switch "press" (active high switch data)
;
movf SWDATA,W ; live debounced switch bits
xorwf SLATCH,W ; delta "live" and "latch"
andwf SWDATA,W ; each '1' is a "new" press
xorwf SWITCH,F ; update flags for MAIN
;
movf SWDATA,W ; live debounced switch bits
movwf SLATCH ; update switch state latch
;
; Code: ;
; detect "new" switch "release" (active high switch data)
;
movf SWDATA,W ; live debounced switch bits
xorwf SLATCH,W ; delta "live" and "latch"
andwf SLATCH,W ; each '1' is a "new" release
xorwf SWITCH,F ; update flags for MAIN
;
movf SWDATA,W ; live debounced switch bits
movwf SLATCH ; update switch state latch
; Code: ;
; detect "new" switch "press" (active high switch data)
;
movf SWDATA,W ; live debounced switch bits
xorwf SLATCH,W ; delta "live" and "latch"
xorwf SLATCH,F ; update switch state latch
andwf SWDATA,W ; each '1' is a "new" press
xorwf SWITCH,F ; update flags for MAIN
; Code: ;
; detect "new" switch "press" (active high switch data)
;
ISR_switch
movf SWDATA,W ; live debounced switch data
xorwf SLATCH,W ; delta "live" and "latch"
xorwf SLATCH,F ; update switch state latch
andwf SWKEYS,W ; any "new" switch press?
skpz ; no, skip, else
bsf BEEP,4 ; send 32-msec short 'beep'
xorwf SWITCH,F ; update flags for MAIN
;
; 500-Hz tone using 1-msec interrupts
;
ISR_beep
movf BEEP,W ; beep timer set?
bz ISR_next ; no, branch, else
movf PORTA,W ; toggle piezo spkr on RA0
xorlw b'00000001' ;
movwf PORTA ;
decf BEEP,F ; decrement BEEP msec counter
;
ISR_next Mike, K8LH Last edited by Mike, K8LH; 31st March 2007 at 04:45 PM. | |
| |
| | (permalink) |
| Hi All, just wondering if you could look at something for me and advise on why its not working... I'm using the code that Mike (pommie) posted above. the situation is, I have 8 push button switches, which are interfaced with a 16F873A pic via a 4014 shift register. I have a register called "input_data", which, suprisingly, is where the data from the shift register is stored. I then have one called "output_data" where the state of my switches is outputted onto 8 LED's... basically i want the LED's to light the first time a switch is pressed, and then turn off when they are pressed again... Code: <bit bashing data from 8 switches, through 4014 into "Incoming_data"> movfw incoming_data movwf temp_data xorwf Previous,W andwf Temp_data,W iorwf output_data movfw Temp_data movwf Previous <bit bashing "output_data" to a 4094 to 8 led's> Cheers Sam J | |
| |
| | (permalink) |
| Hi Sam, A couple comments if I may? If you've got "live" switch press data already in incoming_data (each '1' bit should indicate a switch press) you shouldn't have to make another copy of it. For toggle switch emulation where you press a switch to toggle its output latch bit from on-to-off or from off-to-on you want to use an xorwf instruction on the output latch. Something like this; Code: ;
movf incoming_data,W ; get live switch press bits
xorwf Previous,W ; the '1' bits indicate a change
andwf incoming_data,W ; the '1' bits indicate 'new' presses
xorwf output_data,F ; toggle output flag bits
movf incoming_data,W ; get live switch press bits
movwf Previous ; update switch state latch
; Code: ;
comf incoming_data,F ; complement switch press bits <---
movf incoming_data,W ; get live switch press bits
xorwf Previous,W ; the '1' bits indicate a change
xorwf Previous,F ; update switch state latch
andwf incoming_data,W ; the '1' bits indicate 'new' presses
xorwf output_data,F ; toggle output flag bits
; Good luck with your project. Mike, K8LH Last edited by Mike, K8LH; 31st March 2007 at 04:47 AM. | |
| |
| | (permalink) | |
| Quote:
Just for any newbies following this thread, the first 3 lines of the above code do the equivalent of, W=SWDATA xor SLATCH SLATCH = SWDATA This is a clever method and it is not obvious how it works. Anyone interested should read up on the xor instruction and follow the code through with a few examples. I like the beep code and will almost certainly use it in a future project. Whoops, I just noticed that the code posted earlier is incorrectly commented as being for active low switches. I'll edit that earlier post. Mike. | ||
| |
| | (permalink) | |
| Quote:
I may have confused the matter as I incorrectly labeled the above code as being for active low switches. Mike. | ||
| |