;  ------ uP POWER CONTROLLER ------
;  ------ Processor AT89C2051 24PC ------

;#DEFINE DEBUG		;Debugger on/off
;#DEFINE ASYNCEN		;enables out pin in asynchronous mode
;#DEFINE UNLIMOUT		;unlimited out pulse length (else 4 MS)

#INCLUDE "LIBREG.ASM"	;8051 SFR set
#INCLUDE "LIBMAC.ASM"	;macros set

CLK_KHZ	= 12000		;OSC frequency, KHZ
RTC_MS	= 22		;initial mains pulse wait time, MS
#INCLUDE "LIBRTC.ASM"	;calculate RTCV
INTV	.EQU RTCV		;INTV <- RTCV
RTC_MS	= 4		;indication scan rate, MS
#INCLUDE "LIBRTC.ASM"	;calculate RTCV

#IFDEF DEBUG
#INCLUDE "LIBDEF.ASM"
#ENDIF

;  ------ Constantes ------

STACK	.EQU 056H		;stack location
POW100	.EQU 100		;max. power mode 1
POW10	.EQU 10		;max. power mode 2
KEYDB	.EQU 5		;key debounce delay    (x10mS)
KEYDA	.EQU 70		;key autorepeat delay  (x10mS)
KEYARR	.EQU 15		;autorepeat rate       (x10mS)
KEYFARR	.EQU 15		;fast autorepeat rate  (x10mS)
ARCOUNT	.EQU 10		;autorepeat to fast autorepeat count

;  ------ Debugger variables ------

#IFDEF DEBUG
DBGVA	.EQU STACK-1	;debugger variable address in internal memory
DBGVV	.EQU STACK	;debugger variable value   in internal memory
DBGA	.EQU 0FFH		;debugger address          in external memory
#ENDIF

;  ------ Ports ------

SEG_A	.EQU P1.2		;indicators segment A
SEG_B	.EQU P1.3		;indicators segment B
SEG_C	.EQU P1.4		;indicators segment C
SEG_D	.EQU P1.5		;indicators segment D
SEG_E	.EQU P1.6		;indicators segment E
SEG_F	.EQU P1.7		;indicators segment F
SEG_G	.EQU P3.7		;indicators segment G
SEG_H	.EQU T1		;indicators segment H (1XX)

SCAN0	.EQU TXD		;display scan line 1
SCAN1	.EQU RXD		;display scan line 2
JUMPER	.EQU SEG_H	;jumper

KEY_UP	.EQU INT1		;UP   key
KEY_DN	.EQU T0		;DOWN key

PWM	.EQU INT0		;PWM out

;  ------ Variables ------

;  Bit addressing memory

PRESS	.EQU M_20H.0	;keyboard press bit
SIGN	.EQU 021H		;mains sign
PHASE	.EQU 022H		;PWM phase
POWER	.EQU 023H		;power level
DELTA	.EQU 024H		;PWM_100 internal variable
KEYDBT	.EQU 025H		;key debounce timer
KEYTM	.EQU 026H		;key timer
PREV	.EQU 027H		;previous key code
MAXPOW	.EQU 028H		;max. power value
REPCNT	.EQU 029H		;repeat counter

;  ------ Vectors Area ------

	.ORG 0000H	;reset vector

;  ------ Main Program ------

	MOV SP,#STACK	;stack init
#IFDEF DEBUG
	DEBUGINIT		;debug init
#ENDIF
	MOV MAXPOW,#POW100
	JB JUMPER,M100
	MOV MAXPOW,#POW10
M100:     CLR PRESS		;clear keyboard press bit
	CLR A
	MOV PREV,A
	MOV SIGN,A
	MOV POWER,A
	MOV DPTR,#FONT

	MOV A,MAXPOW
	MOV PHASE,A
	CLR C
	RRC A
	CPL A
	INC A
	MOV DELTA,A

	CLR TR0
	CLR TR1
	CLR TF0
	MOV TMOD,#11H    	;timer 0 and timer 1 init
	MOV TH0,#HI(INTV)	;indication timer load
	MOV TL0,#LO(INTV)
	SETB TR0		;timer start

;======== Comparator out check ========

MAIN:
#IFDEF ASYNCEN
	JB TF0,PWM0	;jump if no mains pulses
#ELSE
	JB TF0,PWM2	;jump if no mains pulses
#ENDIF
	MOV A,P3		;comparator out check
	XRL A,SIGN
	JNB ACC.6,MAIN	;loop if same mains sign

	XRL SIGN,#0FFH	;change sign

;======== PWM out control ========

PWM0:	MOV A,POWER
	ADD A,DELTA
	MOV DELTA,A
	MOV C,ACC.7
	MOV PWM,C
	JC PWM1
	SUBB A,MAXPOW
	MOV DELTA,A
PWM1:     DJNZ PHASE,PWM2
	MOV A,MAXPOW
	MOV PHASE,A
	CLR C
	RRC A
	CPL A
	INC A
	MOV DELTA,A

;======== Indicate 1s ========

PWM2:     CLR TR0
	MOV TH0,#HI(RTCV)	;indication timer load
	MOV TL0,#LO(RTCV)
	CLR  TF0
	SETB TR0		;timer start
	MOV A,POWER
	MOV B,#10
	DIV AB		;A=10s, B=1s
	MOV A,B
	MOVC A,@A+DPTR
	ACALL IND
	SETB SCAN1
	CLR  SCAN0	;indicate 1s

;======== Keyboard check ========

	MOV C,KEY_UP	;keyboard check
	ANL C,KEY_DN
	JC  NP		;jump if no press
	MOV A,#0FFH
	MOV C,KEY_UP
	RLC A
	MOV C,KEY_DN
	RLC A
	CPL A		;ACC.1 - UP, ACC.0 - DN
	MOV R0,A
	XRL A,PREV
	JNZ ND
	MOV A,KEYDBT
	JZ DOV
	DEC KEYDBT
	SJMP W1		;jump if debounce delay is not over
DOV:	CJNE R0,#1,NDN
	ACALL DO_DN	;DOWN pressed
NDN:	CJNE R0,#2,NUP
	ACALL DO_UP	;UP pressed
NUP:	CJNE R0,#3,NUD
	ACALL DO_UD	;UP+DOWN pressed
NUD:	SETB PRESS
	SJMP W1
ND:	MOV PREV,R0
NP:	CLR PRESS
	MOV KEYDBT,#KEYDB	;debounce timer load
W1:	JNB  TF0,$

;======== PWM out off ========

#IFNDEF UNLIMOUT
	SETB PWM		;PWM out off
#ENDIF

;======== Indicate 10s ========

	CLR TR0
	MOV TH0,#HI(RTCV)	;indication timer load
	MOV TL0,#LO(RTCV)
	CLR  TF0
	SETB TR0		;timer start
	MOV A,POWER
	MOV B,#10
	DIV AB		;A=10s, B=1s
	JNZ NZ
	MOV A,#0DH	;blank code
NZ:	MOVC A,@A+DPTR
	ACALL IND
	SETB SCAN0
	CLR  SCAN1	;indicate 10s

;======== Program timer check ========

	MOV A,KEYTM
	JZ W2
	DEC KEYTM		;advance key timer
W2:	JNB  TF0,$

;======== Indication off ========

	CLR TR0
	MOV TH0,#HI(RTCV)	;indication timer load
	MOV TL0,#LO(RTCV)
	CLR  TF0
	SETB TR0		;timer start
	SETB SCAN0
	SETB SCAN1	;indication off
	AJMP MAIN		;main loop

;  ------ Subroutines Area ------

;UP key processing:

DO_UP:    JB PRESS,UPH	;jump if key hold
	MOV KEYTM,#KEYDA	;first press, autorepeat delay load
	MOV REPCNT,#0	;autorepeat counter clear
	SJMP UP_DO
UPH:	MOV A,KEYTM	;KEYTM check
	JNZ UP_RET
	CLR C
	MOV KEYTM,#KEYARR	;load normal repeat rate
	MOV A,REPCNT
	SUBB A,#ARCOUNT	;REPCNT check
	JC UP_DO		;jump if REPCNT < ARCOUNT
	MOV KEYTM,#KEYFARR	;load fast repeat rate
UP_DO:	MOV A,POWER
	XRL A,MAXPOW
	JZ UP_RET		;jump if limit
	INC POWER		;power inc.
	INC REPCNT	;autorepeat counter inc.
UP_RET:   RET

;DOWN key processing:

DO_DN:    JB PRESS,DNH	;jump if key hold
	MOV KEYTM,#KEYDA	;first press, autorepeat delay load
	MOV REPCNT,#0	;autorepeat counter clear
	SJMP DN_DO
DNH:	MOV A,KEYTM	;KEYTM check
	JNZ DN_RET
	CLR C
	MOV KEYTM,#KEYARR	;load normal repeat rate
	MOV A,REPCNT
	SUBB A,#ARCOUNT	;REPCNT check
	JC DN_DO		;jump if REPCNT < ARCOUNT
	MOV KEYTM,#KEYFARR	;load fast repeat rate
DN_DO:    MOV A,POWER
	JZ DN_RET		;jump if limit
	DEC POWER		;power dec.
	INC REPCNT	;autorepeat counter inc.
DN_RET:   RET

;UP+DOWN key processing:

DO_UD:	JB PRESS,UD_RET	;no hold mode
	MOV A,POWER
	JZ DO_MAX
	MOV POWER,#0	;load MIN power
	SJMP UD_RET
DO_MAX:	MOV POWER,MAXPOW	;load MAX power
UD_RET:   RET

;Segments on/off
;Input: A - segments copy, ACC.0 - A, ACC.1 - B, ...

IND:	RRC A
	MOV SEG_A,C
	RRC A
	MOV SEG_B,C
	RRC A
	MOV SEG_C,C
	RRC A
	MOV SEG_D,C
	RRC A
	MOV SEG_E,C
	RRC A
	MOV SEG_F,C
	RRC A
	MOV SEG_G,C
	RRC A
	MOV SEG_H,C
	RET

;Font table
;	    SGFEDCBA
FONT	.DB 11000000B	;code 00H, character 0
	.DB 11111001B	;code 01H, character 1
	.DB 10100100B	;code 02H, character 2
	.DB 10110000B	;code 03H, character 3
	.DB 10011001B	;code 04H, character 4
	.DB 10010010B	;code 05H, character 5
	.DB 10000010B	;code 06H, character 6
	.DB 11111000B	;code 07H, character 7
	.DB 10000000B	;code 08H, character 8
	.DB 10010000B	;code 09H, character 9
	.DB 01000000B	;code 0AH, character 10
	.DB 01111001B	;code 0BH, character 11
	.DB 00100100B	;code 0CH, character 12
	.DB 11111111B	;code 0DH, character blank

#IFDEF DEBUG
#INCLUDE "LIBDBG.ASM"
#ENDIF
	.END
