AVR Assembler Source Blog

Ремонт частотных преобразователей AVR Assembler Source Blog: Multiplexing_LED_4x4_keypad_AVR242_appnote

Monday, October 7, 2013

Multiplexing_LED_4x4_keypad_AVR242_appnote

ремонт преобразователя частоты
                              ;**** A P P L I C A T I O N   N O T E   A V R 242 ************************
                              ;* 
                              ;* 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

No comments:

Post a Comment