; MONITOR for system based on AT89S8252 microcontroler
; Microcontroler clock rateà - 11059,2 kHz
; User program is loaded from PC through RS-232 interface
; and located in external memory beginning from address 2000h

; Declarative part

; Bit declaration
    UP_ACT   bit   7Fh           ; User program activity flag

; Stack parameters
    Init_SP     equ  70h
    stack_size  equ  16

; Reloading control data
    CtrlByteAddr  data  0FFh
    CtrlCode      equ   10101011b

; Addresses of input and output        devices
    ports     equ   0FFh
    SSI_0     equ   0FFF7h   ; SSI - 0 (seven-segment indicators)
    SSI_1     equ   0FFF8h   ; SSI - 1
    SSI_2     equ   0FFF9h   ; SSI - 2
    SSI_3     equ   0FFFAh   ; SSI - 3

    PPI_RUS   equ   0FFFFh   ; Control register of PPI
    LCD       equ   0FFF0h   ; 10-digit LCD-monitor
    LED       equ   0FFF1h   ; 8 single-bit indicators (ligth-emission diodes)

    M_UP      equ   P3.5     ; Signal from switcher "Monitor/User program" (UP - "0" )

; User interrupt vectors table
    UserPrg   equ    2000h            ; Start vector
                                      ; Vectors:
    INT0_U    equ    2003h            ; from external INT0
    T0_U      equ    200Bh            ; from timer T0
    INT1_U    equ    2013h            ; from external INT1
    T1_U      equ    201Bh            ; from timer T1
    UAPP_U    equ    2023h            ; this int vector used for user program
    T2_U      equ    202Bh            ; from timer T2

; Byte code for turning PPI (all ports to input )
    PPI_init   equ    10000000b

; Byte code for setting timer 0 and timer 1 mode
    Init_TMOD  equ   00100010b      ; both timer works in equal mode "0010"
                  ;  0 - program start only
                  ;   0 - device operates as timer
                  ;    10 - automatic reloading modeà

; Byte code for setting UART mode
    Init_SCON  equ   11010000b
                  ;  11       - 9-bit message mode
                  ;    0      - do not kill messages with 9-th bit equal 0
                  ;     1     - receiving enabled (REN=1)
                  ;      00     - start values of 9-th bit for transmit and receiveà
                  ;        00        - start values of interrupt flags (TI and RI)à

    Init_IE   equ    10010000b  ; byte code for setting enebled interrupts
                                ; (only UART interrupt is enabled)

    Init9600  equ  253           ; reloading number for timer 1 to provide 9600 bit/s UART rate
                           ; according to 11059,2 kHz clock rate

    off_code  equ  11H         ; Code for turning off the SSI
    zero_mask equ  0FH  ; Mask for selecting low 4-bit group

    SCode      equ  00010000b  ; Start code for LCD control (A0=1, WR1=0)
    PlusCode   equ  00110000b  ; Set PLUS and off LCD (A0=1, WR1=0, WR2=1)
    MinusCode  equ  10110000b  ; Set MINUS and off LCD (A0=1, WR1=0, WR2=1)
    A0    bit  acc.4
    WR1   bit  acc.6

DSEG
  org Init_SP
    ds  stack_size

; Executable part of MONITOR
CSEG
 ORG 0
         JMP    MONITOR    ; Start interrupt vector
 ORG 03H
         JMP    INT0_U     ; INT0 interrupt vector - by flag IE0
 ORG 0BH
         JMP    T0_U       ; Timer T0 interrupt vector íàby flag TF0
 ORG 13H
         JMP    INT1_U     ; INT1 interrupt vector - by flag IE1
 ORG 1BH
         JMP    T1_U       ; Timer T1 interrupt vector íàby flag TF1

 ORG 23h                   ; UART interrupt vector - by flags RI or TI
         JNB        UP_ACT, UAPP_M        ; for MONITOR
         JMP        UAPP_U                ; for user program
 ORG 2BH
         JMP    T2_U       ; Timer T2 interrupt vector íàby flag TF2
;---------------------------------------------------------------------
 ORG 0030H

MONITOR:

   CLR         RS0                   ; 0 register bank is active
   CLR         RS1
   MOV   SP,#Init_SP-1     ; initialization of the stack

   MOV   R2,#4             ; 0.4s delay for full reset of all devices
   CALL  DELAY01r

   CLR   UP_ACT            ; MONITOR is active

   MOV   SCON, #Init_SCON
   MOV   TMOD, #Init_TMOD

   MOV   TL1,  #Init9600   ; Set reloaded number to Timer T1
   MOV   TH1,  #Init9600   ; to provide 9600 bit/s UART rate

   MOV   PCON, #0           ; Bit SMOD = 0

   SETB   TR1                   ; start Timer T1 -> UART starts its operation

   SETB   PS               ; UART has the higher priority
   MOV    IE, #Init_IE     ; tunning the interrupt enable register

   SETB  M_UP                   ; tunning P3.5 pin to input ( to receive M/UP signal)

   MOV   P2, #ports           ; Initializing (P2) for use LEDs and SSI


        MOV  R0,#CtrlByteAddr
        cjne @R0,#CtrlCode, TESTS        ; To fulfill testing
        JMP  w_tests          ; Operates without testing

; UART interrupt handler: read byte from UART buffer
;                         and write it to the user program memory (from 2000h)
UAPP_M: PUSH  ACC
        PUSH  PSW
        MOV   A, SBUF            ; Read byte from UART
        MOVX  @DPTR,A            ; Write byte to external memory
        INC   DPTR               ; Next address of external memory
        MOV   R1,A
        MOV   R0, #Low (SSI_0)
        ANL   A,#zero_mask
        CALL  SSI_1pR0                 ; Display received data on SSI
        MOV   A,R1
        SWAP  A
        ANL   A,#zero_mask
        MOV   R0, #Low(SSI_1)
        CALL  SSI_1pR0
        POP   PSW
        POP   ACC
        CLR   RI
        RETI

; Checking the first loop (after power on and starting the system)
TESTS:          MOV  R0,#CtrlByteAddr ; Set control code after starting the system
          MOV  @R0,#CtrlCode

; Testing LEDs and SSI

          MOV  A,#SCode    ; testing "minus" (ON/OFF)
          SETB ACC.7
          MOV  R0,#Low(LCD)
          MOVX @R0,A
          MOV  R2,#4
          CALL DELAY01r
          CLR  ACC.7
          MOVX @R0,A

          MOV  R0,#Low(LED)
          MOV  R7,#4
          MOV  A,#11110000B
LED_4:    MOVX @R0,A                  ; LEDs on and off four times by four bits
          MOV  R2,#4
          CALL DELAY01r
          SWAP A
          DJNZ R7,LED_4
          CLR  A
          MOVX @R0,A

          MOV  R5,#4
SSI_4:    MOV  R0,#Low(-8888)        ; SSI display (-8888) and off four times
          MOV  R1,#High(-8888)
          CALL SSI_WI
          MOV  R2,#4
          CALL DELAY01r
          CALL SSI_OFF
          MOV  R2,#4
          CALL DELAY01r
          DJNZ R5,SSI_4

w_tests:
          MOV  R0,#Low(LCD)
          MOV  A,#SCode          ; OFF "minus"
          MOVX @R0,A

          MOV  DPTR, #UserPrg    ; Load start adress of user program location to DPTR

; Wait loop for UART interrupt or for starting user program
; running light on LEDs line
          MOV  A,  #10000000b
WAIT_UP:  MOV  R0, #Low(LED)
          MOVX @R0,A            ;
          MOV  R2, #04                ; Delay for 0.4 s
          CALL DELAY01r
          RL   A
          JB   M_UP, WAIT_UP    ; Loop - up to M/UP is unactive (i.e. in "Monitor")

; Delay before starting user program on 4 s
; ON/OFF all LEDs 4 times
          MOV  R5, #8                ;   8 * 0.4 s = 3.2 s
          MOV  A, #11111111b
          MOV  R0, #Low(LED)
W_Start:  MOVX @R0,A            ; Dislplay 11111111 / 00000000 on LEDs
          MOV  R2, #4
          CALL DELAY01r         ; Delay for 0.4 s
          CPL  A
          DJNZ R5, W_Start
          CALL SSI_OFF                ; Turn off all SSI
          CLR  TR1              ; Stop clocking for UART
          SETB UP_ACT           ; Set the activity flag of user program
          SETB RS0                ; Register bank 1 will be active now
          CLR  RS1
          JMP  UserPrg          ; User program starts up!!!


;==============================================
org 0200h

; Delay the progam execution on 0.1s (R3, R4 used)
DELAY01s:
        MOV   R3,#179
        MOV   R4,#0
z01s:        DJNZ  R4,z01s
        DJNZ  R3,z01s
        RET

org 0210h
; Delay the program execution on (R2 * 0.1s) (R2, R3, R4 used)
DELAY01r:
        MOV   R3,#179
        MOV   R4,#0
z01r:        DJNZ  R4,z01r
        DJNZ  R3,z01r
        DJNZ  R2,z01r
        RET

org 0220h
; Delay the program  execution on 1.005s (R2, R3, R4 used)
DELAY1s:
         MOV   R2,#7
         MOV   R3,#0
         MOV   R4,#0
Z1s:         DJNZ  R4,Z1s
         DJNZ  R3,Z1s
         DJNZ  R2,Z1s
         RET

ORG 0230h
; Delay the program  execution on 0.05s  (R3, R4 only used)
DELAY50ms:
        MOV   R3,#89
        MOV   R4,#0
z005s:        DJNZ  R4,z005s
        DJNZ  R3,z005s
        RET

;===============================================
org 0240h

; Procedure forms the 4-positional packed
; BCD number from one-byte binary number
; Initial number value is given through R0
; Result is obtained in R2 and R3 (R2 - low digits)
b210: mov a,r0
      mov b,#10
      div ab
      mov r2,b  ; the 1st number - in R2
      mov b, #10
      div ab
      mov r3,a  ; the 3rd number - in R3
      mov a,b        ; the 2nd number - in ACC
      rl  a
      rl  a
      rl  a
      rl  a
      orl a,r2  ; packing the 1st and 2nd numbers
      mov r2,a
mr:   ret

;====================================================
org 0260h

; Procedure forms 4-positional packed
; BCD number from two-byte binary number
; Initial number value is given through R0 and R1 (R0 - low byte)
; Maximum value - 9999 (in decimal)
; The overflow value is limited by maximum (and F0 will be set to 1)
; Result is obtained in R2 and R3 (R2 - low digits)
w210: mov  r3, #0
      clr  f0
      cjne r1, #High(9999), w_0
      jmp  w_01
w_0:  jc   w_04
      jmp  w_03
w_01: cjne r0, #Low(9999), w_02
w_02: jc   w_04
w_03: mov  r0,#Low(9999)
      mov  r1,#High(9999)
      setb f0
w_04: call div10
      mov  a,r6
      mov  r2,a   ; the 1st number
      mov  a,r1
      jnz  w_1
      cjne r0, #10, w_2
w_2:  jnc   w_1
      mov  a,r0
      mov  r6,a
      mov  r0,#0
      jmp  w_3
w_1:  call div10
w_3:  mov  a,r6
      rl  a
      rl  a
      rl  a
      rl  a
      orl  a,r2   ; packing the 1st and 2nd numbers
      mov  r2,a   ;
      mov  a,r0
      jz   w_r
      cjne a, #10, w_4
w_4:  jnc  w_5
      mov  r3,a
      jmp  w_r
w_5:  call div10
      mov  a,r6
      mov  r3,a   ; the 3rd number
      mov  a,r0   ; the 4th (last) number
      rl  a
      rl  a
      rl  a
      rl  a
      orl  a,r3   ; packing the 3rd and 4th numbers
      mov  r3,a
w_r:  ret

ORG  02E0h

; Procedure divides 2-byte unsigned number by 10
; Using registers:
; (R0, R1) - initial number value X (R0 - low byte)
; (R6, R7) - temporary value (Z)
; Result (R) is obtained in R0 and R1 registers (R0 - low byte)
; Register (B) is used as counter (i)

DIV10:  MOV  R6, #0   ; Z = 0
        MOV  R7, #0
        MOV  A, R0    ; Checking of the nominator
        ORL  A, R1
        JZ   D10_ret
        MOV  B, #16   ; i = 16
D10_1:  CLR  C
        MOV  A, R0    ; Left shift of (X) è (Z)
        RLC  A        ;
        MOV  R0, A
        MOV  A, R1
        RLC  A
        MOV  R1, A
        MOV  A, R6
        RLC  A
        MOV  R6, A
        MOV  A, R7
        RLC  A
        MOV  R7, A
        JNZ  D10_2
        MOV  A, R6
        SUBB A, #10
        JC   D10_3
 D10_2: CLR  C
        MOV  A, R6
        SUBB A, #10
        MOV  R6, A
        MOV  A, R7    ; (Z) = (Z) - 10
        SUBB A, #0
        MOV  R7, A
        MOV  A, R0   ; Form the next bit od result (R)
        SETB ACC.0
        MOV  R0, A
 D10_3: DJNZ B, D10_1
D10_ret:RET

;========================================
; Decoder for SSI (seven-segments indicator)
; Input code is given through ACC ("17 decimal" - turn off the indicator)
; SSI position adress is given through DPTR
; Result code is returned through ACC and displays on SSI

org 0900h
SSI_1p: ADD A,#2
        MOVC A,@A+PC
        MOVX @DPTR,A
        RET
        DB 3FH, 06H, 5BH, 4FH, 66H   ; 0,1,2,3,4
        DB 6DH, 7DH, 07H, 7FH, 6FH   ; 5,6,7,8,9
        DB 77H, 7CH, 39H, 5EH, 79H   ; A,B,C,D,E
        DB 71H, 40H, 00H, 00H, 00H   ; F,-,off,off,off

; SSI position adress is given through R0 (P2 was determined early)
org 0920h
SSI_1pR0: ADD A,#2
        MOVC A,@A+PC
        MOVX @R0,A
        RET
        DB 3FH, 06H, 5BH, 4FH, 66H   ; 0,1,2,3,4
        DB 6DH, 7DH, 07H, 7FH, 6FH   ; 5,6,7,8,9
        DB 77H, 7CH, 39H, 5EH, 79H   ; A,B,C,D,E
        DB 71H, 40H, 00H, 00H, 00H   ; F,-,off,off,off


;========================================
; Display one-byte unsigned number on SSI (seven-segments indicator)
; Input code is given through R0

org 0940h
SSI_B:  CALL B210        ; result in R2 (low) and R3
        MOV  A,#off_code
        MOV  DPTR,#SSI_3
        CALL SSI_1p
        CLR  F0
        MOV  A,R3        ; high digit
        ANL  A,#zero_mask
        JNZ  SB_1
        MOV  A,#off_code
        SETB F0
SB_1:   MOV  DPTR,#SSI_2
        CALL SSI_1p
        MOV  A,R2        ; middle digit
        SWAP A
        ANL  A,#zero_mask
        JNB  F0,SB_2
        JNZ  SB_2
        MOV  A,#off_code
        JMP  SB_21
SB_2:   MOV  A,R2
        SWAP A
        ANL  A,#zero_mask
SB_21:  MOV  DPTR,#SSI_1
        CALL SSI_1p
        MOV  A,R2        ; low digit
        ANL  A,#zero_mask
        MOV  DPTR,#SSI_0
        CALL SSI_1p
         MOV  A,#PlusCode
        MOV  DPTR,#LCD
        MOVX @DPTR,A        ; display sign PLUS
        RET

;========================================
; Display two-byte unsigned number on SSI (seven-segments indicator)
; Input code is given through R0 and R1 (low and high appr.)

org 0990h
SSI_W:  CALL W210
        CLR  F0
        MOV  A,R3        ; high digit
        SWAP A
        ANL  A,#zero_mask
        JNZ  SW_1
        MOV  A,#off_code
        SETB F0
SW_1:        MOV  DPTR,#SSI_3
        CALL SSI_1p
        MOV  A,R3        ; high-middle digit
        ANL  A,#zero_mask
        JNB  F0,SW_21
        JNZ  SW_21
        MOV  A,#off_code
        SETB F0
        JMP  SW_2
SW_21:        CLR  F0
SW_2:        MOV  DPTR,#SSI_2
        CALL SSI_1p
        MOV  A,R2        ; low-middle digit
        SWAP A
        ANL  A,#zero_mask
        JNB  F0,SW_3
        JNZ  SW_3
        MOV  A,#off_code
        JMP  SW_31
SW_3:   MOV  A,R2
        SWAP A
        ANL  A,#zero_mask
SW_31:  MOV  DPTR,#SSI_1
        CALL SSI_1p
        MOV  A,R2        ; low digit
        ANL  A,#zero_mask
        MOV  DPTR,#SSI_0
        CALL SSI_1p
         MOV  A,#PlusCode
        MOV  DPTR,#LCD
        MOVX @DPTR,A        ; display sign PLUS
        RET

;========================================
; Display one-byte signed number on SSI (seven-segments indicator)
; Input code is given by value through R0 and R1
; (R0 - low byte; R1 - high byte with sign)
; The result returns be value through regiters
;

org 09E0h
SSI_BI: MOV  A,R0
        JNB  ACC.7,SBI_1
        CPL  A
        INC  A
        MOV  R0,A
        MOV  A,#MinusCode
        JMP  SBI_2
SBI_1:        MOV  A,#PlusCode
SBI_2:        MOV  DPTR,#LCD
        MOVX @DPTR,A        ; display sign
        CALL SSI_B
        RET

;========================================
; Display two-byte signed number on SSI (seven-segments indicator)
; Input code is given through R0 and R1

org 0A00h
SSI_WI: MOV  A,R1
        JNB  ACC.7,SWI_1
        MOV  A,R0
        CPL  A
        ADD  A,#1
        MOV  R0,A
        MOV  A,R1
        CPL  A
        ADDC A,#0
        MOV  R1,A
        MOV  A,#MinusCode
        JMP  SWI_2
SWI_1:        MOV  A,#PlusCode
SWI_2:        MOV  DPTR,#LCD
        MOVX @DPTR,A        ; display sign
        CALL SSI_W
        RET

;======================================
; Free all SSI and sign LED
ORG 0A20h
SSI_OFF: MOV  A,#off_code
        MOV  DPTR,#SSI_0
        CALL SSI_1p
        INC  DPTR
        MOV  A,#off_code
        CALL SSI_1p
        INC  DPTR
        MOV  A,#off_code
        CALL SSI_1p
        INC  DPTR
        MOV  A,#off_code
        CALL SSI_1p
        MOV  A,#PlusCode
        MOV  DPTR,#LCD
        MOVX @DPTR,A        ; free sign
        RET



