;  ------ Digital Thermometer ------
;  ------ Processor AT89C2051 24PC ------
;  ------ Supports Dallas DS1820 and DS1821 Thermometers ------

#DEFINE Z_SUP		;Zero suppression

#INCLUDE "LIBREG.ASM"	;8051 SFR set

#DEFINE LO(XXX) XXX & 0FFH
#DEFINE HI(XXX) (XXX >> 8) & 0FFH

CLK_KHZ	= 10000		;OSC frequency, KHZ
RTC_MS	= 20		;System clock , MS
RTCV	= CLK_KHZ*RTC_MS
RTCV	= RTCV/12
RTCV	= - RTCV
RTCV	= RTCV & 0FFFFH

;  ------ Constantes ------

STACK	.EQU 056H		;stack location
V100MS	.EQU 5		;program timer RTPCS value 100mS/20mS=5
I2C_ADDR	.EQU 0A0H		;I2C address for PCF8582 (A0,A1,A2=0)
SMPTMV	.EQU 5		;x20mS thermometers sample timer value
INKTMV	.EQU 35		;x20mS initial key repeat timer value
KEYTMV	.EQU 5		;x20mS key repeat timer value
BRKTMV	.EQU 2		;x20mS brightness key repeat timer value
BLBTMV	.EQU 50		;x20mS blink begin delay timer value
SAVTMV	.EQU 200		;x20mS NVM save delay timer value
TMOV20	.EQU 25		;x20mS timeout value for DS1820
TMOV21	.EQU 100		;x20mS timeout value for DS1821
INDTMV	.EQU 50		;x20mS indication mode 2,4 delay value
OFFTMV	.EQU 50		;x100mS off delay value
MIN_RT	.EQU 5		;x100mS min auto change rate
SKEW	.EQU 20		;brightness control skew
PWM_MAX	.EQU 230		;MAX PWM value
L_MAX	.EQU 09AH		;MAX on and off limit
L_MIN	.EQU 001H		;MIN on and off limit
SHIFT	.EQU 037H		;unsigned limit - shift = signed limit

;  ------ Ports ------

SCAN0	.EQU P3.0		;display scan line 0
SCAN1	.EQU P3.1		;display scan line 1
SCAN2	.EQU P3.5		;display scan line 2

SDA	.EQU SCAN0	;I2C SDA line
SCL	.EQU SCAN1	;I2C SCL line

OWP1	.EQU P3.2		;1-Wire Port 1 (EXT. THERMOMETER)
OWP2	.EQU P3.7		;1-Wire Port 2 (INT. THERMOMETER)

RETL	.EQU P3.4		;keyboard return line
CNTRL	.EQU P3.3		;thermostat control line

;  ------ Variables ------

;R10 used for temporary save of ONLIM and OFLIM (in PROG)
;R11 used for temporary save of DIG1 (in TCONV20, TCONV21)
;R12 used for temporary save of DIG2 (in TCONV20, TCONV21)
;R13 used for temporary save of DIG3 (in TCONV20, TCONV21)
;R14 used for temporary save of OFLIM (in PROG)

PWVH	.EQU R20		;PWM timer value (off state) high
PWVL	.EQU R21		;PWM timer value (off state) low
PHVH	.EQU R22		;PWM timer value (on state) high
PHVL	.EQU R23		;PWM timer value (on state) low
PHASE	.EQU R24		;display scan phase
INCODE	.EQU R25		;keyboard internal scan-code

;  Bit addressing memory

RTPC	.EQU 020H		;Real time program counter
T040M	.EQU M_20H.0	;40mS  period bit
T080M	.EQU M_20H.1	;80mS  period bit
T160M	.EQU M_20H.2	;160mS period bit
T320M	.EQU M_20H.3	;320mS period bit
T640M	.EQU M_20H.4	;640mS period bit
T1S28	.EQU M_20H.5	;1.28S period bit
T2S56	.EQU M_20H.6	;2.56S period bit
T5S12	.EQU M_20H.7	;5.12S period bit

RTPCS	.EQU 021H		;Real time program counter (100mS part)

SEL_EXT	.EQU M_22H.0	;select OWP1 bit (external)
MINUS	.EQU M_22H.1	;minus bit (used in TCONV20, TCONV21)
PRESS	.EQU M_22H.2	;keyboard press bit
BLINK	.EQU M_22H.3	;display blink bit
FEN	.EQU M_22H.4	;ACHR fill enable bit
LEVEL	.EQU M_22H.5	;thermostat active level

NOTSV	.EQU 023H		;not saved in NVM params flags byte
NSV_BR	.EQU M_23H.0	;not saved in NVM brightness bit
NSV_ON	.EQU M_23H.1	;not saved in NVM on limit bit
NSV_OF	.EQU M_23H.2	;not saved in NVM off limit bit
NSV_IM	.EQU M_23H.3	;not saved in NVM indication mode bit
NSV_RT	.EQU M_23H.4	;not saved in NVM auto change rate bit

PARAMS	.EQU PWM		;array address (Array 024H..028H)

PWM	.EQU 024H		;PWM duty cycle value (1..230)
ONLIM	.EQU 025H		;thermostat on  limit (unsigned 0-9AH)
OFLIM	.EQU 026H		;thermostat off limit (unsigned 0-9AH)

INDMD	.EQU 027H		;ind. mode (0-EXT, 1-INT, etc.)
IND_INT	.EQU M_27H.0	;EXT/INT indication (0/1)
IND_SET	.EQU M_27H.1	;indication/set (0/1)
IND_TH1	.EQU M_27H.2	;th1 indication (1)
IND_ONL	.EQU M_27H.3	;on limit indication (1)
IND_TH0	.EQU M_27H.4	;th0 indication (1)
IND_OFL	.EQU M_27H.5	;off limit indication (1)

ACHR	.EQU 028H		;auto change EXT/INT rate

;  Internal data memory

CD1	.EQU 030H		;display digit 1 (segments copy)
CD2	.EQU 031H		;display digit 2 (segments copy)
CD3	.EQU 032H		;display digit 3 (segments copy)

DIG1	.EQU 033H		;display digit 1 (bit 7 - minus seg)
DIG2	.EQU 034H		;display digit 2 (bit 7 - point seg)
DIG3	.EQU 035H		;display digit 3 (bit 7 - LED EXT seg)

D1_EXT	.EQU 036H		;EXT temperature digit 1
D2_EXT	.EQU 037H		;EXT temperature digit 2
D3_EXT	.EQU 038H		;EXT temperature digit 3

D1_INT	.EQU 039H		;INT temperature digit 1
D2_INT	.EQU 03AH		;INT temperature digit 2
D3_INT	.EQU 03BH		;INT temperature digit 3

EXT_TH	.EQU 03CH	;EXT thermometer type (00H-none, 20H-DS1820, 21H-DS1821)
INT_TH	.EQU 03DH	;INT thermometer type (00H-none, 20H-DS1820, 21H-DS1821)

EXT_T	.EQU 03EH		;binary unsigned EXT temperature

TMO_EXT	.EQU 042H		;EXT thermometer ready timeout timer
TMO_INT	.EQU 043H		;INT thermometer ready timeout timer
SMPTM	.EQU 044H		;thermometer sample timer
KEYTM	.EQU 045H		;key repeat timer
SAVTM	.EQU 046H		;NVM save delay timer
DELTM	.EQU 047H		;delay timer
ACHTM	.EQU 048H		;auto change timer
OFFTM	.EQU 049H		;off timer

;  ------ Vectors Area ------

	.ORG 0000H	;reset vector
	AJMP INIT
	.ORG 000BH	;INT TIMER 0 vector
	AJMP RTC
	.ORG 001BH	;INT TIMER 1 vector
	AJMP INDSCAN

;  ------ Main Program ------

INIT:	MOV SP,#STACK	;stack init
	CLR BLINK		;clear display blink bit
	CLR FEN		;fill enable bit clear
	CLR A
	MOV KEYTM,A	;clear key repeat timer
	MOV EXT_TH,A	;no EXT thermometer
	MOV INT_TH,A	;no INT thermometer
	MOV NOTSV,A	;NVM not save flags clear
	MOV OFFTM,#OFFTMV	;off timer load
	ACALL NVMREAD	;PWM, ONLIM, OFLIM, INDMD, ACHR init
	ACALL GETPWM	;get PWM timer values
	ACALL DISP	;CD1-CD3 init
	MOV ACHTM,ACHR

	MOV TMOD,#11H    	;timer 0 and timer 1 init
	MOV TL0,#LO(RTCV)  	;timer 0 load
	MOV TH0,#HI(RTCV)
	MOV TL1,PHVL   	;timer 1 load
	MOV TH1,PHVH
	MOV RTPCS,#V100MS  	;100mS value load
	MOV TCON,#50H	;timer 0 and timer 1 start

	SETB PT1          	;int timer 1 hi, timer 0 low priority
	MOV IE,#8AH	;timer 0, timer 1 int enable (ET0,ET1,EA=1)

	ACALL AD_EXT	;auto detect and start external thermometer
	ACALL AD_INT	;auto detect and start internal thermometer

	MOV SMPTM,#SMPTMV   ;thermometers sample timer load

MAIN:	MOV A,INCODE	;local keyboard test
	CPL A
	JNZ MA10		;jump if press
	CLR FEN
	CLR PRESS
	SJMP MA20		;jump if no press

MA10:	MOV B,A		;save keyboard code
	ACALL DEL10	;debounce delay
	MOV A,INCODE	;read keyboard code
	CPL A
	CJNE A,B,MA20	;no press if codes are differ
	MOV R7,A
	MOV OFFTM,#OFFTMV	;off timer load

	JB PRESS,SAME

;Control Functions Analysis and Processing

DIF:	CJNE R7,#KEY_SL,$+5H	;KEY SELECT
	ACALL SEL
	CJNE R7,#KEY_EX,$+5H	;KEY EXT/INT
	ACALL EXT

SAME:	CJNE R7,#KEY_UP,$+5H	;KEY UP
	ACALL UP
	CJNE R7,#KEY_DN,$+5H	;KEY DOWN
	ACALL DN
	CJNE R7,#KEY_UD,$+5H	;KEY UP+DOWN
	ACALL UPDN

	SETB PRESS		;set PRESS

;End of Control Functions Analysis

MA20:	MOV A,SMPTM	;check sample timer
	JNZ MA24		;jump if no timer overflow
	MOV SMPTM,#SMPTMV   ;timer reload

	ACALL CH_EXT	;check EXT thermometer
	JNZ MA21		;jump if ready
	MOV A,TMO_EXT	;check timeout
	JNZ MA22
	SJMP MA23		;timeout is over, go to auto detect

MA21:	ACALL RD_EXT	;read EXT thermometer
	ACALL LIM_CHK	;thermostat control
MA23:	ACALL AD_EXT	;auto detect and start

MA22: 	ACALL CH_INT	;check INT thermometer
	JNZ MA25		;jump if ready
	MOV A,TMO_INT	;check timeout
	JNZ MA24
	SJMP MA26		;timeout is over, go to auto detect

MA25:    	ACALL RD_INT	;read INT thermometer
MA26:    	ACALL AD_INT	;auto detect and start

MA24:	JB IND_SET,MA33	;jump if set mode
	MOV A,ACHR
	CLR C
	SUBB A,#MIN_RT
	JC MA40		;jump if ACHR<MIN_RT
	MOV A,ACHTM
	JNZ MA40
	MOV ACHTM,ACHR	;auto change timer reload
	CPL IND_INT
	SJMP MA40

MA33:	MOV A,DELTM	;DELTM check
	JNZ MA40		;jump if no timer overflow
	JBC IND_TH1,MA30	;jump if th1 indication mode
	JBC IND_TH0,MA31	;jump if th0 indication mode

	SETB BLINK	;set display blink mode
	SJMP MA40

MA30:	SETB IND_ONL	;set on  limit indication mode
	SJMP MA32
MA31:	SETB IND_OFL	;set off limit indication mode
MA32:	MOV DELTM,#BLBTMV	;load blink begin delay

MA40:	MOV A,SAVTM
	JNZ MA100		;jump if no save timer overflow
	MOV A,NOTSV
	JZ MA50		;skip save if all params are saved
	ACALL SAVE
	SJMP MA100

MA50:	MOV A,OFFTM
	JNZ MA100
	MOV OFFTM,#OFFTMV	;off timer load
	CLR RETL		;50mS off pulse generating
	ACALL DEL50
	SETB RETL

MA100:    ACALL DISP	;CD1-CD3 load
	AJMP MAIN

;  ------ Subroutines Area ------

;Up key processing

UP:       JNB IND_SET,UP_PWM
	JB IND_ONL,UP_ON
	JB IND_OFL,UP_OF
EUD_PWM:	RET

UP_PWM:   MOV A,KEYTM
	JNZ EUD_PWM
	MOV A,PWM
	MOV B,#SKEW
	DIV AB
	INC A
	ADD A,PWM
	JC UP_OVFL
	CJNE A,#PWM_MAX,$+3H
	JNC UP_OVFL
	MOV PWM,A
	SJMP END_PWM
UP_OVFL:	MOV PWM,#PWM_MAX
	SJMP END_PWM

UP_ON:	JB PRESS,UP_ONS
	MOV KEYTM,#INKTMV
	SJMP UP_ON2
UP_ONS:   MOV A,KEYTM
	JNZ END_UDS	;end up/down function
	MOV KEYTM,#KEYTMV
UP_ON2:	MOV A,ONLIM
	CJNE A,#L_MAX,$+3H
	JNC END_UDS	;end up/down function
	INC ONLIM
	SJMP END_UDSN	;end up/down function and save ONLIM in NVM

UP_OF:	JB PRESS,UP_OFS
	MOV KEYTM,#INKTMV
	SJMP UP_OF2
UP_OFS:   MOV A,KEYTM
	JNZ END_UDS	;end up/down function
	MOV KEYTM,#KEYTMV
UP_OF2:	MOV A,OFLIM
	CJNE A,#L_MAX,$+3H
	JNC END_UDS	;end up/down function
	INC OFLIM
	SJMP END_UDSF	;end up/down function and save OFLIM in NVM

;Down key processing

DN:       JNB IND_SET,DN_PWM
	JB IND_ONL,DN_ON
	JB IND_OFL,DN_OF
EDD_PWM:	RET

DN_PWM:	MOV A,KEYTM
	JNZ EDD_PWM
	MOV A,PWM
	MOV B,#SKEW
	DIV AB
	INC A
	XCH A,PWM
	CLR C
	SUBB A,PWM
	JC DN_OVFL
	CJNE A,#2,$+3H
	JC DN_OVFL
	MOV PWM,A
	SJMP END_PWM
DN_OVFL:	MOV PWM,#2H
END_PWM:	MOV KEYTM,#BRKTMV
	MOV SAVTM,#SAVTMV
	SETB NSV_BR
	ACALL GETPWM	;get timer load values
	RET

END_UDSN:	SETB NSV_ON
	SJMP END_UDS
END_UDSF:	SETB NSV_OF
END_UDS:	MOV SAVTM,#SAVTMV
	CLR BLINK
	MOV DELTM,#BLBTMV
	RET

DN_ON:	JB PRESS,DN_ONS
	MOV KEYTM,#INKTMV
	SJMP DN_ON2
DN_ONS:   MOV A,KEYTM
	JNZ END_UDS	;end up/down function
	MOV KEYTM,#KEYTMV
DN_ON2:	MOV A,ONLIM
	CJNE A,#L_MIN,$+3H
	JC END_UDS	;end up/down function
	DEC ONLIM
	SJMP END_UDSN	;end up/down function and save ONLIM in NVM

DN_OF:	JB PRESS,DN_OFS
	MOV KEYTM,#INKTMV
	SJMP DN_OF2
DN_OFS:   MOV A,KEYTM
	JNZ END_UDS	;end up/down function
	MOV KEYTM,#KEYTMV
DN_OF2:	MOV A,OFLIM
	CJNE A,#L_MIN,$+3H
	JC END_UDS	;end up/down function
	DEC OFLIM
	SJMP END_UDSF	;end up/down function and save OFLIM in NVM

;Up+down key processing

UPDN:     JNB IND_SET,UPDN_PWM
	JB IND_ONL,UPDN_ON
	JB IND_OFL,UPDN_OF
	JB IND_TH1,PROG
	JB IND_TH0,PROG
	RET

UPDN_ON:	MOV ONLIM,#SHIFT	;load ONLIM = 0 'C
	MOV KEYTM,#INKTMV
	SJMP END_UDSN	;end up/down function and save ONLIM in NVM

UPDN_OF:	MOV OFLIM,#SHIFT	;load OFLIM = 0 'C
	MOV KEYTM,#INKTMV
	SJMP END_UDSF	;end up/down function and save OFLIM in NVM

UPDN_PWM:	MOV PWM,#PWM_MAX	;load MAX brightness
	SJMP END_PWM

;Thermostat programming support
;Sets DS1821 to thermostat mode if ONLIM<>OFLIM
;Sets DS1821 to read mode if ONLIM=OFLIM
;Input: ONLIM, OFLIM, bit LEVEL

PROG:	CLR CNTRL		;VDD on
	SETB OWP1
	MOV DIG1,#CH_P
	MOV DIG2,#CH_r
	MOV DIG3,#BLANK
	ACALL IND1
	MOV A,#(~KEY_SL)
	CJNE A,INCODE,$

	ACALL TRESET1	;Issue reset pulse.
	JC TH_PRG		;jump if no error (read mode)

	SETB CNTRL	;VDD off
	CLR EA
	MOV P1,#0FFH	;indication off
	MOV R0,#16
TOG1:	CLR OWP1
	INC DPTR		;delay
	SETB OWP1
	DJNZ R0,TOG1
	CLR CNTRL		;VDD on

	ACALL DEL10

TH_PRG:	MOV A,OFLIM
	CJNE A,ONLIM,PRG1

	MOV R1,#0CH	;Write command register
	CLR A		;ONLIM=OFLIM, return device to read mode
	ACALL COMM

	MOV DIG1,#CH_r
	MOV DIG2,#CH_d
	SJMP PRG2

PRG1:     MOV R14,ONLIM
	JNC ONH		;jump if ONLIM>OFLIM (C=0)
	XCH A,R14
ONH:      MOV LEVEL,C
	CLR C
	SUBB A,#SHIFT
	MOV R10,A
	MOV R1,#01H	;Write TH command
	ACALL COMM

	MOV R1,#0A1H	;Read TH command
	MOV A,#0FFH
	ACALL COMM
	CJNE A,R10,PR_ER

	MOV A,R14
	SUBB A,#SHIFT
	MOV R10,A
	MOV R1,#02H	;Write TL command
	ACALL COMM

	MOV R1,#0A2H	;Read TL command
	MOV A,#0FFH
	ACALL COMM
	CJNE A,R10,PR_ER

	MOV R1,#0CH	;Write command register.
	MOV A,#04H	;Thermostat mode
	MOV C,LEVEL
	MOV ACC.1,C
	ACALL COMM

PR_TH:	MOV DIG1,#CH_t
	MOV DIG2,#CH_h

PRG2:     ACALL DEL50
	ACALL IND1
	SETB CNTRL	;VDD off
	MOV A,#(~KEY_UD)
	CJNE A,INCODE,$
	MOV OFFTM,#OFFTMV	;off timer load
	AJMP EXTR

RT_ER:	DEC SP
	DEC SP
PR_ER:	MOV DIG1,#CH_E
	MOV DIG2,#CH_r
	MOV DIG3,#CH_r
	SJMP PRG2

;Perform write/read command to DS1821 at OWP1
;Input: R1 - command (01H - write TH, 02H - write TL
;                 A1H - read  TH, A2H - read  TL
;                     0CH - write command register)
;       A - byte (= 0FFH for read)
;Out:   A (if read operation)

COMM:	ACALL TRESET1	;Issue reset pulse.
	JNC RT_ER		;Fail if no part on bus.
COMM_N:	MOV R2,A
	MOV A,R1		;Command.
	ACALL TOUCHBY1	;Send command byte.
	MOV A,R2
	ACALL TOUCHBY1	;Send command byte.
	SETB C
	RET

;Select key processing

SEL:      JB IND_SET,SEL1
	SETB IND_SET	;EXT/INT indication mode, SET=1
	SETB IND_TH1	;TH1=1
	SJMP SEL10
SEL1:	JBC IND_TH1,SEL2
	JBC IND_ONL,SEL2
	CLR IND_TH0
	CLR IND_OFL
	CLR IND_SET
	MOV KEYTM,#0H
	SJMP SEL11
SEL2:	SETB IND_TH0
SEL10:	MOV DELTM,#INDTMV
SEL11:	CLR BLINK
	MOV SAVTM,#SAVTMV
	RET

;External/Internal key processing

EXT:      CPL IND_INT
	MOV ACHR,#0H
	SETB FEN
	SETB NSV_IM
	SETB NSV_RT
EXTR:	ANL INDMD,#1H
	SJMP SEL11

;  ------ 1-Wire Dallas Interface Support ------

#DEFINE CLK_10MHZ
#DEFINE INT_DIS

;
;  Uses CLK_8MHZ, CLK_10MHZ, CLK_11MHZ or CLK_12MHZ
;  Uses INT_DIS for interrupts disable in time slots
;
;  Main program must define:
;
;  Dallas 1-Wire Port as OWP1
;
;  This library includes:
;
;  TRESET1  - Reset pulse generation for port #1
;  TOUCHBY1 - Read/write byte via port #1
;
;  TRESET1:
;  This procedure transmits the Reset signal to the 1-Wire
;  device and watches for a presence pulse. On return,
;  the Carry bit is set if a presence pulse was detected,
;  otherwise the Carry is cleared. The code is timed for
;  an 8, 10, 11.059 and 12 MHz crystal.
;
;  TOUCHBY1:
;  This procedure sends the byte in the accumulator
;  to the 1-Wire device, and returns a byte from the
;  1-Wire device in the accumulator. For reading
;  operation set accumulator to 0FFH. The code is
;  timed for an 8, 10, 11.059 and 12 MHz crystal.

;  ------ TRESET1 ------

TRESET1:	CLR  OWP1      		;Start the reset pulse.
#IFDEF CLK_8MHZ  \ MOV B,#160 \ #ENDIF	;  2.  Set time interval.
#IFDEF CLK_10MHZ \ MOV B,#200 \ #ENDIF	;  2.  Set time interval.
#IFDEF CLK_11MHZ \ MOV B,#221 \ #ENDIF	;  2.  Set time interval.
#IFDEF CLK_12MHZ \ MOV B,#240 \ #ENDIF	;  2.  Set time interval.
	DJNZ B,$         		;320. 400. 442. 480. Wait with Data low.
#IFDEF INT_DIS \ CLR EA \ #ENDIF	; Interrupt disable if needed
	SETB OWP1       		;  1.  Release Data line.
#IFDEF CLK_8MHZ  \ MOV B,#80  \ #ENDIF	;High wait delay.
#IFDEF CLK_10MHZ \ MOV B,#101 \ #ENDIF	;High wait delay.
#IFDEF CLK_11MHZ \ MOV B,#111 \ #ENDIF	;High wait delay.
#IFDEF CLK_12MHZ \ MOV B,#120 \ #ENDIF	;High wait delay.
	CLR  C           		;  1.  Clear presence flag.
WAITL1:	JB OWP1,WH1    		;Exit loop if line high.
	DJNZ B,WAITL1   		;Hang around if line is low.
#IFDEF INT_DIS \ SETB EA \ #ENDIF	; Interrupt enable if needed
	SJMP SHORT1       		;Line could not go high.
WH1:
#IFDEF INT_DIS \ SETB EA \ #ENDIF	; Interrupt enable if needed
#IFDEF CLK_8MHZ  \ MOV B,#80  \ #ENDIF	;Delay for presence detect.
#IFDEF CLK_10MHZ \ MOV B,#101 \ #ENDIF	;Delay for presence detect.
#IFDEF CLK_11MHZ \ MOV B,#111 \ #ENDIF	;Delay for presence detect.
#IFDEF CLK_12MHZ \ MOV B,#120 \ #ENDIF	;Delay for presence detect.
HL1:	ORL  C,/OWP1    		;160. 202. 222. 240. Catch presence pulse.
	DJNZ B,HL1        		;160. 202. 222. 240. Wait with Data high.
SHORT1:	RET              		;Return.

;  ------ TOUCHBY1 ------

TOUCHBY1:	PUSH B           		;Save the B register.
	MOV  B,#8        		;Setup for 8 bits.
B_LOOP1:	RRC  A           		;1. Get bit in carry.
	LCALL TOUCHB1   		;2. Send bit.
	DJNZ B,B_LOOP1  		;2. Get next bit.
	RRC  A           		;   Get final bit in ACC.
	POP  B           		;Restore B register.
	RET              		;Return to caller.

TOUCHB1:
#IFDEF INT_DIS \ CLR EA \ #ENDIF	; Interrupt disable if needed
	CLR OWP1       		; 1.  Start the time slot.
	NOP              		; 1.  Delay to make sure
	NOP              		; 1.    that the Touch Memory
	NOP              		; 1.      sees a low for at
	NOP              		; 1.        least 1 microsecond.
	MOV OWP1,C    		; 2.  Send out the data bit.
	NOP              		; 1.  Delay to give the
	NOP              		; 1.    data returned from
	NOP              		; 1.      the Touch Memory
	NOP              		; 1.        time to settle
	NOP              		; 1.          before reading
	NOP              		; 1.            the bit.
	MOV  C,OWP1     		; 1.  Sample input data bit.
#IFDEF INT_DIS \ SETB EA \ #ENDIF	; Interrupt enable if needed
	PUSH B           		; 2.  Save B register.
#IFDEF CLK_8MHZ  \ MOV B,#13 \ #ENDIF	; 2.  Delay until the end
#IFDEF CLK_10MHZ \ MOV B,#16 \ #ENDIF	; 2.  Delay until the end
#IFDEF CLK_11MHZ \ MOV B,#18 \ #ENDIF	; 2.  Delay until the end
#IFDEF CLK_12MHZ \ MOV B,#20 \ #ENDIF	; 2.  Delay until the end
	DJNZ B,$         		;26. 32. 36. 40. of the time slot.
	POP  B           		;Restore B register.
	SETB OWP1       		;Terminate time slot.
	RET              		;Return to caller.

;
;  Uses CLK_8MHZ, CLK_10MHZ, CLK_11MHZ or CLK_12MHZ
;  Uses INT_DIS for interrupts disable in time slots
;
;  Main program must define:
;
;  Dallas 1-Wire Port as OWP2
;
;  This library includes:
;
;  TRESET2  - Reset pulse generation for port #2
;  TOUCHBY2 - Read/write byte via port #2
;
;  TRESET2:
;  This procedure transmits the Reset signal to the 1-Wire
;  device and watches for a presence pulse. On return,
;  the Carry bit is set if a presence pulse was detected,
;  otherwise the Carry is cleared. The code is timed for
;  an 8, 10, 11.059 and 12 MHz crystal.
;
;  TOUCHBY2:
;  This procedure sends the byte in the accumulator
;  to the 1-Wire device, and returns a byte from the
;  1-Wire device in the accumulator. For reading
;  operation set accumulator to 0FFH. The code is
;  timed for an 8, 10, 11.059 and 12 MHz crystal.

;  ------ TRESET2 ------

TRESET2:	CLR  OWP2      		;Start the reset pulse.
#IFDEF CLK_8MHZ  \ MOV B,#160 \ #ENDIF	;  2.  Set time interval.
#IFDEF CLK_10MHZ \ MOV B,#200 \ #ENDIF	;  2.  Set time interval.
#IFDEF CLK_11MHZ \ MOV B,#221 \ #ENDIF	;  2.  Set time interval.
#IFDEF CLK_12MHZ \ MOV B,#240 \ #ENDIF	;  2.  Set time interval.
	DJNZ B,$         		;320. 400. 442. 480. Wait with Data low.
#IFDEF INT_DIS \ CLR EA \ #ENDIF	; Interrupt disable if needed
	SETB OWP2       		;  1.  Release Data line.
#IFDEF CLK_8MHZ  \ MOV B,#80  \ #ENDIF	;High wait delay.
#IFDEF CLK_10MHZ \ MOV B,#101 \ #ENDIF	;High wait delay.
#IFDEF CLK_11MHZ \ MOV B,#111 \ #ENDIF	;High wait delay.
#IFDEF CLK_12MHZ \ MOV B,#120 \ #ENDIF	;High wait delay.
	CLR  C           		;  1.  Clear presence flag.
WAITL2:	JB OWP2,WH2    		;Exit loop if line high.
	DJNZ B,WAITL2   		;Hang around if line is low.
#IFDEF INT_DIS \ SETB EA \ #ENDIF	; Interrupt enable if needed
	SJMP SHORT2       		;Line could not go high.
WH2:
#IFDEF INT_DIS \ SETB EA \ #ENDIF	; Interrupt enable if needed
#IFDEF CLK_8MHZ  \ MOV B,#80  \ #ENDIF	;Delay for presence detect.
#IFDEF CLK_10MHZ \ MOV B,#101 \ #ENDIF	;Delay for presence detect.
#IFDEF CLK_11MHZ \ MOV B,#111 \ #ENDIF	;Delay for presence detect.
#IFDEF CLK_12MHZ \ MOV B,#120 \ #ENDIF	;Delay for presence detect.
HL2:	ORL  C,/OWP2    		;160. 202. 222. 240. Catch presence pulse.
	DJNZ B,HL2        		;160. 202. 222. 240. Wait with Data high.
SHORT2:	RET              		;Return.

;  ------ TOUCHBY2 ------

TOUCHBY2:	PUSH B           		;Save the B register.
	MOV  B,#8        		;Setup for 8 bits.
B_LOOP2:	RRC  A           		;1. Get bit in carry.
	LCALL TOUCHB2   		;2. Send bit.
	DJNZ B,B_LOOP2  		;2. Get next bit.
	RRC  A           		;   Get final bit in ACC.
	POP  B           		;Restore B register.
	RET              		;Return to caller.

TOUCHB2:
#IFDEF INT_DIS \ CLR EA \ #ENDIF	; Interrupt disable if needed
	CLR OWP2       		; 1.  Start the time slot.
	NOP              		; 1.  Delay to make sure
	NOP              		; 1.    that the Touch Memory
	NOP              		; 1.      sees a low for at
	NOP              		; 1.        least 1 microsecond.
	MOV OWP2,C    		; 2.  Send out the data bit.
	NOP              		; 1.  Delay to give the
	NOP              		; 1.    data returned from
	NOP              		; 1.      the Touch Memory
	NOP              		; 1.        time to settle
	NOP              		; 1.          before reading
	NOP              		; 1.            the bit.
	MOV  C,OWP2     		; 1.  Sample input data bit.
#IFDEF INT_DIS \ SETB EA \ #ENDIF	; Interrupt enable if needed
	PUSH B           		; 2.  Save B register.
#IFDEF CLK_8MHZ  \ MOV B,#13 \ #ENDIF	; 2.  Delay until the end
#IFDEF CLK_10MHZ \ MOV B,#16 \ #ENDIF	; 2.  Delay until the end
#IFDEF CLK_11MHZ \ MOV B,#18 \ #ENDIF	; 2.  Delay until the end
#IFDEF CLK_12MHZ \ MOV B,#20 \ #ENDIF	; 2.  Delay until the end
	DJNZ B,$         		;26. 32. 36. 40. of the time slot.
	POP  B           		;Restore B register.
	SETB OWP2       		;Terminate time slot.
	RET              		;Return to caller.

;  Common routines:

TRESET:	JNB SEL_EXT,TRESET2
	AJMP TRESET1
TOUCHBY:	JNB SEL_EXT,TOUCHBY2
	AJMP TOUCHBY1

;  Autodetect and start external thermometer
;  Out: EXT_TH = 21H if DS1821 external thermometer is detected
;       EXT_TH = 20H if DS1820 external thermometer is detected
;       EXT_TH = 00H if no external thermometer is detected

AD_EXT:	SETB SEL_EXT
	MOV EXT_TH,#00H
	ACALL TRESET	;Issue reset pulse.
	JNC ADEXT1	;Fail if no part on bus.
	MOV EXT_TH,#21H
	MOV A,#0ACH	;Read DS1821 status command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#0FFH	;Perform read.
	ACALL TOUCHBY	;Read status.
	JB ACC.2,ADEXT2	;Jump if not DS1821 present.
	ACALL START_21
	MOV TMO_EXT,#TMOV21
	RET
ADEXT2:	MOV EXT_TH,#20H
	ACALL START_20
	MOV TMO_EXT,#TMOV20
ADEXT1:	RET

;  Autodetect and start internal thermometer
;  Out: INT_TH = 21H if DS1821 internal thermometer is detected
;       INT_TH = 20H if DS1820 internal thermometer is detected
;       INT_TH = 00H if no internal thermometer is detected

AD_INT:	CLR SEL_EXT
	MOV INT_TH,#00H
	ACALL TRESET	;Issue reset pulse.
	JNC ADINT1	;Fail if no part on bus.
	MOV INT_TH,#21H
	MOV A,#0ACH	;Read DS1821 status command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#0FFH	;Perform read.
	ACALL TOUCHBY	;Read status.
	JB ACC.2,ADINT2	;Jump if not DS1821 present.
	ACALL START_21
	MOV TMO_INT,#TMOV21
	RET
ADINT2:	MOV INT_TH,#20H
	ACALL START_20
	MOV TMO_INT,#TMOV20
ADINT1:	RET

;  Read external thermometer

RD_EXT:	SETB SEL_EXT
	MOV A,EXT_TH
	CJNE A,#20H,REXT1
	ACALL READ_20
	SJMP REXT3
REXT1:	CJNE A,#21H,REXT2
	ACALL READ_21
REXT3:	MOV D1_EXT,R11
	MOV D2_EXT,R12
	MOV D3_EXT,R13
	MOV A,R6
	ADD A,#SHIFT
	MOV EXT_T,A
REXT2:	RET

;  Read internal thermometer

RD_INT:	CLR SEL_EXT
	MOV A,INT_TH
	CJNE A,#20H,RINT1
	ACALL READ_20
	SJMP RINT3
RINT1:	CJNE A,#21H,RINT2
	ACALL READ_21
RINT3:	MOV D1_INT,R11
	MOV D2_INT,R12
	MOV D3_INT,R13
RINT2:	RET

;  Check external thermometer

CH_EXT:	SETB SEL_EXT
	MOV A,EXT_TH
	CJNE A,#20H,CEXT1
	ACALL RDY_20
	RET
CEXT1:	CJNE A,#21H,CEXT2
	ACALL RDY_21
CEXT2:	RET

;  Check internal thermometer

CH_INT:	CLR SEL_EXT
	MOV A,INT_TH
	CJNE A,#20H,CINT1
	ACALL RDY_20
	RET
CINT1:	CJNE A,#21H,CINT2
	ACALL RDY_21
CINT2:	RET

;  ------ 1-Wire thermometer DALLAS DS1820 support ------

;  Start conversion in 1-wire thermometer DS1820.
;  Calls TRESET, TOUCHBY

START_20: ACALL TRESET	;Issue reset pulse.
	JNC STR20           ;Fail if no part on bus.

	MOV A,#0CCH	;Skip ROM command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#044H	;Convert T1 command.
	ACALL TOUCHBY	;Send command byte.

	SETB C
STR20:	RET

;  Check ready 1-wire thermometer DS1820.
;  Returns A=0 when device not ready.
;  Calls TOUCHBY

RDY_20:	MOV A,#0FFH	;Perform read.
	ACALL TOUCHBY	;Read.
	RET

;  Read temperature from 1-wire thermometer DS1820.
;  Returns C=1 in case of valid code, else C=0.
;  Returns D1_EXT,D2_EXT,D3_EXT=BCD temperature value -55.0..99.9
;  Calls TRESET, TOUCHBY

READ_20:  ACALL TRESET	;Issue reset pulse.
	JNC RDR20		;Fail if no part on bus.

	MOV A,#0CCH	;Skip ROM command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#0BEH	;Read scratchpad command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read LSB.
	MOV R2,A		;LSB store
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read MSB.
	MOV R3,A		;MSB store
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read TH.
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read TL.
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read RESERVED BYTE.
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read RESERVED BYTE.
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read COUNT REMAIN.
	MOV R4,A		;COUNT REMAIN store
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read COUNT PER C.
	MOV R5,A		;COUNT PER C store

	ACALL TCONV20
	SETB C
RDR20:	RET

;  Temperature HEX to BCD conversion
;  Truncates T<0
;  Input R3,R2=MSB,LSB of temperature
;  Input R4=COUNT REMAIN
;  Input R5=COUNT PER C
;  Out Dx_INT or Dx_EXT=-55.0-99.9
;  MINUS - bit D1_INT.7

TCONV20:  MOV A,R3		;MSB restore
	RRC A
	MOV MINUS,C

	MOV A,R2		;LSB restore
	MOV C,MINUS
	RRC A
	MOV R6,A
	JNB MINUS,DLC4
	CPL A
	INC A
DLC4:	MOV B,#10
	MUL AB		;B,A=Tx10

	JNB MINUS,DLC6
	XCH A,B
	CPL A
	XCH A,B
	CPL A
	ADD A,#1H
	XCH A,B
	ADDC A,#0H
	XCH A,B

DLC6:	ADD A,#7
	MOV R1,A
	MOV A,B
	ADDC A,#0
	MOV R2,A		;R2,R1=Tx10+7

	MOV A,R5
	MOV B,#10
	DIV AB		;A=COUNT PER C/10

	MOV B,A
	MOV A,R4
	DIV AB		;A=COUNT REMAIN/(COUNT PER C/10)

	XCH A,R1
	SUBB A,R1
	MOV R1,A
	MOV A,R2
	SUBB A,#0H
	MOV R2,A		;R2,R1=T(actual)x10
	ORL C,MINUS
	MOV MINUS,C
	JNC DLC3

	MOV A,R2
	CPL A
	MOV R2,A
	MOV A,R1
	CPL A
	ADD A,#1H
	MOV R1,A
	MOV A,R2
	ADDC A,#0H
	MOV R2,A

DLC3:	MOV R11,#0FFH	;100s init

DLC1:	MOV R4,R02
	MOV R3,R01
	INC R11
	CLR C
	MOV A,R3
	SUBB A,#100
	MOV R1,A
	MOV A,R4
	SUBB A,#0
	MOV R2,A
	JNC DLC1		;if C=1 then R11=N/100,R4=0

	MOV A,R3
	MOV B,#10
	DIV AB		;A=N/10,B=N/1
	SETB ACC.7
	MOV R12,A
	MOV R13,B
	JNB MINUS,DLC5
	MOV A,R11
	SETB ACC.7
	MOV R11,A
DLC5:	RET

;  ------ 1-Wire thermometer DALLAS DS1821 support ------

;  TEMPERATURE CONVERSION COMMANDS
;
;  0EEH - start convert T
;  022H - stop convert T
;  0AAH - Read temperature
;
;  THERMOSTAT COMMANDS
;
;  001H - write TH
;  002H - write TL
;  0A1H - read TH
;  0A2H - read TL
;  00CH - write status
;  0ACH - read status
;
;  Status register:
;
;  bit 7 - DONE 1= conversion complete
;               0= conversion in progress
;  bit 6 - 1
;
;  bit 5 - NVB   1= nonvolatile memory is busy
;                0= nonvolatile memory is not busy
;  bit 4 - THF   1= temperature exceeds TH (remain 1 until reset by writing 0)
;                0= normally
;  bit 3 - TLF   1= temperature lower TL (remain 1 until reset by writing 0)
;                0= normally
;  bit 2 - T/R   1= power up thermostat mode
;                0= power up one wire mode
;  bit 1 - POL   1= thermostat output is active high
;                0= thermostat output is active low
;  bit 0 - 1SHOT 1= one conversion
;                0= continuous conversion
;
;  Bits THF, TLF, T/R, POL, 1SHOT are nonvolatile
;
;  Temperature code format:
;
;  +125 - 07DH
;   +25 - 019H
;     0 - 000H
;    -1 - 0FFH
;   -25 - 0E7H
;   -55 - 0C9H

;  Init and start conversion in 1-wire thermometer DS1821.
;  Calls TRESET, TOUCHBY

START_21:	ACALL TRESET	;Issue reset pulse.
	JNC STR21           ;Fail if no part on bus.

	MOV A,#0ACH	;Read status command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#0FFH	;Perform read.
	ACALL TOUCHBY	;Read status.

	ANL A,#1H
	JNZ ST_21		;Skip write status if 1SHOT=1

	ACALL TRESET	;Issue reset pulse.
	JNC STR21           ;Fail if no part on bus.

	MOV A,#0CH	;Write status command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#01H	;Set 1SHOT to 1 (one conv. per start).
	ACALL TOUCHBY	;Write status.

ST_21:	ACALL TRESET	;Issue reset pulse.
	JNC STR21           ;Fail if no part on bus.

	MOV A,#0EEH	;Start convert command.
	ACALL TOUCHBY	;Send command byte.

	SETB C
STR21:	RET

;  Check ready 1-wire thermometer DS1821.
;  Returns A=0 when device not ready.
;  Calls TRESET, TOUCHBY

RDY_21:	ACALL TRESET	;Issue reset pulse.
	MOV A,#0ACH	;Read status command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#0FFH	;Perform read.
	ACALL TOUCHBY	;Read status.
	ANL A,#80H
	RET

;  Read temperature from 1-wire thermometer DS1821.
;  Returns C=1 in case of valid code, else C=0.
;  Returns D1_INT,D2_INT,D3_INT,MINUS of temperature (-55..99).
;  Calls TRESET, TOUCHBY

READ_21:  ACALL TRESET	;Issue reset pulse.
	JNC RDR21		;Fail if no part on bus.

	MOV A,#0AAH	;Read temperature command.
	ACALL TOUCHBY	;Send command byte.
	MOV A,#0FFH	;perform read
	ACALL TOUCHBY	;Read temperature.

	ACALL TCONV21	;HEX to BCD conversion
	SETB C
RDR21:	RET

;  Temperature HEX to BCD conversion
;  Input A=0..0C9H
;  Returns Dx_INT or Dx_EXT
;  MINUS - bit D1_INT.7

TCONV21:  MOV R6,A
	MOV C,ACC.7
	MOV MINUS,C	;minus store
	JNC TPL
	CPL A
	INC A
TPL:      MOV B,#10		;HEX to BCD conversion
	DIV AB
	JNB MINUS,TPL1
	SETB ACC.7
TPL1:	MOV R11,A
#IFDEF Z_SUP
	MOV R13,#BLANK
	MOV R12,B
#ELSE
	MOV R13,#0H
	SETB B.7
	MOV R12,B
#ENDIF
	RET

;Check for limits and thermostat control (000H <= ONLIM, OFLIM <= 09AH)

LIM_CHK:	MOV A,EXT_TH
	JZ OFF_TH		;thermostat off if EXT_TH=0
	MOV A,ONLIM
	CJNE A,OFLIM,CHK1
OFF_TH:	SETB CNTRL	;thermostat off if ONLIM=OFLIM
	RET

ON_TH:	CLR CNTRL
	RET

CHK1:	JC CHK2		;jump if OFLIM>ONLIM (heater mode)
	MOV A,EXT_T	;OFLIM<ONLIM (cooler mode)
	CJNE A,ONLIM,$+3H
	JNC ON_TH
	CJNE A,OFLIM,$+3H
	SJMP CHK3

CHK2:	CJNE A,EXT_T,$+3H	;A=ONLIM, OFLIM>ONLIM (heater mode)
	JNC ON_TH
	MOV A,OFLIM
	CJNE A,EXT_T,$+3H
CHK3:	JZ OFF_TH
	JC OFF_TH
	RET

;I2C NVM memory 24C08 support

;  Main program defines:
;
;  I2C slave address  I2C_ADDR (0A0H for first 256 bytes)
;  I2C data line	  SDA
;  I2C clock line	  SCL

I2C_DWBD: CLR ET1
	MOV P1,#0FFH
	SETB SDA
	SETB SCL

	PUSH ACC            ;save data byte
	MOV A,#I2C_ADDR	;I2C device address and write mode
	ACALL I2C_WR	;transmission
	MOV A,R1		;subaddress
	ACALL I2C_WR	;transmission
	POP ACC		;restore data byte
	ACALL I2C_WR	;transmission
	ACALL I2C_STOP

	SETB ET1
	ACALL DEL50	;delay 50mS
	RET

I2C_DRDD: CLR ET1
	MOV P1,#0FFH
	SETB SDA
	SETB SCL

	MOV A,#I2C_ADDR	;I2C device address and write mode
	ACALL I2C_WR	;transmission
	MOV A,R1		;subaddress
	ACALL I2C_WR	;transmission
	ACALL I2C_STOP	;stop
	MOV A,#I2C_ADDR+1	;I2C device address and read mode
	ACALL I2C_WR	;transmission
	ACALL I2C_LRD	;receive byte
	ACALL I2C_STOP	;stop

	SETB ET1
	RET

;Write byte from A to I2C

I2C_WR:  	MOV R3,#9H	;bit counter load
	SETB C		;set bit C for bit9=1 (when ACK)
	ACALL SDA0	;SDA 1/0 - start
I2CWR1:	ACALL SCL0	;SCL 1/0
	RLC A
	JC OUTP1		;jump if bit=1
	ACALL SDA0	;else SDA=0
OUTP0:	ACALL SCL1	;SCL 0/1
	DJNZ R3,I2CWR1
	RET
OUTP1:	ACALL SDA1	;SDA=1 if bit=1
	SJMP OUTP0

;Read byte from I2C to A and no ACK (read last byte)

I2C_LRD:	MOV A,#1H
I2CLRD1:	ACALL SCL0
	ACALL SDA1
	ACALL SCL1
	MOV C,SDA
	RLC A
	JNC I2CLRD1
	ACALL SCL0
	ACALL SCL1	;SCL 0/1 when SDA=1 - no ACK
	RET

;Stop condition generation

I2C_STOP:	ACALL SCL0
	ACALL SDA0
	ACALL SCL1
	ACALL SDA1
	RET

;SDA and SCL lines drive

SDA0:	CLR SDA	;SDA 1/0
	NOP	;delay
	RET

SDA1:	SETB SDA	;SDA 0/1
	NOP	;delay
	RET

SCL0:	CLR SCL	;SCL 1/0
	NOP	;delay
	RET

SCL1:	SETB SCL	;SCL 0/1
	NOP	;delay
	RET

SIGN	.EQU 098H		;signature

;EEPROM address map

NVM_SIG	.EQU 0F0H		;signature address
NVM_BR	.EQU 0F1H		;brightness address
NVM_ONL	.EQU 0F2H		;on limit address
NVM_OFL	.EQU 0F3H		;off limit address
NVM_IDM	.EQU 0F4H		;indication mode address
NVM_RTV	.EQU 0F5H		;auto change rate value address

SAVE:	JBC NSV_BR,SV1
	JBC NSV_ON,SV2
	JBC NSV_OF,SV3
	JBC NSV_IM,SV4
	JBC NSV_RT,SV5
	RET
SV1:	MOV R1,#NVM_BR
	MOV A,PWM
	SJMP DO_SV
SV2:	MOV R1,#NVM_ONL
	MOV A,ONLIM
	SJMP DO_SV
SV3:	MOV R1,#NVM_OFL
	MOV A,OFLIM
	SJMP DO_SV
SV4:	MOV R1,#NVM_IDM
	MOV A,INDMD
	ANL A,#1H
	SJMP DO_SV
SV5:	MOV R1,#NVM_RTV
	MOV A,ACHR
DO_SV:	ACALL I2C_DWBD
	RET

NVMREAD:	MOV R1,#NVM_SIG
	ACALL I2C_DRDD
	CJNE A,#SIGN,NVMINIT
	MOV R0,#PARAMS
	MOV R2,#5H
NR1:	INC R1
	ACALL I2C_DRDD
	MOV @R0,A
	INC R0
	DJNZ R2,NR1
	RET
NVMINIT:  MOV R1,#NVM_SIG
	MOV A,#SIGN
	ACALL I2C_DWBD
	MOV PWM,#PWM_MAX
	MOV ONLIM,#SHIFT
	MOV OFLIM,#SHIFT
	CLR A
	MOV INDMD,A
	MOV ACHR,A
	MOV NOTSV,#1FH
	RET

DISP:	JB IND_SET,D2
	JB IND_INT,D1
	MOV A,EXT_TH	;INDMD=0
	JNZ D3
	MOV A,#CH_MIN
	MOV D1_EXT,A
	MOV D3_EXT,A
	SETB ACC.7
	MOV D2_EXT,A
D3:	MOV DIG1,D1_EXT
	MOV DIG2,D2_EXT
	MOV DIG3,D3_EXT
	SJMP IND

D1:	MOV A,INT_TH	;INDMD=1
	JNZ D9
	MOV A,#CH_MIN
	MOV D1_INT,A
	MOV D3_INT,A
	SETB ACC.7
	MOV D2_INT,A
D9:	MOV DIG1,D1_INT
	MOV DIG2,D2_INT
	MOV DIG3,D3_INT
	SJMP IND

D2:       JNB IND_TH1,D5
	MOV DIG3,#1H
	SJMP D8

D5:	JNB IND_ONL,D6
	MOV A,ONLIM
	SJMP D4

D6:	JNB IND_TH0,D7
	MOV DIG3,#0H
D8:	MOV DIG1,#CH_t
	MOV DIG2,#CH_h
	SJMP IND

D7:       MOV A,OFLIM
D4:	CLR C
	SUBB A,#SHIFT
	MOV MINUS,C
	JNC DM
	CPL A
	INC A
DM:	MOV B,#10
	DIV AB
	MOV C,MINUS
	MOV ACC.7,C
	MOV DIG1,A
	MOV DIG2,B
	MOV DIG3,#BLANK

IND:	MOV C,T320M
	ORL C,/BLINK
	JC IND1
	CLR A
	CPL A
	MOV CD1,A
	MOV CD2,A
	MOV CD3,A
	RET

IND1:	MOV DPTR,#FONT
	MOV A,DIG1
	MOV C,ACC.7	;minus bit store
	CPL C
	CLR ACC.7
	MOVC A,@A+DPTR
	MOV ACC+SB,C	;minus on/off
	MOV CD1,A

	MOV A,DIG2
	MOV C,ACC.7	;point bit store
	CPL C
	CLR ACC.7
	MOVC A,@A+DPTR
	MOV ACC+SB,C	;point on/off
	MOV CD2,A

	MOV A,DIG3
	MOVC A,@A+DPTR
	MOV C,IND_INT
	MOV ACC+SB,C	;LED EXT on/off
	MOV CD3,A

	RET

GETPWM:   MOV A,PWM
	MOV B,#7H		;682H/238
	MUL AB		;682H/238*PWM
	CPL A
	MOV PHVL,A
	MOV A,B
	CPL A
	MOV PHVH,A

	MOV A,PHVL
	ADD A,#82H
	CPL A
	MOV PWVL,A
	MOV A,PHVH
	ADDC A,#06H
	CPL A
	MOV PWVH,A
	RET

;Delay 50mS

DEL50:    MOV R2,#100
	SJMP DEL05

;Delay 10mS

DEL10:    MOV R2,#20
	SJMP DEL05

DEL05:    MOV R3,#CLK_KHZ/48
	DJNZ R3,$
	DJNZ R2,DEL05
	RET

;  ------ Interrupt Holders ------

;  TIMER 0 Interrupt
;  System clock (20mS)

RTC:	PUSH PSW
	PUSH ACC
	CLR TR0          	;timer 0 stop
	MOV TH0,#HI(RTCV)  	;timer 0 load for 20mS
	MOV TL0,#LO(RTCV)
	SETB TR0         	;timer start

	INC RTPC         	;Real Time Program Counter INC

	DJNZ RTPCS,RTC1
	MOV RTPCS,#V100MS

;  100mS program counters

	JNB FEN,RTC11
	MOV A,ACHR
	ADD A,#1H
	JC RTC12
	MOV ACHR,A
	MOV ACHTM,A
	SJMP RTC12

RTC11:	MOV A,ACHTM
	JZ RTC12
	DEC ACHTM

RTC12:	MOV A,OFFTM
	JZ RTC1
	DEC OFFTM

;  20mS program counters

RTC1:	MOV A,SMPTM
	JZ RTC2
	DEC SMPTM

RTC2:	MOV A,KEYTM
	JZ RTC3
	DEC KEYTM

RTC3:	MOV A,TMO_EXT
	JZ RTC4
	DEC TMO_EXT

RTC4:	MOV A,TMO_INT
	JZ RTC5
	DEC TMO_INT

RTC5:	MOV A,DELTM
	JZ RTC6
	DEC DELTM

RTC6:	MOV A,SAVTM
	JZ RTC7
	DEC SAVTM

RTC7:	POP ACC
	POP PSW
	RETI

;  TIMER 1 Interrupt
;  Indicators Scanning (2mS)

INDSCAN:	PUSH PSW
	PUSH ACC

	MOV A,PHASE
	JZ PH0
	DEC A
	JZ PW0
	DEC A
	JZ PH1
	DEC A
	JZ PW1
	DEC A
	JZ PH2
PW2:	SETB SCAN2
	MOV PHASE,#0FFH
	SJMP PW
PW1:	SETB SCAN1
	SJMP PW
PW0:	SETB SCAN0
	SJMP PW
PH2:	SETB SCAN1
	MOV P1,CD3
	CLR SCAN2
	SJMP PH
PH1:      SETB SCAN0
	MOV P1,CD2
	CLR SCAN1
	SJMP PH
PH0:	SETB SCAN2
	MOV P1,CD1
	CLR SCAN0

PH:	CLR TR1          	;timer 1 stop
	MOV TH1,PHVH   	;timer 1 load (PH phase)
	MOV TL1,PHVL
	SETB TR1         	;timer start
	SJMP EOPH

PW:       CLR TR1          	;timer 1 stop
	MOV TH1,PWVH	;timer 1 load (PW phase)
	MOV TL1,PWVL
	SETB TR1         	;timer start

	MOV P1,#0H
	MOV INCODE,#0FFH
	JNB RETL,KEYSCAN
	MOV P1,#0FFH
	SJMP EOPH

KEYSCAN:	MOV A,#0EEH
KSC:	MOV P1,A		;scan keyboard
	MOV C,RETL
	XCH A,INCODE
	RLC A
	XCH A,INCODE
	RLC A
	JC KSC

EOPH:	INC PHASE
	POP ACC
	POP PSW
	RETI

;Keys codes table

KEY_DN	.EQU 08H
KEY_UP	.EQU 04H
KEY_SL	.EQU 02H
KEY_EX	.EQU 01H
KEY_UD	.EQU 0CH

;Font table
;	    SEDCGABF
FONT	.DB 10001000B	;code 00H, character 0
	.DB 11101110B	;code 01H, character 1
	.DB 10010100B	;code 02H, character 2
	.DB 11000100B	;code 03H, character 3
	.DB 11100010B	;code 04H, character 4
	.DB 11000001B	;code 05H, character 5
	.DB 10000001B	;code 06H, character 6
	.DB 11101100B	;code 07H, character 7
	.DB 10000000B	;code 08H, character 8
	.DB 11000000B	;code 09H, character 9
	.DB 10100000B	;code 0AH, character A
	.DB 10000011B	;code 0BH, character B
	.DB 10011001B	;code 0CH, character C
	.DB 10000110B	;code 0DH, character D
	.DB 10010001B	;code 0EH, character E
	.DB 10110001B	;code 0FH, character F
	.DB 11110111B	;code 10H, character -
	.DB 11111111B	;code 11H, character blank
	.DB 10010011B	;code 12H, character t
	.DB 10100011B	;code 13H, character h
	.DB 10110111B	;code 14H, character r
	.DB 10110000B	;code 15H, character P

SB	.EQU 07H		;S bit position

; ------ Characters codes table ------

CH_E	.EQU 00EH		;character "E" code
CH_d	.EQU 00DH		;character "d" code
CH_MIN	.EQU 010H		;character "-" code
BLANK	.EQU 011H		;character "blank" code
CH_t	.EQU 012H		;character "t" code
CH_h	.EQU 013H		;character "h" code
CH_r	.EQU 014H		;character "r" code
CH_P	.EQU 015H		;character "P" code

	.END
