;Dick Cappels' project pages projects@cappels.org - you shoudl be able to copy and paste this text into an assembler file.

;©2002 Richard Cappels All Rights Reserved

;HOME

;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
	
;http://projects.cappels.org/		

;HOME