Full Version : How to MUX 4x4 KBD & LED Driver (AVR ASM)
avr >>BEGINNER UTILITIES >>How to MUX 4x4 KBD & LED Driver (AVR ASM)


AVR_Admin- 05-17-2006
How to MUX 4x4 KBD & LED Driver (AVR ASM)

CODE

;**** A P P L I C A T I O N   N O T E   A V R ??? ************************
;*
;* Title:  Multiplexing LED drive and 4x4 keypad sampling
;* Version:  1.0
;* Last Updated: 98.07.24
;* Target:  All AVR Devices
;*
;* Support E-mail: avr@atmel.com
;*
;* DESCRIPTION
;* This Application note covers a program to provide a 24 hr Industrial
;* timer or real-time clock using I/O pins for dual functions.
;* With input via a 4 x 4 matrix keypad, output to a multiplexed
;* four digit LED display and two ON/OFF outputs to drive loads via additional
;* interface circuitry.  LED loads are driven in this example but it could drive
;* any load with the addition of suitable components. Tactile feedback is provided
;* on every key press by a piezo sounder which beeps when a key is pressed.
;* Included is a main program that allows clock setting via the keypad
;* and one ON/OFF time setting per 24 hours for each load, functions for the
;* real time clock, key scanning, and adjustment routines. The example runs on
;* the AT90S1200 to demonstrate how limited I/O  can be overcome, but can
;* be any AVR with suitable changes in vectors, EEPROM and stack pointer.
;* The timing assumes a 4.096 MHz crystal is employed (a 4 MHz crystal produces
;* an error of -0.16% if 178 instead of 176 used in the timer load sequence, but this
;* could be adjusted in software at regular intervals). Look up tables are
;* used in EEPROM to decode the display data, with additional characters provided
;* for time and ON/OFF setting displays and a key pad conversion table.  
;* If the EEPROM is needed for your application the tables could be moved
;* to ROM in the larger AVR devices.
;***************************************************************************

;***** Registers used by all programs
;******Global variables used by routines

.def loset =r1;storage for timeset minutes
.def hiset =r2;storage for timeset hours
.def ld1minon=r3;storage for load on and off times
.def ld1hron =r4;set from keypad entry
.def ld1minoff=r5;and tested in the housekeeping function
.def ld1hroff=r6;and stores on or off times for the loads
.def ld2minon=r7
.def ld2hron =r8
.def ld2minoff=r9
.def ld2hroff=r10

.def temp =r16;general scratch space
.def second =r17;storage for RTC second count
.def  minute =r18;storage for RTC minute count
.def hour =r19;storage for RTC hour count
.def mask =r20;flash mask for  digits flashing
.def  blink =r21;colon blink rate counter
.def bounce =r22;keypad debounce counter
.def  flash =r23;flash delay counter
.def lobyte =r24;storage for display function minutes digits
.def hibyte =r25;storage for display function hours digits
.def key =r26;key number from scan

;***'key' values returned by 'keyscan'***************************
;VALUE 0   1 2   3 4   5 6   7  8   9  10  11   12 13  14   15  16
;KEY 1   2   3   F   4   5   6   E    7   8   9   D    A  0  B    C   NONE  
;FUNC 1   2   3 LD1ON 4   5   6 LD1OFF 7   8   9 LD2ON SET 0 CLEAR LD2OFF

.def tock =r27;5 ms pulse
.def flags =r28;flag byte for keypad command keys
 ;  7     6     5    4      3      2     1    0
 ;  5ms  keyok ld2off ld2on ld1off ld1on ld2 ld1
 ; tick      0 = off, 1 = on
.equ ms5 =7;ticks at 5 ms intervals for display time
.equ keyok =6;sets when key is debounced, must be cleared again
.equ ld2off =5;set by load ON/OFF key press and flags
.equ ld2on =4;up the need for action
.equ  ld1off =3;in the housekeeping routine
.equ ld1on =2
.equ ld2 =1;when set tells the housekeeping routine to
.equ ld1 =0;check load on/off times.

;***the T flag in the status register is used as a SET flag for time set
.equ clear =0;RTC modification demand flag


;Port B pins

.equ col1 =0;LED a segment/keypad col 1
.equ col2 =1;LED b segment/keypad col 2
.equ col3 =2;LED c segment/keypad col 3
.equ col4 =3;LED d segment/keypad col 4
.equ row1 =4;LED e segment/keypad row 1
.equ row2 =5;LED f segment/keypad row 2
.equ row3 =6;LED g segment/keypad row 3
.equ row4 =7;LED decimal point/keypad row 4

;Port D pins

.equ A1 =0;common anode drives (active low)
.equ A2 =1;
.equ A3 =2;
.equ A4 =3;
.equ LOAD1 =4;Load 1 output (active low)
.equ LOAD2 =5;Load 2 output (active low)
.equ PZ =6;Piezo sounder output (active low)

.include "1200def.inc"

;***** Registers used by timer overflow interrupt service routine


.def timer =r31;scratch space for timer loading
.def  status  =r0;low register to preserve status register

;*****Look up table for LED display decoding **********************
.eseg    ;EEPROM segment
.org 0

table1: .db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90
;digit  0    1    2    3    4    5    6    7    8    9    

.db 0x86,0x8E,0xA3,0xAB,0XFF,0XFF
;digit  E     f   o    n       BLANK       special characters

;****Look up table for key value conversion into useful numbers****

;key 1  2  3  F  4  5  6  E  7  8  9   D    A  0   B   C
table2: .db 1, 2, 3,15, 4, 5, 6,14, 7, 8, 9,  13, 10, 0, 11, 12
;value 0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15

;****Source code***************************************************
.cseg    ;CODE segment
.org 0
 rjmp reset ;Reset handler
 nop  ;unused ext. interrupt
 rjmp tick ;timer counter overflow (5 ms)
 nop  ;unused analogue interrupt

;*** Reset handler **************************************************
;*** to provide initial port, timer and interrupt setting up

reset:  
 ser temp ;  
 out DDRB,temp ;initialize port B as all Outputs
 out DDRD,temp ;initialize port D as all Outputs
 out PORTB,temp ;key columns all high/LEDs off
 out PORTD,temp ;turn off LEDs and loads off
 ldi temp,0x04 ;timer prescalar /256
 out TCCR0,temp
 ldi timer,176 ;load timer for 5 ms
 out TCNT0,timer ;(256 - n)*256*0.2441 us
 ldi temp,0x02 ;enable timer interrupts
 out TIMSK,temp
 clr flags ;clear control flags
 clr tock ;clear 5 ms tick
 clr bounce ;clear key bounce counter
 clr flash
 clr blink
 sei  ;enable global interrupts

;****Flash EEEE on LEDS as test and power down warning**************
;****repeats until SET key is pressed on keypad
 
 
timesetting: ldi hibyte,0xaa ;show "EEEE" on LED
 ldi lobyte,0xaa ;display and
 ser mask ;set flashing display
notyet:  rcall display ;display until time set
 brtc notyet ;repeat until SET key pressed
 rcall setrtc ;and reset time  
 mov hour,hiset ;and reload hours
 mov minute,loset;and minutes
 clt  ;clear T flag  
   
;*****Main clock house keeping loop*****************************

do:  
 clr mask ;do housekeeping
 cpi blink,100 ;is half second up
 brne nohalf
 clr blink
 com flash ;invert flash
nohalf:  
 cpi second,60 ;is one minute up?
 brne nochange ;no
 clr second ;yes clear seconds and
 inc minute ;add one to minutes
 mov temp,minute
 andi temp,0x0f ;mask high minute
 cpi temp,10 ;is it ten minutes?
 brne nochange ;no
 andi minute,0xf0;clear low minutes
 ldi temp,0x10
 add minute,temp ;increment high minutes
 cpi minute,0x60 ;is it 60 minutes?
 brne nochange ;no
 clr minute ;yes, clear minutes and
 inc hour ;add one to hours
 mov temp,hour
 andi temp,0x0f ;mask high hour
 cpi temp,10 ;is 10 hours up?
 brne nochange ;no
 andi hour,0xf0 ;yes, increment
 ldi temp,0x10
 add hour,temp ;high hours
nochange:
 cpi hour,0x24 ;is it 24 hours?  
 brne sameday ;no,
 clr hour ;yes, clear time variables
 clr minute ;to start new day
 clr second  
sameday:   ;update times
 mov lobyte,minute
 mov hibyte,hour
 rcall display ;show time for 20 ms
 brtc case1 ;if not SET
 rcall setrtc ;and reset time  
 mov hour,hiset ;and reload hours
 mov minute,loset;and minutes
 clt  ;else, clear T flag  
case1:  sbrc flags,ld1 ;is load 1 active?
 rjmp chkload1 ;yes, check load 1
case2:  sbrc flags,ld2 ;is load 2 active
 rjmp chkload2 ;yes, check load 2
case3:  sbrc flags,ld1on;is load 1 on time reset
 rjmp setld1on ;yes reset on time
case4:  sbrc flags,ld1off;is load 1 off time reset
 rjmp setld1off ;yes reset off time
case5:  sbrc flags,ld2on;is load 2 on time reset
 rjmp setld2on ;yes reset on time
case6:  sbrc flags,ld2off;is load 2 on time reset
 rjmp setld2off ;yes reset on time
case7:  rjmp do  ;repeat housekeeping loop

;****case routines to service load times and key presses********
 

chkload1: cp hour,ld1hroff;is load 1 off time reached?
 brne onload1
 cp minute,ld1minoff
 brne onload1
 sbi PORTD,LOAD1 ;yes, turn load 1 off
onload1:  
 cp hour,ld1hron ;is load 1 on time reached?
 brne case2
 cp minute,ld1minon
 brne case2
 cbi PORTD,LOAD1 ;yes,turn load 1 on
 rjmp case2 ;repeat with load on

chkload2: cp hour,ld2hroff;is load 2 off time reached?
 brne onload2
 cp minute,ld2minoff
 brne onload2
 sbi PORTD,LOAD2 ;yes, turn load 2 off
onload2:
 cp hour,ld2hron ;is load 2 on time reached?
 brne case3
 cp minute,ld2minon
 brne case3
 cbi PORTD,LOAD2 ;yes,turn load 2 on
 rjmp case3 ;repeat with load on
setld1on:
 sbr flags,0x01 ;make load 1 active
 rcall setrtc ;pickup new on time
 mov ld1hron,hiset;and store
 mov ld1minon,loset
 cbr flags,0x04 ;clear ld1on flag
 rjmp case4

setld1off:
 
 rcall setrtc ;pickup new off time
 mov ld1hroff,hiset;and store
 mov ld1minoff,loset
 cbr flags,0x08 ;clear ld1off flag
 rjmp case5
setld2on:
 sbr flags,0x02 ;make load 2 active
 rcall setrtc ;pickup new on time
 mov ld2hron,hiset;and store
 mov ld2minon,loset
 cbr flags,0x10 ;clear ld2on flag
 rjmp case6
setld2off:
 
 rcall setrtc ;pickup new on time
 mov ld2hroff,hiset;and store
 mov ld2minoff,loset
 cbr flags,0x20 ;clear ld2off flag
 rjmp case7

 
;****Multiplexing routine to display time and scan keypad every*****
;****second pass,used by all routines taking digits from hibyte
;****and lobyte locations with each digit on for 5 ms

display: ser temp ;clear display
 out PORTB,temp
;****Keypad scanning routine to update key flags*******************

keyscan: cbr flags,0x40 ;clear keyok flag
 ldi key,0x10 ;set no key pressed value
 ser temp ;set keypad port high prior to
 out PORTB,temp ;reinitializing the port
 in temp,PORTD ;turn off LEDs and leave loads
 ori temp,0x0f ;untouched prior to
 out PORTD,temp ;key scan
 ldi temp,0x0f ;set columns output and
 out DDRB,temp ;rows input with pull-ups
 ldi temp,0xf0 ;enabled and all columns
 out PORTB,temp ;low ready for scan
 ldi temp,20 ;short settling time
tagain1: dec temp
 brne tagain1
 sbis PINB,ROW1 ;find row of keypress
 ldi key,0 ;and set ROW pointer
 sbis PINB,ROW2
 ldi key,4
 sbis PINB,ROW3
 ldi key,8
 sbis PINB,ROW4
 ldi key,12
 ldi temp,0xF0 ;change port B I/O to
 out DDRB,temp ;find column press
 ldi temp,0x0F ;enable pull ups and
 out PORTB,temp ;write 0s to rows
 ldi temp,20 ;short settling time
tagain2: dec temp
 brne tagain2 ;allow time for port to settle
 clr temp
 sbis PINB,COL1 ;find column of keypress
 ldi temp,0 ;and set COL pointer
 sbis PINB,COL2
 ldi temp,1
 sbis PINB,COL3
 ldi temp,2
 sbis PINB,COL4
 ldi temp,3
 add key,temp ;merge ROW and COL for pointer
 cpi key,0x10 ;if no key pressed
 breq nokey ;escape routine, else
 ldi temp,0x10
 add key,temp ;change to table 2
 out EEAR,key ;send address to EEPROM (0 - 15)
 sbi EECR,EERE ;strobe EEPROM
 in key,EEDR ;read decoded number for true key
convert: cpi key,10 ;is it SET key ?
 brne notset ;no check next key
 set  ;yes set T flag in status register
notset:  cpi key,11 ;is key CLEAR?
 brne notclear ;no, check next key
 sbi PORTD,LOAD1 ;yes, shut down all loads
 sbi PORTD,LOAD2
 cbr flags,0x03 ;deactivate both loads
notclear: cpi key,15 ;is key LD1ON?
 brne notld1on ;no, check next key
 sbr flags,0x04 ;yes, set LD1ON flag
notld1on: cpi key,14 ;is key LD1OFF?
 brne notld1off ;no, check next key
 sbr flags,0x08 ;yes, set LD1OFF flag
notld1off: cpi key,13 ;is key LD2ON?
 brne notld2on ;no, check next key
 sbr flags,0x10 ;yes, set LD2ON flag
notld2on: cpi key,12 ;is key LD2OFF?
 brne notld2off ;no, check next key
 sbr flags,0x20 ;yes, set LD2OFF flag
notld2off:

;***Tactile feedback note generation routine*****************
;***provides a 4 kHz TONE to the piezo sounder for 5 ms*****

tactile: cbr flags,0x80
 cbi PORTD,PZ ;turn on piezo
 ldi temp,125 ;for a short time
t1again: dec temp
 brne t1again
 sbi PORTD,PZ ;turn on piezo
 ldi temp,125 ;for a short time
t2again: dec temp
 brne t2again
 sbrs flags,ms5 ;repeat for 5ms
 rjmp tactile
notok:  cpi bounce,40
 brlo nokey
 sbr flags,0x40 ;set bounce flag
nokey:  ser temp
 out DDRB,temp ;reinitialize port B as all Outputs
 out PORTB,temp ;and clear LEDs

;***Display routine to multiplex all four LED digits****************

 cbi PORTD,A1 ;turn digit 1 on
 mov temp,lobyte ;find low minute
digit1:
 cbr flags,0x80 ;clear 5 ms tick flag
 andi temp,0x0f ;mask high nibble of digit
 out EEAR,temp ;send address to EEPROM (0 - 15)
 sbi EECR,EERE ;strobe EEPROM
 in temp,EEDR ;read decoded number
 sbrs flash,clear;flash every 1/2 second
 or temp,mask ;flash digit if needed
 out PORTB,temp ;write to LED for 5 ms
led1:  sbrs flags,ms5 ;5 ms finished?
 rjmp led1 ;no, check again
 sbi PORTD,A1 ;turn digit 1 off
 ser temp ;clear display
 out PORTB,temp
 cbi PORTD,A2 ;
 mov temp,lobyte ;find high minute
 swap temp
digit2:
 cbr flags,0x80 ;clear 5 ms tick flag
 andi temp,0x0f ;mask high nibble of digit
 out EEAR,temp ;send address to EEPROM (0 - 15)
 sbi EECR,EERE ;strobe EEPROM
 in temp,EEDR ;read decoded number
 sbrs flash,clear;flash every 1/2 second
 or temp,mask ;flash digit if needed
 out PORTB,temp ;write to LED for 5 ms
led2:  sbrs flags,ms5 ;5 ms finished?
 rjmp led2 ;no, check again
 sbi PORTD,A2 ;
 ser temp ;clear display
 out PORTB,temp
 cbi PORTD,A3 ;
 mov temp,hibyte
digit3:
 cbr flags,0x80 ;clear 5 ms tick flag
 andi temp,0x0f ;mask high nibble of digit
 out EEAR,temp ;send address to EEPROM (0 - 15)
 sbi EECR,EERE ;strobe EEPROM
 in temp,EEDR ;read decoded number
 sbrs second,clear;flash colon
 andi temp,0x7f
 sbrs flash,clear;flash every 1/2 second
 or temp,mask ;flash digit if needed
 out PORTB,temp ;write to LED for 5 ms
led3:  sbrs flags,ms5 ;5 ms finished?
 rjmp led3 ;no, check again
 sbi PORTD,A3
 ser temp ;clear display
 out PORTB,temp
 cbi PORTD,A4 ;
 mov temp,hibyte
 swap temp
 andi temp,0x0f ;is hi hour zero?
 brne digit4
 ldi temp,0xff ;yes,blank hi hour
digit4:
 cbr flags,0x80 ;clear 5 ms tick flag
 andi temp,0x0f ;mask high nibble of digit
 out EEAR,temp ;send address to EEPROM (0 - 15)
 sbi EECR,EERE ;strobe EEPROM
 in temp,EEDR ;read decoded number
 sbrs flash,clear;flash every 1/2 second
 or temp,mask ;flash digit if needed
 out PORTB,temp ;write to LED for 5 ms
led4:  sbrs flags,ms5 ;5 ms finished?
 rjmp led4 ;no, check again
 sbi PORTD,A4
 ser temp ;clear display
 out PORTB,temp
 tst mask ;is flash complete?
 breq outled ;yes, exit
 cpi blink,50 ;is blink time done?
 brlo outled ;no, exit
 clr blink ;yes, clear blink rate counter
 com flash ;and invert flash byte
outled:  ret



 
;****Function to Set RTC/on-off hours and minutes from keypad
;****returns with minutes in 'loset' and hours in'hiset'
 
setrtc:  ser mask ;set flashing display
 ldi hibyte,0xdf ;place 'n' in hi hour
 ser lobyte ;and blank in lo hr & minutes
hihrus:  clr bounce
bounce1: rcall display ;display and check keypad
 sbrs flags,keyok
 rjmp bounce1
 cbr flags,0x40 ;clear keyok flag
 cpi key,0x03 ;is high hour > 2
 brsh hihrus ;yes, read key again
hihrok:    ;no, valid entry
 swap key ;move hihour to hi nibble
 mov hiset,key ;and store in hours
 ldi hibyte,0x0d ;place 'n' in lo hour
 add hibyte,hiset;merge hihour and 'n'
lohrus:  clr bounce
bounce2: rcall display ;display and check keypad
 sbrs flags,keyok;is key stable?
 rjmp bounce2 ;no try again
 cbr flags,0x40 ;yes, clear keyok flag
 mov temp,hibyte ;check that total hours
 andi temp,0xf0 ;are not > 24
 add temp,key
 cpi temp,0x24 ;is hour>24?
 brsh lohrus ;yes, read key again
 add hiset,key ;no, merge hi and lo hours
lohrok:  
 mov hibyte,hiset;display hours as set
 ldi lobyte,0xdf ;place 'n' in hi minutes
himinus: clr bounce
bounce3: rcall display ;display and check keypad
 sbrs flags,keyok
 rjmp bounce3
 cbr flags,0x40 ;clear keyok flag
 cpi key,6 ;is hi minutes >5
 brsh himinus ;no, read key again
lominok:
 swap key ;move himin to hi nibble
 mov loset,key ;and store in minutes
 ldi lobyte,0x0d ;place 'n' in lo minutes
 add lobyte,loset;merge with hi minute
lominus: clr bounce
bounce4: rcall display ;display and check keypad
 sbrs flags,keyok
 rjmp bounce4
 cbr flags,0x40 ;clear keyok flag
 cpi key,10 ;is key >9
 brsh lominus ;no, read key again
 add loset,key ;yes, merge hi and lo minutes
 clr mask ;clear digits flash
 ret  ;and return with time set

;****Timer Overflow Interrupt service routine******************************
;****Updates 5 ms, flash and debounce counter to provide RTC time reference

tick:  
 in status,SREG ;preserve status register
 inc tock ;add one to 5 ms 'tock' counter
 inc blink ;and blink rate counter
 inc bounce ;and bounce rate delay
 sbr flags,0x80 ;set 5 ms flag for display time
 cpi tock,200 ;is one second up?
 breq onesec ;yes, add one to seconds
 nop  ;balance interrupt time
 rjmp nosecond ;no, escape
onesec:  inc second ;add one to seconds
 clr tock ;clear 5 ms counter
nosecond: ldi timer,176 ;reload timer
 out TCNT0,timer
 out SREG,status ;restore status register
 reti  ;return to main





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