;*************************************************************************
;
; Project : RDD (REMOTE DATA DISPLAY)
;
; Title : RDDKITC1.SRC
;
; Registry No. :
;
; Version Edit author Date Change description
; ------- ----------- ----- ---------------------
; A G.HOPKINS 01/07/99 Initial development
; B G.HOPKINS 09/08/00 Preset number facility added
;***********************************************************************
;
; SOFTWARE FOR REMOTE DATA COMMAND STATION USING AT89C2051
;
;***********************************************************************
;
;
;-----------------------------------------------------------------------
;
; CONSTANTS
;
$mod51
stack EQU 0000FH ; start of stack
presence_copy EQU 00060H ; copy of presence bytes for gradual acknowledge
data_4 EQU 0005BH ; | counter stores
data_3 EQU 0005AH ; | counter stores
data_2 EQU 00059H ; | counter stores
data_1 EQU 00058H ; | counter stores
presence_origin EQU 00050H ; bytes to indicate presence of displays (8)
mess_store_origin EQU 00030H ; start of o/p message store
data_store EQU 00038H ; start of data
del_count1 EQU 0004AH ; delay counter msb
del_count0 EQU 00049H ; delay counter lsb
TOH EQU 00048H ; timeout counter hi
TOL EQU 00047H ; timeout counter lo
mess_length EQU 00046H ; current message length
rx_byte_store EQU 00045H ; rx byte store
rx_chk_acc EQU 00044H ; rx checksum accumulator
rx_byte_count EQU 00043H ; rx byte counter
mess_type EQU 00041H ; message type store
tx_chk_acc EQU 00041H ; tx checksum accumulator
addr_store EQU 00040H ; address store
tried EQU 033H ; indicates an ack poll has occurred
nb EQU 034H ; no blanking flag
present EQU 035H ; present flag
disp_done EQU 036H ; indicates display has been updated
dp EQU 037H ; decimal point
new_data EQU 038H ; new data is being displayed
flash EQU 039H ; flash flag
reply_ack EQU 03AH ; acknowledge flag (1=acknowledge)
char_received EQU 03BH ; indicates a character has arrived
message_incoming EQU 03CH ; indicates a message is arriving 
length_byte_flag EQU 03DH ; indicates byte is length
new_rx_mess EQU 03EH ; indicates new message for processing
delay_over_flag EQU 03FH ; indicates delay has finished
i_sw EQU P1.0 ; inc switch
d_sw EQU P1.1 ; dec switch
s_sw EQU P1.2 ; send switch
r_sw EQU P1.3 ; reset switch
p_sw EQU P1.4 ; poll switch
baud_rate EQU 0FDH ; reload value to give
; baud rate for timer 1 in mode 3
; =(2^PCON.7)*Osc/(384*(256-baud_rate))
; Osc=11.0592E6, baud=9600, PCON.7=0.
;
;-----------------------------------------------------------------------------
;
; I/O port usage
;
; P1.0 inc switch
; P1.1 dec switch
; P1.2 send switch
; P1.3 reset switch
; P1.4 poll/no poll switch
; P1.5 ack led clk
; P1.6 ack led data
; P1.7 ack led strobe
;
; P3.0 RXD
; P3.1 TXD
; P3.2 Tx/Rx Control
; P3.3 display /data enable 
; P3.4 display data
; P3.5 display clock
; P3.7 
;
;-----------------------------------------------------------------------------
;
ORG 00000H ;reset vector
JMP init ;goto start of program
ORG 0000BH ;T0 vector
CALL t0_isr
RETI
ORG 00023H ;serial interrupts
CALL serial_isr ;RI and TI interrupts
RETI ; 

;------------------------------------------------------------------------------
;
init:
MOV P1,#01FH ;initialise port 1, clk data, strobe low
MOV P3,#0CBH ;initialise port 3, clk, data, tx/rx low 
ANL PSW,#0E7H ;select reg bank 0
MOV SP,#stack ;stack origin
CLR EA ;disable interrupts
CLR TR0 ;Timer 0 off
CLR TR1 ;Timer 1 off
CLR delay_over_flag ;reset delay flag
MOV TMOD,#021H ;Timer 0 set to 16 bit for delay
;Timer 1 set to 8 bit auto for baud
start_serial_link:
MOV SCON,#11010000B ;Run serial port in mode 3 (7,6)
;Turn off multiproc. Feature (5)
;Enable data reception (4)
;Set 9th bit to space parity (3)
;(2,1,0) are RB8,TI,RI and are
;controlled by hardware
ANL PCON,#000H ;NOT Double baud rate for UART (7)
MOV TH0,#000H ;set up timer 0 to give delay of
MOV TL0,#000H ;~100ms
MOV TH1,#baud_rate ;set up timer 1 to give baud rate of
MOV TL1,#baud_rate ;9600
SETB TR1 ;start baud rate generator timer 1.
MOV IP,#00010000B ;Not used (7,6,5)
;Give serial port max prior (4)
;Give low priority to other
;potential sources (3,2,1,0)
SETB EA ;enable interrupts
SETB ET0 ;allow T0 interrupts first
CALL clear_disp ;ensure correct start-up
CALL self_test ;self test routine
SETB ES ;now allow serial interrupts
CALL poll_check ;determine displays on bus
CALL disp_poll ;display results on LEDs
JB r_sw,$ ;wait for reset switch
CALL clear_disp ;leds off
MOV data_1,#000H ;zero counter stores
MOV data_2,#000H
MOV data_3,#000H
MOV data_4,#000H
JB s_sw,main ;if send switch held down, enter presetting sequence
CALL preset ;allow previous number entry
main:
JNB r_sw,reset_sys_call ;if reset switch selected 
JNB s_sw,send_data_call ;if send switch selected
JNB d_sw,dec_disp_call ;if dec switch selected
JNB i_sw,inc_disp_call ;if inc switch selected
JMP main ;loop if there is no command to do 

reset_sys_call:
CALL reset_sys
JNB r_sw,$ ;wait here until switch up
CALL debounce ;debounce
JMP main

send_data_call:
CALL send_data
JNB s_sw,$ ;wait here until switch up
CALL debounce ;debounce
JMP main

dec_disp_call:
CALL dec_disp
JNB d_sw,$ ;wait here until switch up 
CALL debounce ;debounce
JMP main

inc_disp_call:
CALL inc_disp
JNB i_sw,$ ;wait here until switch up
CALL debounce ;debounce
JMP main

reset_sys:
CALL clear_disp
CALL poll_check
CALL disp_poll
CALL disp_del ;allow viewing
JNB r_sw,$ ;wait for reset switch up
CALL debounce ;debounce
CALL clear_disp
MOV data_1,#000H ;zero counter stores
MOV data_2,#000H
MOV data_3,#000H
MOV data_4,#000H
CALL conv_to_disp
CALL led_display
CALL send_data
RET

preset:
JNB s_sw,$ ;wait for switch up
CALL debounce ;debounce
JNB r_sw,$ ;wait for switch up
CALL debounce ;debounce
MOV R5,#000H ;point to first digit
CALL conv_to_pre_disp ;ascii conversion with modified blanking
CALL led_display ;display first digit for preset
preset_loop:
JNB i_sw,inc_disp_x ;increment digit
JNB d_sw,dec_disp_x ;decrement digit
JNB s_sw,next_preset ;point to next digit
JNB r_sw,exit_preset ;exit preset routine
JMP preset_loop ;until exit

next_preset:
CALL debounce ;debounce
INC R5 ;R5 is preset digit counter (starts at 0)
CJNE R5,#004H,no_wrap ;detect digit wrap round 
MOV R5,#000H ;start at first digit again
no_wrap:
CALL conv_to_pre_disp ;ascii conversion with modified blanking
CALL led_display ;unblank display digit for preset
JNB s_sw,$ ;wait for switch up
CALL debounce ;debounce
JMP preset_loop ;go back to switches

exit_preset:
CALL debounce ;debounce
CALL conv_to_disp ;revert to standard display after preset
CALL led_display ;
JNB r_sw,$ ;wait for switch up
CALL debounce ;debounce
RET

dec_disp_x: ;individual digit dec, R5 holds digit on entry
CALL debounce ;debounce
CLR C ;no carry
MOV A,R5 ;ready for offset calculation
ADD A,#data_1 ;add digit offset
MOV R0,A ;store digit address in R0
MOV A,@R0 ;get required digit value
DEC A
CJNE A,#0FFH,no_under ;detect underflow
MOV A,#009H ;underflow to 9
no_under:
MOV @R0,A ;put modified digit back
CALL conv_to_pre_disp ;ascii conversion with modified blanking
CALL led_display
JNB d_sw,$ ;wait here for switch up
CALL debounce ;debounce
JMP preset_loop ;go back to switches

inc_disp_x: ;individual digit inc, R5 holds digit on entry
CALL debounce ;debounce
CLR C ;no carry
MOV A,R5 ;ready for offset calculation
ADD A,#data_1 ;add digit offset
MOV R0,A ;store digit address in R0
MOV A,@R0 ;get required digit value
INC A
CJNE A,#00AH,no_over ;detect overflow
CLR A ;overflow back to 0
no_over:
MOV @R0,A ;put modified digit back
CALL conv_to_pre_disp ;ascii conversion with modified blanking
CALL led_display
JNB i_sw,$ ;wait here for switch up
CALL debounce ;debounce
JMP preset_loop ;go back to switches

send_data:
SETB P3.2 ;set tx mode
CALL delay_500us ;wait for bus
MOV R1,#data_store ;point to data store
MOV R2,#004H ;4 data bytes to send
MOV tx_chk_acc,#000H ;clear checksum
MOV A,#006H ;message type 6 to global address 0
SETB TB8 ;mark parity for address
MOV SBUF,A ;send addr/mess type
JNB TI,$ ;wait until sent
CLR TI ;ready for next
CLR TB8 ;space parity for others
MOV SBUF,#005H ;5 bytes to follow
JNB TI,$ ;wait until sent
CLR TI ;ready for next
next_data_send:
MOV A,@R1 ;get byte
INC R1 ;ready for next
MOV SBUF,A ;send byte
XRL A,tx_chk_acc ;calculate checksum
MOV tx_chk_acc,A ;update store
JNB TI,$ ;wait until sent
CLR TI ;ready for next
DJNZ R2,next_data_send ;send all 4 bytes
MOV SBUF,tx_chk_acc ;send checksum
JNB TI,$ ;wait until sent
CLR TI ;ready for next
CALL delay_50us ;release bus delay
CLR P3.2 ;revert to receive
JNB p_sw,poll_ack ;check poll switch
RET

poll_ack:
CALL copy_presence ;create temporary copy for ack
next_round:
CLR tried ;until a poll occurs
MOV R0,#000H ;address pointer
MOV R1,#presence_copy ;point to first address
MOV R2,#008H ;8 to check
next_poll_ack:
INC R0 ;point to next bus address
MOV A,@R1 ;get presence value
JZ next_try ;ack already received if zero
SETB tried ;indicate a poll was requested this round
CALL get_response ;prompt response from display
JNB present,next_try ;ignore if timeout occurs
MOV @R1,rx_byte_store ;update acknowledge - become zero if ack
next_try:
INC R1
DJNZ R2,next_poll_ack ;if all polled, display results
MOV R1,#presence_copy ;formulate_ack_display
CALL format_ack
JB p_sw,poll_ack_exit ;either exit if polling abandoned or
JNB r_sw,poll_ack_exit ;if reset switch selected as a last resort
JB tried,next_round ;keep trying until all acks received
RET
poll_ack_exit:
MOV A,#0FFH ;clear ack leds
CALL ack_disp
RET

copy_presence: ;create temporary copy for acknowledge sequence
MOV R0,#presence_origin ;original
MOV R1,#presence_copy ;copy
MOV R2,#008H ;8 to copy
next_copy:
MOV A,@R0 ;get original
MOV @R1,A ;make copy
INC R0
INC R1
DJNZ R2,next_copy ;do 8 copies
RET

dec_disp:
CLR C ;ready for sub
MOV A,data_1 ;get lsb
SUBB A,#001H ;decrement
CJNE A,#0FFH,no_uf1 ;no underflow if >= 0
MOV A,#009H ;back to 9
no_uf1:
CPL C ;after compare, ready for next sub
MOV data_1,A ;store new lsb
MOV A,data_2 ;get next
SUBB A,#000H ;include carry only
CJNE A,#0FFH,no_uf2 ;no underflow if >=0
MOV A,#009H ;back to 9
no_uf2:
CPL C ;after compare, ready for next add
MOV data_2,A ;store new 2sb
MOV A,data_3 ;get next
SUBB A,#000H ;include carry only
CJNE A,#0FFH,no_uf3 ;no underflow if >=0
MOV A,#009H ;back to 9
no_uf3:
CPL C ;after compare, ready for next add
MOV data_3,A ;store new 3sb
MOV A,data_4 ;get next
SUBB A,#000H ;include carry only
CJNE A,#0FFH,no_uf4 ;no underflow if >=0
MOV A,#009H ;back to 9
no_uf4:
CPL C ;after compare, ready for next add
MOV data_4,A ;store new msb
CALL conv_to_disp ;ascii conversion
CALL led_display
RET

inc_disp:
CLR C ;ready for add
MOV A,data_1 ;get lsb
ADD A,#001H ;increment
CJNE A,#00AH,no_of1 ;no overflow if less than 10
CLR A
no_of1:
CPL C ;after compare, ready for next add
MOV data_1,A ;store new lsb
MOV A,data_2 ;get next
ADDC A,#000H ;include carry only
CJNE A,#00AH,no_of2 ;no overflow if less than 10
CLR A
no_of2:
CPL C ;after compare, ready for next add
MOV data_2,A ;store new 2sb
MOV A,data_3 ;get next
ADDC A,#000H ;include carry only
CJNE A,#00AH,no_of3 ;no overflow if less than 10
CLR A
no_of3:
CPL C ;after compare, ready for next add
MOV data_3,A ;store new 3sb
MOV A,data_4 ;get next
ADDC A,#000H ;include carry only
CJNE A,#00AH,no_of4 ;no overflow if less than 10
CLR A
no_of4:
CPL C ;after compare, ready for next add
MOV data_4,A ;store new msb
CALL conv_to_disp ;ascii conversion
CALL led_display
RET

disp_del: 
MOV TOH,#0FFH ;approx 1s
MOV TOL,#0FFH ;display delay
next_disp_del:
NOP
NOP
NOP
NOP
NOP
DJNZ TOL,next_disp_del ;small wait
DJNZ TOH,next_disp_del ;next large wait
RET

conv_to_disp:
CLR nb ;allow blanking for now
MOV R1,#data_store ;point to display data store, left
MOV A,data_4 ;get highest digit
JZ blank1 ;zero blanking
ADD A,#010H ;extra addition for ascii offset
SETB nb ;disallow further blanking
blank1:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
INC R1 ;point to next display data store
MOV A,data_3 ;get second highest digit
JB nb,no_blank2 ;no blanking
JZ blank2 ;zero blanking
no_blank2:
ADD A,#010H ;extra addition for ascii offset
SETB nb ;disallow further blanking
blank2:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
INC R1 ;point to next display data store
MOV A,data_2 ;get third highest digit
JB nb,no_blank3 ;no blanking
JZ blank3 ;zero blanking
no_blank3:
ADD A,#010H ;extra addition for ascii offset
SETB nb ;disallow further blanking
blank3:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
INC R1 ;point to next display data store
MOV A,data_1 ;get lowest digit
; JB nb,no_blank4 ;no blanking ;prevent blanking of last digit
; JZ blank4 ;zero blanking
;no_blank4:
ADD A,#010H ;extra addition for ascii offset
;blank4:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
RET

conv_to_pre_disp:
CLR nb ;allow blanking for now
MOV R1,#data_store ;point to display data store, left
MOV A,data_4 ;get highest digit
JZ pre_blk4 ;if zero check for presetting this digit
JMP asc_dig4 ;if not zero, convert to ascii anyway
pre_blk4:
CJNE R5,#003H,pre_blank4 ;if it's not this digit allow further blanking
asc_dig4: ;it is an ascii digit
ADD A,#010H ;extra addition for ascii offset
SETB nb ;disallow further blanking
pre_blank4:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
INC R1 ;point to next display data store
MOV A,data_3 ;get second highest digit
JZ pre_blk3 ;if zero check for presetting this digit
JMP asc_dig3 ;if not zero, convert to ascii anyway
pre_blk3:
JB nb,asc_dig3 ;if no blanking allowed make it ascii
CJNE R5,#002H,pre_blank3 ;if it's not this digit allow further blanking
asc_dig3: ;it is an ascii digit
ADD A,#010H ;extra addition for ascii offset
SETB nb ;disallow further blanking
pre_blank3:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
INC R1 ;point to next display data store
MOV A,data_2 ;get second highest digit
JZ pre_blk2 ;if zero check for presetting this digit
JMP asc_dig2 ;if not zero, convert to ascii anyway
pre_blk2:
JB nb,asc_dig2 ;if no blanking allowed make it ascii
CJNE R5,#001H,pre_blank2 ;if it's not this digit allow further blanking
asc_dig2: ;it is an ascii digit
ADD A,#010H ;extra addition for ascii offset
SETB nb ;disallow further blanking
pre_blank2:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
INC R1 ;point to next display data store
MOV A,data_1 ;get second highest digit
JZ pre_blk1 ;if zero check for presetting this digit
JMP asc_dig1 ;if not zero, convert to ascii anyway
pre_blk1:
JB nb,asc_dig1 ;if no blanking allowed make it ascii
CJNE R5,#000H,pre_blank1 ;if it's not this digit allow further blanking
asc_dig1: ;it is an ascii digit
ADD A,#010H ;extra addition for ascii offset
SETB nb ;disallow further blanking
pre_blank1:
ADD A,#020H ;minimum addition for space
MOV @R1,A ;store display char
RET

clear_disp: ;segs first, then acks
CLR P3.5
CLR P3.4
CLR P3.3
MOV R2,#002H ;do it twice
next_clr_disp:
MOV R1,#028H ;segs to do
SETB P3.4 ;start bit
NOP
SETB P3.5 ;clock
NOP
CLR P3.5
NOP
CLR P3.4 ;all data zero
NOP
next_clr_seg:
SETB P3.5 ;clock
NOP
CLR P3.5
NOP
DJNZ R1,next_clr_seg ;do all segs
DJNZ R2,next_clr_disp ;clear twice
MOV A,#0FFH ;ack leds off
CALL ack_disp
RET 

led_display:
CLR P3.3 ;enable data
MOV DPTR,#char_segs ;point to look-up table
MOV R0,#data_store ;point to segmented stores
MOV R2,#004H ;4 chars to do
SETB P3.4 ;start bit
NOP
SETB P3.5 ;sr clock high
NOP
CLR P3.5 ;sr clock low
NOP
next_disp_char:
MOV A,@R0 ;get ascii char
CLR C
SUBB A,#020H ;<space> is lowest valid char
MOVC A,@A+DPTR ;get segmented version
MOV C,dp ;get dp setting
MOV ACC.0,C ;dp into A
MOV R1,#008H ;8 segs to do
next_seg:
RLC A ;segment into C
MOV P3.4,C ;C to display
NOP
SETB P3.5 ;sr clock high
NOP
CLR P3.5 ;sr clock low
NOP
DJNZ R1,next_seg ;do all segs
INC R0 ;point to next segmented char
DJNZ R2,next_disp_char ;do next display character
MOV A,@R0 ;get external LEDs
ANL A,#0C0H ;ensure rest is zero
MOV R1,#006H ;6 more to do including 3 spare
next_seg2:
RLC A ;LED into C
MOV P3.4,C ;C to display
NOP
SETB P3.5 ;sr clock high
NOP
CLR P3.5 ;sr clock low
NOP
DJNZ R1,next_seg2 ;do all segs
RET

poll_check:
MOV R0,#000H ;address pointer
MOV R1,#presence_origin ;presence byte store
MOV R2,#008H ;8 to check
next_check:
INC R0 ;next address
CALL get_response ;prompt display
CLR A ;ready to store presence
MOV C,present ;get present bit into C
ADDC A,#000H ;include present bit
MOV @R1,A ;store bit
INC R1 ;next location
DJNZ R2,next_check ;check next address
RET

get_response:
SETB present ;assume present for now
MOV A,R0 ;copy to A for poll
CALL poll ;send message type 5
MOV TOH,#03CH ;approx 100ms timeout
MOV TOL,#022H ;for each character
next_check_to1: 
JB char_received,present1 ;if char arrives in time
DJNZ TOL,next_check_to1 ;small wait
DJNZ TOH,next_check_to1 ;next large wait
not_present1:
CLR present ;forget it and start again
present1:
CLR char_received ;clear flag and wait for second byte
MOV TOH,#03CH ;approx 100ms timeout
MOV TOL,#022H ;for each character
next_check_to2: 
JB char_received,present2 ;if char arrives in time
DJNZ TOL,next_check_to2 ;small wait
DJNZ TOH,next_check_to2 ;next large wait
not_present2:
CLR present ;forget it and start again
present2:
CLR char_received ;clear flag
RET

disp_poll:
MOV data_store,#'P' ;prompt segs
MOV data_store+1,#'O' ;
MOV data_store+2,#'L' ;
MOV data_store+3,#'L' ;
CLR dp ;dp's off
CALL led_display
MOV R1,#presence_origin ;start at bottom
CALL format_ack ;formulate ack display
RET

format_ack:
MOV R2,#008H ;8 to get
CLR A
MOV B,A ;clear B as well
CLR C
next_presence:
MOV A,@R1 ;get bit value
RRC A ;presence into C
XCH A,B ;exchange values
RLC A ;presence into byte
XCH A,B ;swap back
INC R1 ;next presence
DJNZ R2,next_presence ;do all 8
XCH A,B ;get presence byte
CPL A ;invert for display
CALL ack_disp ;send to leds
RET

poll:
SETB P3.2 ;set tx mode
CALL delay_500us ;wait for bus
ADD A,#050H ;include message type in top nibble
SWAP A ;swap nibbles
SETB TB8 ;mark parity for address
MOV SBUF,A ;send addr/mess type
JNB TI,$ ;wait until sent
CLR TI ;ready for next
CLR TB8 ;space parity for others
MOV SBUF,#002H ;two bytes to follow
JNB TI,$ ;wait until sent
CLR TI ;ready for next
MOV SBUF,#001H ;request lowest bit
JNB TI,$ ;wait until sent
CLR TI ;ready for next
MOV SBUF,#001H ;same again for checksum
JNB TI,$ ;wait until sent
CLR TI ;ready for next
CLR P3.2 ;revert to receive
CALL delay_50us ;release bus delay
RET

debounce:
MOV del_count1,#005H ;all incremented by one
MOV del_count0,#09AH ;for djnz 
CALL delay
RET

delay_50us:
MOV del_count1,#001H ;all incremented by one
MOV del_count0,#010H ;for djnz
CALL delay
RET

delay_500us:
MOV del_count1,#001H ;all incremented by one
MOV del_count0,#09AH ;for djnz 
CALL delay
RET

delay: ;553/256 us per count 
DJNZ del_count0,delay ;small delay
DJNZ del_count1,delay ;medium delay
RET

t0_isr:
JNB flash,stop_flash ;stop flashing if acknowledge detected
DJNZ R3,next_t0
CPL dp
CALL led_display ;toggle decimal points
MOV R3,#008H ;2 T0's per toggle period (~2.5Hz)
SETB disp_done ;indicate display has been updated
next_t0:
RET ;carry on
stop_flash:
CLR TR0 ;stop timer
CLR dp
CALL led_display ;decimal points off
RET

self_test:
MOV R3,#008H ;ready for flashing
CLR disp_done ;not done yet
SETB flash ;allow flashing
SETB TR0 ;set flash timer running
SETB RS0 ;select RB1
MOV R2,#000H ;start point in sequence
MOV R4,#01AH ;26 chars to scroll
st_loop2: ;get next 4
MOV DPTR,#st_data ;point to self test character store
MOV R3,#004H ;4 chars to load each time
MOV R0,#data_store ;place to put characters
MOV R1,00AH ;MOV R1,R2 equivalent
st_loop1: ;get next char
MOV A,R1 ;load offset
MOVC A,@A+DPTR
MOV @R0,A ;put char in store
INC R0
INC R1
DJNZ R3,st_loop1 ;do all 4 chars
CLR RS0 ;revert to RB0
wait_seg_st: ;expect flash timer when disp done
JBC disp_done,cont_seg_st ;if disp is done, continue self test sequence
JMP wait_seg_st ;otherwise wait here
cont_seg_st:
SETB RS0 ;back to RB1 for next load
INC R2 ;point to next start char
DJNZ R4,st_loop2 ;scroll 26 times
MOV A,#0FFH ;all leds off to start
CLR C ;walking zero
MOV R0,#008H ;8 to test
next_led_st:
RRC A ;shift starting point down 1
PUSH ACC ;store current
CALL ack_disp ;display leds
CLR RS0
wait_led_st: ;expect flash_timer
JBC disp_done,cont_led_st ;if disp done, continue
JMP wait_led_st ;otherwise wait here
cont_led_st:
SETB RS0
POP ACC ;retrieve previous
SETB C ;ensure last led goes off next time
DJNZ R0,next_led_st ;next led on
CALL clear_disp ;clear after test sequence
CLR RS0 ;back to RB1 after chars put on display
CLR TR0 ;stop flash timer
CLR flash ;disable flashing
RET

ack_disp: ;A contains data on entry, uses R1
CLR P1.5 ;ensure clk low
CLR P1.7 ;ensure strobe low
MOV R1,#008H ;8 clks per disp
next_led_clk:
RLC A ;bottom up
MOV P1.6,C ;led data to port
SETB P1.5 ;clk hi
CLR P1.5 ;clk low
DJNZ R1,next_led_clk ;next bit out
SETB P1.7 ;strobe hi
CLR P1.7 ;strobe low
RET

st_data:
DB ' '
DB ' '
DB ' '
DB ' '
DB 'S'
DB 'E'
DB 'L'
DB 'F'
DB ' '
DB 't'
DB 'E'
DB 'S'
DB 't'
DB ' '
DB '0'
DB '1'
DB '2'
DB '3'
DB '4'
DB '5'
DB '6'
DB '7'
DB '8'
DB '9'
DB ' '
DB 'L'
DB 'E'
DB 'd'
DB 'S'
;---------------------------------------------------------------------------
; SERIAL PORT INTERRUPT HANDLER

serial_isr:
JB RI,test_for_addr ;jump if an RI interrupt (byte recd)
RET ;return if a TI interrupt

test_for_addr:
PUSH ACC ;store acc
PUSH PSW ;store psw
SETB RS0 ;select RB1
SETB char_received ;set flag
MOV rx_byte_store,SBUF ;store rx data, same for both bytes
quit_rx_int:
POP PSW
POP ACC
CLR RI ;Acknowledge interrupt handled.
RET ;Return to interrupt vector.

;---------------------------------------------------------------------------
;
char_segs:
DB 00000000B ;<space> 32
DB 0
DB 01000100B ;" 34
DB 0
DB 0
DB 0
DB 0
DB 01000000B ;' 39
DB 10011100B ;( 40
DB 11110000B ;) 41
DB 0
DB 0
DB 00000100B ;` 44
DB 00000010B ;- 45
DB 0
DB 0
DB 11111100B ;0 48
DB 01100000B ;1 49
DB 11011010B ;2 50
DB 11110010B ;3 51
DB 01100110B ;4 52
DB 10110110B ;5 53
DB 10111110B ;6 54
DB 11100000B ;7 55
DB 11111110B ;8 56
DB 11110110B ;9 57
DB 0
DB 0
DB 0
DB 0
DB 0
DB 11001010B ;? 63
DB 0
DB 11101110B ;A 65
DB 11111110B ;B 66
DB 10011100B ;C 67
DB 11111100B ;D 68
DB 10011110B ;E 69
DB 10001110B ;F 70
DB 10111100B ;G 71
DB 01101110B ;H 72
DB 01100000B ;I 73
DB 11111000B ;J 74
DB 0
DB 00011100B ;L 76
DB 0
DB 0
DB 11111100B ;O 79
DB 11001110B ;P 80
DB 0
DB 0
DB 10110110B ;S 83
DB 0
DB 01111100B ;U 85
DB 0
DB 0
DB 0
DB 0
DB 0
DB 10011101B ;[ 91
DB 0
DB 11110000B ;] 93
DB 0
DB 00010000B ;_ 95
DB 00000100B ;` 96
DB 11111010B ;a 97
DB 00111110B ;b 98
DB 00011010B ;c 99
DB 01111010B ;d 100
DB 11011110B ;e 101
DB 10001110B ;f 102
DB 11110110B ;g 103
DB 00101110B ;h 104
DB 01000000B ;i 105
DB 01111000B ;j 106
DB 0
DB 01100000B ;l 108
DB 0
DB 00101010B ;n 110
DB 00111010B ;o 111
DB 11001110B ;p 112
DB 0
DB 00001010B ;r 114
DB 10110110B ;s 115
DB 00011110B ;t 116
DB 00111000B ;u 117
DB 0
DB 0
DB 0
DB 01110110B ;y 121
DB 0


END


