;5x7disp.asm ;Dhananjay V. Gadre ;31st August, 1999 ;Synopsis: ;--------- ;A display controller for a 5 by 7 dot matrix display. ;This Sample program has the 7 Cathodes on PortD and 5 ;anodes on PortB. A switch on PB7 is used to change the ;current displayed character. ;PB0 ---> Base of Anode0 Transistor ;PB1 ---> Base of Anode1 Transistor ;PB2 ---> Base of Anode2 Transistor ;PB3 ---> Base of Anode3 Transistor ;PB4 ---> Base of Anode4 Transistor ;Note the Anodes are connected to the collectors of PNP ;transistors. A 1Kohm resistor is put between the PortB ;pin and the transistor base ;PB7 ---> Sw1 ;PD0 ---> Cathode0 ;PD1 ---> Cathode1 ;PD2 ---> Cathode2 ;PD3 ---> Cathode3 ;PD4 ---> Cathode4 ;PD5 ---> Cathode5 ;PD6 ---> Cathode6 ;The cathodes are connected to the PortD pins with a ;series resistance of 150 Ohm each to limit the current. ;This leads to a LED current of about 20 mA with a ;20% duty cycle as each column of LED is on for 20% ;of the time. So the average current is about 3.6 mA ;per LED. .include "2313def.inc" ;These are reload values in TCNT0 for ;mux'ing the display .equ T1 = -20 ;leads to an intr rate of 200 Hz at ;4MHz clock and using 1/1024 the system clock ;as input to the timer. ;The actual clock used in the prototype is 3.58 MHz ;which leads to an intr rate of (200*3.58)/4 = 179 Hz ;Clock0 prescale select value .equ CKSRC = 5 ;divide the basic clock by 1024 .equ COL0 = $fe .equ COL1 = $fd .equ COL2 = $fb .equ COL3 = $f7 .equ COL4 = $ef .equ MAXKEY = 36 ;This is the max num of display codes ;in the system: A to Z, 0 to 9 and a blank ;Total of 37 display codes; the first display ;code is at address offset 0 and therefore the ;last is at 36 .def save_status = r1 ;used to store the SREG during an ISR .def sundry=r16 .def low_del=r17 ;delay variable .def high_del=r18 ;another delay variable .def temp=r19 ;temperory variable .def curr_char=r22 ;which char to display. has a value from ;0 to MAXKEY .def curr_col=r23 ;which is the current active column ;on the display. value between 0 to 5 .cseg .org 0 rjmp RESET ;Reset Handle ;for 2313, the Timer0 ISR starts at offset 6 in the code memory .org 6 rjmp Timer0_int ;Timer0 Interrupt Subroutine RESET: ldi temp, low(RAMEND) ;init the Stack pointer out SPL, temp ldi sundry, CKSRC ;select a clock source for the out TCCR0, sundry ;Timer0 to operate ldi sundry, T1 ;Load Timer0 reload value out TCNT0, sundry ; ldi sundry, 255 ;configure PORT D for all outputs out DDRD, sundry ldi sundry, 255 ;all PORT ouputs high out PORTD, sundry ldi sundry, 0b00011111 out DDRB, sundry ;configure PORTB ldi sundry, $ff ;everything on PORTB is off out PORTB, sundry ldi curr_char, 0 ;first char to be displayed will be ;'A' ldi curr_col, 0 ldi sundry, 2 ;Set the TOIE0 bit to enable out TIMSK, sundry ;the Timer0 Interrupt to occur sei ;enable interrupts ;This is the main part of the program which only ;looks for a keystroke on a switch connected to PB7 ;the display refresh is continually going on in the ;background main: rcall get_key ;increment the display character pointer ;on a keystroke. roll it to zero if it ;exceeds the max. cpi curr_char, MAXKEY brne itsnotmax ldi curr_char, 0 rjmp main itsnotmax: inc curr_char rjmp main rjmp main rjmp main ;Subroutine to wait for a switch to be pressed ;and released with suitable debounce get_key: sbic PINB, 7 ;if Pin PB7 is low rjmp get_key ;means switch is pressed. else go back rcall delay ;wait for the possible ;logic fluctuations to cease wait_for1: sbis PINB, 7 ;now wait for the switch to be ;released. If Pin PB7 is '1' ;the switch is released rjmp wait_for1 rcall delay ;again wait for some time. ret ;a simple delay subroutine. delay: ldi high_del, 100 reload_low: ldi low_del, 100 dec_low: dec low_del cpi low_del, 0 brne dec_low dec high_del cpi high_del, 0 brne reload_low ret ;The most important routine. It handles all the ;display switching. Timer0 interrupt occurs ;every 5 ms for a 4 MHz clock. Each column of the ;display gets the display value for this duration after ;which the next column has it;s turn and so on. Timer0_int: in save_status, SREG ;save processor status ldi temp, T1 out TCNT0, temp ;Get the display value to be put on the port pins. ldi ZH, high(DISPTABL*2); ;load display table address ldi ZL, low(DISPTABL*2); ;now calculate the offset into the table to get ;required column values which drive the LED cathodes ;since each character display code takes 3 words ;multiply the character pointer by 3, then add to the ;result to the base address. For a byte wide character pointer ;this method can safely access a table with upto 85 character ;display codes. mov sundry, curr_char mov temp, curr_char add sundry, sundry add sundry, temp add sundry, sundry ldi temp, 0 add ZL, sundry adc ZH, temp ;now increment the comulmn offset for a particular ;character; first check it is in range of 0 to 5 inc curr_col cpi curr_col, 5 brlt in_range ldi curr_col, 0 ;add the offset the table pointer in_range: add ZL, curr_col adc ZH, temp lpm ;and get the code in reg R0 ;now find out which column this code belongs to. ;In our particular case, the display table ;contains value in the order COL4, COL3, COL2, COL1 and COL0 ;there fore a curr_col value of 0 means refresh column 4 ;and so on. cpi curr_col, 0 brne not_0 ldi temp, COL4 rjmp dump_it not_0: cpi curr_col, 1 brne not_1 ldi temp, COL3 rjmp dump_it not_1: cpi curr_col, 2 brne not_2 ldi temp, COL2 rjmp dump_it not_2: cpi curr_col, 3 brne not_3 ldi temp, COL1 rjmp dump_it not_3: ldi temp, COL0 dump_it: ldi sundry, 255 ;first put off all columns out PORTB, sundry com r0 ;complement the row values out PORTD, r0 ;now dump the row values. ;This enables one of the 5 ;PNP transistors out PORTB, temp ;now set the columns to reqd value out SREG, save_status ;restore machine status reti ;-------------------------------------------------------- ;---------------Character Display Codes------------------ ;------------------A-Z 0-9 and blank--------------------- ;-------------------------------------------------------- ;Display table with 6 entries for each character. The ;last entry is 0 by default and is not used. Only the ;first 5 entries are used. but since each storage ;location in the program memory of the processor is ;2 bytes, a minimum of 3 words must be used. ;The display values are such that the first entry in the ;table corresponds to the fifth column of the display ;matrix. Also, the values encoded in this table are for ;a 'rows with anodes' display but the display that I am using ;is a 'rows on cathode' kind. Hence the value must be ;inverted before putting on the port pins. DISPTABL: DATAA: .db $1F, $28 ; .db $48, $28 ; .db $1F, 0 ; DATAB: .db $36, $49 ; .db $49, $49 ; .db $7F, 0 ; DATAC: .db $22, $41 .db $41, $41 .db $3E, 0 DATAD: .db $3E, $41 .db $41, $41 .db $7f, 0 DATAE: .db $41, $49 .db $49, $49 .db $7f,0 DATAF: .db $40, $48 .db $48, $48 .db $7F, 0 DATAG: .db $26, $45 .db $45, $41 .db $3E, 0 DATAH: .db $7f, $08 .db $08, $08 .db $7F, 0 DATAI: .db $41, $41 .db $7F, $41 .db $41, 0 DATAJ: .db $40, $07E .db $41, $41 .db $46, 0 DATAK: .db $41, $22 .db $14, $08 .db $7f, 0 DATAL: .db $01, $01 .db $01, $01 .db $7F, 0 DATAM: .db $7F, $20 .db $18, $20 .db $7F, 0 DATAN: .db $7F, $04 .db $08, $10 .db $7F, 0 DATAO: .db $3E, $41 .db $41, $41 .db $3E, 0 DATAP: .db $30, $48 .db $48, $48 .db $7F, 0 DATAQ: .db $3F, $43 .db $45, $41 .db $3E, 0 DATAR: .db $31, $4A .db $4C, $48 .db $7F, 0 DATAS: .db $26, $49 .db $49, $49 .db $32, 0 DATAT: .db $40, $40 .db $7F, $40 .db $40, 0 DATAU: .db $7E, $01 .db $01, $01 .db $7E, 0 DATAV: .db $7C, $02 .db $01, $02 .db $7C, 0 DATAW: .db $7E, $01 .db $0E, $01 .db $7E, 0 DATAX: .db $63, $14 .db $08, $14 .db $63, 0 DATAY: .db $60, $10 .db $0F, $10 .db $60, 0 DATAZ: .db $61, $51 .db $49, $45 .db $43, 0 DATA0: .db $3E, $51 .db $49, $45 .db $3E, 0 DATA1: .db $01, $01 .db $7F, $21 .db $11, 0 DATA2: .db $33, $49 .db $45, $43 .db $31, 0 DATA3: .db $36, $49 .db $49, $41 .db $22, 0 DATA4: .db $04, $7F .db $24, $14 .db $0C, 0 DATA5: .db $4E, $51 .db $51, $51 .db $72, 0 DATA6: .db $26, $49 .db $49, $49 .db $3E, 0 DATA7: .db $70, $48 .db $44, $42 .db $41, 0 DATA8: .db $36, $49 .db $49, $49 .db $36, 0 DATA9: .db $3E, $49 .db $49, $49 .db $30, 0 BLANK: .db $00, $00 .db $00, $00 .db $00, 0