Full Version : Cheap Decode of 4 Switches with 2 lines (AVR)
avr >>PROJECTS (AVR) >>Cheap Decode of 4 Switches with 2 lines (AVR)


Admin5- 04-27-2006
Cappel's Decoding 4 buttons with 2 I/O pins on AVR Micro controllers


Just the solution for AVR applications in which I/O is tight, such as the ATtiny12. This should work well on other kids of controllers that have independently controlled I/O direction registers, such as PIC and 6805 controllers.

This is a solution was devised for those I/O limited 8 pin controllers like the AT90S2323 (though I tested it on an AT90S1200A).

In principle, the circuit senses three states of the pushbuttons: Open (no button down), Pulled Up, and Pulled Down. The process is this: Pin A (PORTB bit 4)driven high through a resistor and the other end of the resistor is looked, at Pin B (PORTB bit 4) to see if it is being pulled high, low, or not being driven up a button at all. Then Pin B is driven and the other end of the resistor (Pin A) is looked at.

In the circuit, a 39k resistor is placed across the two I/O pins to allow each pin to drive the other through the resistor. The two pair of buttons connected identically, except that one pair of buttons is connected to pin A (PORTB bit 3) and the other pair of buttons is connected Pin B (PORTB bit 4). In each pair, one button is connected to VCC through a 10k resistor and the other button connects to ground through a 10k resistor. The remaining contacts on the two buttons in each pair are connected together and connected to their respective I/O pin. Its a digital circuit so the actual resistor values aren't important as long as the logic thresholds for the input ports are exceeded. The four button implementation only requires three resistors total.

This concept can be extended by using more pairs of I/O pins and still has an advantage over simpler matrices, but the disadvantage disappears when the number of I/O lines reaches 8.


(Added June, 2003):
One other note: A circuit was published on the web around the end of 2002 (about a year after this circuit was first published) that uses one less resistor but relies on the value of the weak internal pullup on the processor's I/O pin. I rejected this concept early on as it was not robust enough in light of the poorly defined characteristics of the weak pullup. The design presented here will work by design.

Link: http://cappels.org/dproj/4w2bp/4w2b.htm

Admin5- 04-27-2006


CODE

;Four Bottons on Two I/O Pin Driver

;Traget: AVR microcontroller  Questions? Dick Cappels, avr@cappels.org
;Date: 05 March, 2002

; THE KEY ROUTINE ALLOWS THE READING OF
;FOUR BUTTONS USING TWO I/O PINS. It uses one high  register
;as a scratch register and one low register, to return the scan results.
;The only hardware required are the two I/O pins to test and determine \
;the button status, though a timer could be used a number of ways to
;improve CPU utilization, when taking the delay for settling of the I/O lines
;into account. Note that this concept can be extend but in a quick analyis,
;the benefit in I/O efficency over a regular matrix disappears when 8 I/O pins
;or more are used.

; The routine, getbuttonstatus, returns a "1" in bits in
;buttonstatus register to indicate which of up to four buttons are pressed.
;Bits in buttonstatus register are assigned as follows:
; butonBdown  = 0  
; buttonBup   = 1
; buttonAdown = 2
; buttonAup   = 3
;
; In prinicple, the circuit senses three states of the pushbuttons:
;Open (no button down), Pulled Up, and Pulled Down.
;The process is this:
;Pin A (PORTB bit 4)driven high through a resitor and the other end of the resistor
;is looked, at Pin B (PORTB bit 4) to see if it is being pulled high, low, or not
;being driven up a button at all. Then Pin B is driven and the other end
;of the resistor (Pin A) is looked at.
;
; In the circuit, a 40k resistor is placed across the two I/O pins
;to allow each pin to drive the other through the resistor.
;The two pair of buttons connected identically, except that
;one pair of buttons is connected to pin A (PORTB bit 3) and the other
;pair of buttons is connected Pin B (PORTB bit 4). In each pair, one
;button is connected to VCC through a 10k resistor and the other button
;connects to ground through a 10k resistor. The remaining contacts on
;the two buttons in each pair are connected together and connected to
;their respective I/O pin. Its a digital circuit so the actual resitor
;values aren't important as long as the logic thresholdsfor the input ports
;are exceeded. The four button implimentation only requires three resistors
;total.
;
;
; The rotuine getbuttonstatus returns the status of the buttons. It requires
;ShortDelayAndLoadPinB to provide some delay to let the I/O lines settle before
;it reads the state of the input pins. In cases in which there is very light
;capacitive loading on the I/O pins associated with the buttons the delay can be reduce or
;even completely eliminated (though the statement in temp,pinb would need to replace
;the call to ShortDelayAndLoadPinB). The amount of capacitive loading that can be
;tolerated is dependent upon the value of the resitor across the I/O pins (39k in
;the example) and the microcontroller clock rate.
;
;The routine will not respond properly if both the pull-high and pull-low buttons
;in a pair are pushed at the same time, so these two are mutually exclusive.

.include "1200def.inc"

.def buttonstatus = r21
.def temp    = r16


;bits in Port B used test and sense button status
.equ Apin = 3
.equ Bpin = 4

.org $0000

ldi temp,$FF ;set port D as all output ONL USED TO TEST THE ROUTINE
out ddrd,temp

forever:  ;this loop is only used for testing
rcall getbuttonstatus;get the status of the buttons
out   portd,buttonstatus;output the button status to PORTD
rjmp forever ;do this until the power is switched off or reset


getbuttonstatus:;Read and four buttons, return flags showing which
 ;buttons are down.

 
 
clr buttonstatus
 


;set A high, test for B low
cbi DDRB,Bpin ;make B an input
sbi PORTB,Apin ;make pull for B buttons high
sbi DDRB,Apin ;make A output pin
rcall ShortDelayAndLoadPinB;delay to settle I/O then load PORTB into temp
andi temp,$10 ;mask all but the relevant bit
brne notblow  ;test for b being low
ldi temp,$01 ;if be is low, then set but stat bit high
or buttonstatus,temp
notblow:


;set A low, test for B high (enter with DDRB Apin already set high)
cbi portB,Apin ;make pull for B buttons low
rcall ShortDelayAndLoadPinB;delay to settle I/O then load PORTB into temp
andi temp,$10 ;mask all but the relevant bit
breq notbhigh
ldi temp,$02
or buttonstatus,temp
notbhigh:

cbi DDRB,Apin ;make pin A input, pin B output
sbi DDRB,Bpin


;set B high, test for A low
sbi PORTB,Bpin ;make pull for A buttons high
rcall ShortDelayAndLoadPinB;delay to settle I/O then load PORTB into temp
andi temp,$08 ;mask all but the relevant bit
brne notalow
ldi temp,$04
or buttonstatus,temp
notalow:

;set B low, test for A high

cbi portB,Bpin ;make pull for B buttons low
rcall ShortDelayAndLoadPinB;delay to settle I/O then load PORTB into temp
andi temp,$08 ;mask all but the relevant bit
breq notahigh
ldi temp,$08
or buttonstatus,temp
notahigh:
 
ret



ShortDelayAndLoadPinB:
ldi temp,$00
shordelayroutine:
dec temp
brne shordelayroutine
in temp,pinb

ret



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.