ProgrammablaufAssembler-Programm


Empfang der Uhrzeit

Die Uhrzeit wird beim Starten empfangen und jeden Sonntag um 4:00:50. Der Einfachheit halber zähle ich die Uhrzeit nicht weiter, während die Zeit empfangen wird. Damit man die stehende Uhr möglichst nicht sieht, empfange ich nachts um 4 Uhr die Uhrzeit. Die Quarztaktung ist so genau, dass kein täglicher Abgleich stattfinden muss. Um trotzdem die Umschaltung zwischen Sommer- und Winderzeit zu erkennen, die ja immer nachts um 2 bzw. 3 Uhr an einem Sonntag stattfindet, mache ich den Abgleich jeden Sonntag. Das Starten in der 50. Sekunde verringert die Zeit, die für den Empfang benötigt wird, da die Übertragung der Daten bei der 1. Sekunde einer Minute startet.

Das Weiterzählen der Uhrzeit um eine Sekunde findet mit den entsprechenden Überträgen statt. Beim Tag wird ein evtl. Schaltjahr am Ende des Februars ebenfalls berücksichtigt.


Temperaturanzeige mit Speicherfunktion

Im Normalbetrieb wird die aktuelle Temperatur mit 1° Genauigkeit angezeigt. Ich hatte mich entschieden, keine Nachkommastelle anzuzeigen. Zwar machen das die meisten digitalen Thermometer (auch wenn deren Genauigkeit meist nur etwa +- 1° beträgt), aber ganze Gradzahlen reichen zur Information aus und die Anordnung der Ziffern insgesamt gefiel mir so besser.

Die Temperatur wird einmal pro Minute gemessen. Für innen und außen wird jeweils der bisher vorgekommene Maximal- und Minimalwert abgespeichert. Für jeden dieser vier Werte wird ein ganzer Satz Informationen inkl. Datum und Uhrzeit abgespeichert, wobei der Zeitpunkt aufgezeichnet wird, zudem diese Temperatur das letzte Mal auftrat. Zum Vergleich der Temperaturen wird übrigens intern ein gemessene Zeitwert abgespeichert statt der Temperatur als Ganzzahl. In der Praxis bedeutet das, dass der tatsächliche Zeitpunkt mit der minimalen / maximalen Temperatur genauer bestimmt wird, da eine höhere Genauigkeit als 1°C benutzt wird.

Zur Anzeige der bisherigen Maximal- und Minimalwerte drückt man einen Taster, der leicht versenkt an der Seite des Gehäuses eingebaut ist. Die vier Datensätze werden dann jeweils für 3 Sekunden angezeigt, wobei eine der beiden Temperaturen jeweils ausgeblendet wird. Danach wird wieder die aktuelle Zeit und Temperatur angezeigt. Zum Zurücksetzen der gespeicherten Daten drückt man während des Anzeigezyklus' nochmals den Taster. Alle Datensätze werden dann (wie auch nach Start der Uhr) auf die aktuellen Werte gesetzt.


Überprüfung der Impulslänge des DCF-Signals

Zur sicheren Erkennung der einzelnen Bits beim Empfang der Uhrzeit habe ich die Signallängen gemessen:

Dadurch ergeben sich die Schwellwerte

Durch die Verwendung der Schwellwerte kann der Empfang von falschen Daten verringert werden. Zusätzlich werden die übertragenen Prüfbits verglichen.


Quelltext

dcf77.asm (32 kB)

; #####################################################################
; ### Funkuhr 1.0 01/2004 (c) Uwe Freese                            ###
; ### http://www.uwe-freese.de                   mail@uwe-freese.de ###
; ###                                                               ###
; ### You can use this program freely, but please always include    ###
; ### this copyright information when you share it.                 ###
; ###                                                               ###
; ### Diese Software kann frei verwendet werden, aber bitte immer   ###
; ### diesen Copyright-Hinweis hinzufügen, wenn es weitergegeben    ###
; ### wird!                                                         ###
; #####################################################################

.CSEG
.ORG 0x00

.INCLUDE "2313def.inc"

.EQU SIGNAL_LENGTH_SHORT_LOW = 7   ; threshold between low and a too short signal (reception error)
.EQU SIGNAL_LENGTH_SHORT_HIGH = 79 ; (unused)
.EQU SIGNAL_LENGTH_LONG_HIGH = 95
.EQU SIGNAL_LENGTH_LONG_LOW = 21
.EQU SIGNAL_LENGTH_HIGH  = 11      ; threshold between low and high signal
.EQU SIGNAL_LENGTH_SYNC_LOW  = 171 ; minimum length for a sync signal (59th second)
.EQU SIGNAL_LENGTH_SYNC_HIGH = 195 ; maximum length for a sync signal (59th second)

.EQU SYNCTIME_H = 4
.EQU SYNCTIME_M = 0
.EQU SYNCTIME_S = 50
.EQU SYNCTIME_W = 7 ; day, Mo=1, ... So=7

.DEF R_TMP           = R20
.DEF R_TMP2          = R21
.DEF R_CHECKBIT      = R22
.DEF R_SIGNAL_LENGTH = R19
.DEF R_7SEG_DIGIT    = R23 ; digit that should be displayed
.DEF R_7SEG_DIGIT_NR = R24 ; number of the LED display that should display the number
.DEF R_OVERFLOW      = R25

.DEF R_DELAY1        = R16
.DEF R_DELAY2        = R17
.DEF R_DCFBIT        = R18

; Ports 'n Pins
.EQU DCF_IN_PORT = PINB
.EQU DCF_IN_PIN  = 2
.EQU USERKEY_IN_PORT = PIND
.EQU USERKEY_IN_PIN  = 6
.EQU TEMP1_IN_PORT = PINB
.EQU TEMP1_IN_PIN  = 0
.EQU TEMP2_IN_PORT = PINB
.EQU TEMP2_IN_PIN  = 1
.EQU LED_PORT    = PORTB
.EQU LED_PIN     = 3
.EQU SEVENSEG_CLCK_PORT = PORTD
.EQU SEVENSEG_CLCK_PIN  = 4
.EQU CLOCK_PORT    = PIND
.EQU CLOCK_PIN     = 5
.EQU CLOCK_RESET_PIN = 0
.EQU PORTX_CHANNEL = 14 ; channel of PORTX on the 4067

; one byte for every LED-7segment-display
.EQU SRAM_DATA_START = 0xB6
.EQU portx           = 0xB6; PORTX byte
.EQU therm_counter   = 0xB7 ; thermometer 0=show time, 1..3=show min in, 4..6=show max in, 7..9=show min out, 10..12=show max out

.EQU maxout_therm_out       = 0xB8 ; thermometer
.EQU maxout_therm_in        = 0xB9 ; thermometer
.EQU maxout_d_m             = 0xBA ; date
.EQU maxout_d_d             = 0xBB ; date
.EQU maxout_t_h             = 0xBC ; time
.EQU maxout_t_m             = 0xBD ; time

.EQU minout_therm_out       = 0xBE ; thermometer
.EQU minout_therm_in        = 0xBF ; thermometer
.EQU minout_d_m             = 0xC0 ; date
.EQU minout_d_d             = 0xC1 ; date
.EQU minout_t_h             = 0xC2 ; time
.EQU minout_t_m             = 0xC3 ; time

.EQU maxin_therm_out       = 0xC4 ; thermometer
.EQU maxin_therm_in        = 0xC5 ; thermometer
.EQU maxin_d_m             = 0xC6 ; date
.EQU maxin_d_d             = 0xC7 ; date
.EQU maxin_t_h             = 0xC8 ; time
.EQU maxin_t_m             = 0xC9 ; time

.EQU minin_therm_out       = 0xCA ; thermometer
.EQU minin_therm_in        = 0xCB ; thermometer
.EQU minin_d_m             = 0xCC ; date
.EQU minin_d_d             = 0xCD ; date
.EQU minin_t_h             = 0xCE ; time
.EQU minin_t_m             = 0xCF ; time

.EQU therm_out       = 0xD0 ; thermometer
.EQU therm_in        = 0xD1 ; thermometer
.EQU d_m             = 0xD2 ; date
.EQU d_d             = 0xD3 ; date
.EQU t_h             = 0xD4 ; time
.EQU t_m             = 0xD5 ; time
.EQU t_s             = 0xD6 ; time
.EQU d_w             = 0xD7 ; date
.EQU d_y             = 0xD8 ; date

.EQU therm_out_shown = 0xD9 ; date
.EQU therm_in_shown  = 0xDA ; date
.EQU d_m_shown       = 0xDB ; date
.EQU d_d_shown       = 0xDC ; date
.EQU t_h_shown       = 0xDD ; time
.EQU t_m_shown       = 0xDE ; time
.EQU t_s_shown       = 0xDF ; time

.EQU NOTEMP_VALUE    = 235; value that's stored in SRAM if this temp shouldn't be shown
.EQU TEMPZERO_VALUE  = 125; a time value at 0°C

; Stack initialisieren
	ldi   R_TMP, 0xB5; RAMEND == 0xDF
	out   SPL, R_TMP

	rcall Init

; for calibrating the temp sensor, uncomment the following line
	;rjmp  GetTempRaw

	; if user button pressed, run Demo
	sbic  USERKEY_IN_PORT, USERKEY_IN_PIN ; Skip next inst. if bit in Port cleared
	rjmp  Demo
	rjmp  Start

; Temperature constants, Values for -20°C, -19°C,... +40°C
; if measured time is lower than the first value, -20°C is displayed,
; if measured time is higher or equal than the first, -19°C is displayed, ...
; (values are stored in EEPROM)

; ----- delay 100us (at 4 MHz -> 400 cycles) -----

Delay100us:
	ldi   R_DELAY1, 98 ; 1 cycle
Delay100us2:
	dec   R_DELAY1     ; 1 cycle
	cpi   R_DELAY1, 0  ; 1 cycle
	brne  Delay100us2  ; 1 cycle if false, 2 if true
	nop
	ret                ; 4 cycles
	
; ----- delay 5ms (at 4 MHz) -----

Delay5ms:
	ldi   R_DELAY2, 49
Delay5ms2:
	rcall Delay100us
	dec   R_DELAY2
	cpi   R_DELAY2, 0
	brne  Delay5ms2
	ret

; ----- delay 10ms (at 4 MHz) -----

Delay10ms:
	ldi   R_DELAY2, 99
Delay10ms2:
	rcall Delay100us
	dec   R_DELAY2
	cpi   R_DELAY2, 0
	brne  Delay10ms2
	ret

; ----- Delay 850ms -----
Delay890ms:
	ldi   R_TMP, 89
Delay890ms_Loop:
	rcall delay10ms
	dec   R_TMP
	cpi   R_TMP, 1
	brsh  Delay890ms_Loop
	ret

; ----- Wait for a clock tick -----

WaitForTick:
	ldi   R_TMP, 0 ; remember in R_TMP if user key was pressed
WaitForTick_Low: ; (Low)
	sbic  USERKEY_IN_PORT, USERKEY_IN_PIN ; Skip next inst. if bit in Port cleared
	ldi   R_TMP, 1
	sbic  CLOCK_PORT, CLOCK_PIN ; Skip next inst. if bit in Port cleared
	rjmp  WaitForTick_High
	rjmp  WaitForTick_Low
WaitForTick_High: ; (High)
	sbic  USERKEY_IN_PORT, USERKEY_IN_PIN ; Skip next inst. if bit in Port cleared
	ldi   R_TMP, 1
	sbis  CLOCK_PORT, CLOCK_PIN ; Skip next inst. if bit in Port set
	rjmp  WaitForTick_CheckUserPressedKey
	rjmp  WaitForTick_High
WaitForTick_CheckUserPressedKey:
	; if R_TMP == 1, set therm_counter to 12
	cpi   R_TMP, 1
	breq  WaitForTick_SetThermCounter
	ret
WaitForTick_SetThermCounter:
	; if 0 < therm_counter < 12, then the user pressed the key a second time
	; delete all remembered temperatures then
	lds   R_TMP, therm_counter
	cpi   R_TMP, 12
	brge  WaitForTick_NoSecondKeypress
	cpi   R_TMP, 0
	breq  WaitForTick_NoSecondKeypress
	; Ah! Second keypress detected. Delete temperatures.
	rcall Reset_Temp

WaitForTick_NoSecondKeypress:
	ldi   R_TMP, 13
	sts   therm_counter, R_TMP
	ret

; ----- wait until level going low, then up -----

WaitForLow:
	ldi   R_SIGNAL_LENGTH, 0      ; Reset signal length
WaitForLow2:
	rcall Delay10ms
	cpi   R_SIGNAL_LENGTH, 0xFF   ; inc signal length if not at maximum
	breq  WaitForLow2_NoInc
	inc   R_SIGNAL_LENGTH         ; count signal length
WaitForLow2_NoInc:
	sbic  DCF_IN_PORT, DCF_IN_PIN ; Skip next inst. if bit 0 in Port D set
	rjmp  WaitForLow2             ; Bit not set
	ret

; ----- wait until level going high, count signal length -----

WaitForHigh:
	ldi   R_SIGNAL_LENGTH, 0      ; Reset signal length
WaitForHigh2:
	rcall Delay10ms
	cpi   R_SIGNAL_LENGTH, 0xFF   ; inc signal length if not at maximum
	breq  WaitForHigh2_NoInc
	inc   R_SIGNAL_LENGTH         ; count signal length
WaitForHigh2_NoInc:
	sbis  DCF_IN_PORT, DCF_IN_PIN ; Skip next inst. if bit 0 in Port D set
	rjmp  WaitForHigh2            ; Bit not set
	ret

; ----- wait for the start of a minute -----

WaitForSecond0:           ; Wait for the 59th second (long period)
	rcall WaitForHigh
	rcall WaitForLow
	cpi   R_SIGNAL_LENGTH, SIGNAL_LENGTH_SYNC_LOW
	brlo  WaitForSecond0
	cpi   R_SIGNAL_LENGTH, SIGNAL_LENGTH_SYNC_HIGH
	brge  WaitForSecond0
	ret

; ----- 'PORTC' is the 74HC573 latch on the 15th output of the 4067 -----
; ----- It stores 4 bits output. The value is stored in SRAM. -----
; PORTX mapping:
; bit 0: real time clock counter reset (reset offset)
; bit 1: minus sign of 10th display of out temperature
; bit 2: extra minus sign

OutPORTX:
	lds   R_7SEG_DIGIT, portx
	ldi   R_7SEG_DIGIT_NR, PORTX_CHANNEL
	rcall PrintDigit
	ret

; ----- reset max/min temperatures -----

Reset_Temp:
	; clear maxout
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, maxout_therm_out
	rcall CopyData

	; clear maxin
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, maxin_therm_out
	rcall CopyData

	; clear minout
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, minout_therm_out
	rcall CopyData

	; clear minin
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, minin_therm_out
	rcall CopyData

	ret

Init:
; Pins on Port D used:
;   Bit 0: 7segment data
;       1: 7segment data
;       2: 7segment data
;       3: 7segment data
;       4: 7segment selection clock (4067)
;       5: real time clock signal in (1 Hz)
;       6: user button in
	ldi   R_TMP, 0b00011111 ; Port D Control
	out   DDRD, R_TMP ; Data direction register
	ldi   R_TMP, 0b00010000 ; Pullup resistors on DCF input on to avoid glitches
	out   PortD, R_TMP ; on open inputs
; Pins on Port B:
;   Bit 0: Input Temp. 1
;       1: Input Temp. 2
;       2: DCF In
;       3: DCF Sync LED + Charge Temp. Capacity
;       4: 7segment address
;       5: 7segment address
;       6: 7segment address
;       7: 7segment address
	ldi   R_TMP, 0b11111000 ; Port B Control
	out   DDRB, R_TMP ; Data Direction Register
	ldi   R_TMP, 0b11110111 ; pullup resistors
	out   PortB, R_TMP

	; clear SRAM
	ldi   R_TMP, 0
	ldi   R_TMP2, SRAM_DATA_START

Init_ClearSRAM:
	ldi   XH, 0
	mov   XL, R_TMP2
	st    X, R_TMP

	inc   R_TMP2
	cpi   R_TMP2, 0xE0
	brlo  Init_ClearSRAM

	ret

; ----- scan one DCF bit and save it as bit 0 in R_DCFBIT -----
; ----- on error, also set bit 1 in R_DCFBIT -----

ScanBit:
	rcall WaitForLow
	cpi   R_SIGNAL_LENGTH, SIGNAL_LENGTH_LONG_HIGH
	brge  ScanBitError                           ; Error if signal pause was too long
	
	rcall PrintTimeAndDate ; update display, takes about 0,3 ms, so it's not a problem for the signal length measurement

	rcall WaitForHigh

	; inc sec. counter
	lds   R_OVERFLOW, t_s ; misuse of R_OVERFLOW, because R_TMP and R_TMP2 are used outside
	inc   R_OVERFLOW
	sts   t_s, R_OVERFLOW

	cpi   R_SIGNAL_LENGTH, SIGNAL_LENGTH_SHORT_LOW
	brlo  ScanBitError                           ; Error if signal was too short
	cpi   R_SIGNAL_LENGTH, SIGNAL_LENGTH_LONG_LOW
	brge  ScanBitError                           ; Error if signal was too long
	cpi   R_SIGNAL_LENGTH, SIGNAL_LENGTH_HIGH
	brlo  ScanBit0
ScanBit1:
	ldi   R_DCFBIT, 1
	sbi   LED_PORT, LED_PIN
	ret
ScanBit0:
	ldi   R_DCFBIT, 0
	cbi   LED_PORT, LED_PIN
	ret
ScanBitError:
	ldi   R_DCFBIT, 2
	ret

; ----- scan one bit. If R_DCFBIT shows an error, jump (!) to ScanTime -----
; ----- (return address is consumed from stack beforre!). -----
; ----- If R_DCFBIT is 1 (1 received), add R_TMP2 to R_TMP. -----
; ----- R_CHECKBIT is negated if a 1 was received. -----

ScanBitAndAdd:
	rcall ScanBit
	sbrs  R_DCFBIT, 1 ; if error bit is set, restart
	rjmp  ScanBitAndAdd_ok
	; consume return address from stack, because we'll do a rjmp instead of a ret
	pop   R_CHECKBIT ; R_CHECKBIT isn't used anymore
	pop   R_CHECKBIT
	rjmp  ScanTime

ScanBitAndAdd_ok:
	sbrc  R_DCFBIT, 0
	add   R_TMP, R_TMP2 ; add value if bit was high
	sbrc  R_DCFBIT, 0
	neg   R_CHECKBIT ; calculate check bit
	ret

; ----- clear current time and temp values -----

ClearCurrentTimeAndTemp:
	ldi   R_TMP, 0
	sts   t_s, R_TMP
	sts   t_m, R_TMP
	sts   t_h, R_TMP
	sts   d_d, R_TMP
	sts   d_m, R_TMP
	sts   d_y, R_TMP
	sts   d_w, R_TMP
	ldi   R_TMP, TEMPZERO_VALUE ; store the value at temp 0°C
	sts   therm_out, R_TMP
	sts   therm_in, R_TMP
	ret

; ----- read all bits of one minute, starting at second 0 -----
; ----- save them to time registers -----

ScanTime:

	rcall ClearCurrentTimeAndTemp
	rcall PrintTimeAndDate

	; turn clock counter off
	lds   R_TMP, portx
	ori   R_TMP, 0b00000001
	sts   portx, R_TMP
	rcall OutPORTX

	sbi   LED_PORT, LED_PIN
	rcall Delay10ms
	rcall Delay10ms
	rcall Delay10ms
	rcall Delay10ms
	cbi   LED_PORT, LED_PIN
	rcall Delay10ms
	rcall Delay10ms
	rcall Delay10ms
	rcall Delay10ms
	sbi   LED_PORT, LED_PIN
	rcall Delay10ms
	rcall Delay10ms
	rcall Delay10ms
	rcall Delay10ms
	cbi   LED_PORT, LED_PIN

	rcall WaitForSecond0
	; now we are at the start of a minute

; Sekunde:    Bedeutung:
; 0.          Minutenbeginn (immer LOW)
; 1. - 14.    Reserviert, keine Bedeutung
; 15.         Reserveantenne aktiv
; 16.         Umstellung von Sommer- auf Winterzeit, oder umgekehrt
; 17.         Sommerzeit aktiv
; 18.         Winterzeit aktiv
; 19.         Ankündigung Schaltsekunde
; 20.         Zeitbeginn
; 21. - 27.   Minute 1, 2, 4, 8, 10, 20, 40
; 28.         Prüfbit Minute
; 29. - 34.   Stunde 1, 2, 4, 8, 10, 20
; 35.         Prüfbit Stunde
; 36. - 41.   Tag 1, 2, 4, 8, 10, 20
; 42. - 44.   Wochentag 1, 2, 4
; 45. - 49.   Monat 1, 2, 4, 8, 10
; 50. - 57.   Jahr 1, 2, 4, 8, 10, 20, 40, 80
; 58.         Prüfbit Datum
; 59.         fehlt zur Erkennung des Minutenanfangs

	; skip 21 bits
ScanTime_Skip21:
	rcall ScanBit
	sbrc  R_DCFBIT, 1 ; if error bit is set, restart
	rjmp  ScanTime
	lds   R_OVERFLOW, t_s
	cpi   R_OVERFLOW, 21
	brlo  ScanTime_Skip21

	; read minutes
	ldi   R_TMP, 0
	ldi   R_CHECKBIT, 0

	ldi   R_TMP2, 1
	rcall ScanBitAndAdd
	ldi   R_TMP2, 2
	rcall ScanBitAndAdd
	ldi   R_TMP2, 4
	rcall ScanBitAndAdd
	ldi   R_TMP2, 8
	rcall ScanBitAndAdd
	ldi   R_TMP2, 10
	rcall ScanBitAndAdd
	ldi   R_TMP2, 20
	rcall ScanBitAndAdd
	ldi   R_TMP2, 40
	rcall ScanBitAndAdd

	; check minutes check bit
	rcall ScanBit
	sbrc  R_DCFBIT, 1 ; if error bit is set, restart
	rjmp  ScanTime
	sbrc  R_DCFBIT, 0
	neg   R_CHECKBIT ; calculate check bit
	; R_TMP2 must be 0 if data is correct
	sbrc  R_CHECKBIT, 0
	rjmp  ScanTime ; back to start
	
	; save minutes to sram
	sts   t_m, R_TMP

	; read hours
	ldi   R_TMP, 0
	ldi   R_CHECKBIT, 0

	ldi   R_TMP2, 1
	rcall ScanBitAndAdd
	ldi   R_TMP2, 2
	rcall ScanBitAndAdd
	ldi   R_TMP2, 4
	rcall ScanBitAndAdd
	ldi   R_TMP2, 8
	rcall ScanBitAndAdd
	ldi   R_TMP2, 10
	rcall ScanBitAndAdd
	ldi   R_TMP2, 20
	rcall ScanBitAndAdd

	; check hours check bit
	rcall ScanBit
	sbrc  R_DCFBIT, 1 ; if error bit is set, restart
	rjmp  ScanTime
	sbrc  R_DCFBIT, 0
	neg   R_CHECKBIT ; calculate check bit
	; R_TMP2 must be 0 if data is correct
	sbrc  R_CHECKBIT, 0
	rjmp  ScanTime ; back to start
	
	; save hours to sram
	sts   t_h, R_TMP

	; read days
	ldi   R_TMP, 0
	ldi   R_CHECKBIT, 0

	ldi   R_TMP2, 1
	rcall ScanBitAndAdd
	ldi   R_TMP2, 2
	rcall ScanBitAndAdd
	ldi   R_TMP2, 4
	rcall ScanBitAndAdd
	ldi   R_TMP2, 8
	rcall ScanBitAndAdd
	ldi   R_TMP2, 10
	rcall ScanBitAndAdd
	ldi   R_TMP2, 20
	rcall ScanBitAndAdd

	; save days to sram
	sts   d_d, R_TMP

	; skip weekday
	ldi   R_TMP, 0

	ldi   R_TMP2, 1
	rcall ScanBitAndAdd
	ldi   R_TMP2, 2
	rcall ScanBitAndAdd
	ldi   R_TMP2, 4
	rcall ScanBitAndAdd

	; save weekdays to sram
	sts   d_w, R_TMP

	; read month
	ldi   R_TMP, 0

	ldi   R_TMP2, 1
	rcall ScanBitAndAdd
	ldi   R_TMP2, 2
	rcall ScanBitAndAdd
	ldi   R_TMP2, 4
	rcall ScanBitAndAdd
	ldi   R_TMP2, 8
	rcall ScanBitAndAdd
	ldi   R_TMP2, 10
	rcall ScanBitAndAdd

	; save month to sram
	sts   d_m, R_TMP

	; read year
	ldi   R_TMP, 0

	ldi   R_TMP2, 1
	rcall ScanBitAndAdd
	ldi   R_TMP2, 2
	rcall ScanBitAndAdd
	ldi   R_TMP2, 4
	rcall ScanBitAndAdd
	ldi   R_TMP2, 8
	rcall ScanBitAndAdd
	ldi   R_TMP2, 10
	rcall ScanBitAndAdd
	ldi   R_TMP2, 20
	rcall ScanBitAndAdd
	ldi   R_TMP2, 40
	rcall ScanBitAndAdd
	ldi   R_TMP2, 80
	rcall ScanBitAndAdd

	; save year to sram
	sts   d_y, R_TMP

	; check date check bit
	rcall ScanBit
	sbrc  R_DCFBIT, 1 ; if error bit is set, restart
	rjmp  ScanTime
	sbrc  R_DCFBIT, 0
	neg   R_CHECKBIT ; calculate check bit
	; R_TMP2 must be 0 if data is correct
	sbrc  R_CHECKBIT, 0
	rjmp  ScanTime ; back to start

	; charge capacitor
	cbi   LED_PORT, LED_PIN

	; ExactSync loop, about 900ms
	rcall Delay890ms
	rcall PrintTimeAndDate ; show 59 sec.

	ldi   R_TMP, 0
	sts   t_s, R_TMP

	; turn clock counter on
	lds   R_TMP, portx
	andi  R_TMP, 0b11111110
	sts   portx, R_TMP

	; now wait for low of the DCF receiver, then start the clock!
	rcall WaitForLow
	rcall OutPORTX

	rcall PrintTimeAndDate ; show 0 sec.

	ret

; ----- add one second to the current time & date of the clock -----
ClockTick:
	; add one second
	lds	  R_TMP, t_s
	inc   R_TMP
	sts   t_s, R_TMP
	cpi   R_TMP, 60 ; if (s >= 60) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	ret

	; set second to 0
	ldi   R_TMP, 0
	sts   t_s, R_TMP

	; add one minute
	lds	  R_TMP, t_m
	inc   R_TMP
	sts   t_m, R_TMP
	cpi   R_TMP, 60 ; if (m >= 60) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	ret

	; set minute to 0
	ldi   R_TMP, 0
	sts   t_m, R_TMP

	; add one hour
	lds	  R_TMP, t_h
	inc   R_TMP
	sts   t_h, R_TMP
	cpi   R_TMP, 24 ; if (m >= 24) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	ret

	; set hour to 0
	ldi   R_TMP, 0
	sts   t_h, R_TMP

	; calculate overflow for 1ths and 10ths for days
	lds   R_TMP, d_m
    ; Jan
	cpi   R_TMP, 1
	breq  ClockTick_31days
    ; Feb
	cpi   R_TMP, 2
	breq  ClockTick_Feb
    ; Mar
	cpi   R_TMP, 3
	breq  ClockTick_31days
    ; Apr
	cpi   R_TMP, 4
	breq  ClockTick_30days
    ; May
	cpi   R_TMP, 5
	breq  ClockTick_31days
    ; Jun
	cpi   R_TMP, 6
	breq  ClockTick_30days
    ; Jul
	cpi   R_TMP, 7
	breq  ClockTick_31days
    ; Aug
	cpi   R_TMP, 8
	breq  ClockTick_31days
    ; Sep
	cpi   R_TMP, 9
	breq  ClockTick_30days
    ; Oct
	cpi   R_TMP, 10
	breq  ClockTick_31days
    ; Nov
	cpi   R_TMP, 11
	breq  ClockTick_30days
    ; Dec
	cpi   R_TMP, 12
	breq  ClockTick_31days

	; check if 28 or 29 days in feb this year
ClockTick_Feb:
	lds	  R_TMP2, d_y
	andi  R_TMP2, 3
	cpi   R_TMP2, 0 ; if 0, then 29 days in feb
	breq  ClockTick_29days
	;rjmp  ClockTick_28days

ClockTick_28days:
	ldi   R_OVERFLOW, 29
	rjmp  ClockTick_days

ClockTick_29days:
	ldi   R_OVERFLOW, 30
	rjmp  ClockTick_days

ClockTick_30days:
	ldi   R_OVERFLOW, 31
	rjmp  ClockTick_days

ClockTick_31days:
	ldi   R_OVERFLOW, 32
	rjmp  ClockTick_days

ClockTick_days:

	; add one weekday modulo 7 (1..7)
	lds	  R_TMP, d_w
	inc   R_TMP
	cpi   R_TMP, 8
	brne  ClockTick_days_ok
	ldi   R_TMP, 1

ClockTick_days_ok:
	sts   d_w, R_TMP

	; add one day
	lds	  R_TMP, d_d
	inc   R_TMP
	sts   d_d, R_TMP
	cp    R_TMP, R_OVERFLOW ; if (d >= R_OVERFLOW) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	ret

	; set day to 1
	ldi   R_TMP, 1
	sts   d_d, R_TMP

	; add one month
	lds	  R_TMP, d_m
	inc   R_TMP
	sts   d_m, R_TMP
	cpi   R_TMP, 13 ; if (s >= 13) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	ret

	; set month to 1
	ldi   R_TMP, 1
	sts   d_m, R_TMP

	ret

; ----- divide R_TMP (0..69) by 10 and store result in R_TMP2 (0..6) -----
DivideBy10:

	; assume 0 as result
	ldi   R_TMP2, 0
	cpi   R_TMP, 10
	brge  DivideBy10_1
	ret

DivideBy10_1:
	; assume 1 as result
	ldi   R_TMP2, 1
	cpi   R_TMP, 20
	brge  DivideBy10_2
	ret

DivideBy10_2:
	; assume 2 as result
	ldi   R_TMP2, 2
	cpi   R_TMP, 30
	brge  DivideBy10_3
	ret

DivideBy10_3:
	; assume 3 as result
	ldi   R_TMP2, 3
	cpi   R_TMP, 40
	brge  DivideBy10_4
	ret

DivideBy10_4:
	; assume 4 as result
	ldi   R_TMP2, 4
	cpi   R_TMP, 50
	brge  DivideBy10_5
	ret

DivideBy10_5:
	; assume 5 as result
	ldi   R_TMP2, 5
	ret

MultiplyBy10:
	mov   R_TMP2, R_TMP
	lsl   R_TMP2 ; * 2
	lsl   R_TMP2 ; * 4
	lsl   R_TMP2 ; * 8
	add   R_TMP2, R_TMP
	add   R_TMP2, R_TMP
	ret

; ----- print out one digit to a 7 segment LED display -----

PrintDigit:
	push  R_TMP
	push  R_TMP2

	; set data at port d
	in    R_TMP, PORTD
	andi  R_TMP, 0b01110000
	or    R_TMP, R_7SEG_DIGIT
	out   PORTD, R_TMP
	; set address at port b
	mov   R_TMP2, R_7SEG_DIGIT_NR
	lsl   R_TMP2
	lsl   R_TMP2
	lsl   R_TMP2
	lsl   R_TMP2
	in    R_TMP, PORTB
	andi  R_TMP, 0b00001111
	or    R_TMP, R_TMP2
	out   PORTB, R_TMP
	nop
	nop
	; let the 4067 select the current 7segment driver
	cbi   SEVENSEG_CLCK_PORT, SEVENSEG_CLCK_PIN
	nop
	sbi   SEVENSEG_CLCK_PORT, SEVENSEG_CLCK_PIN
	nop
	; now let the 4067 select a non existant 7segment
	ori   R_TMP, 0b11110000
	out   PORTB, R_TMP
	nop
	nop
	cbi   SEVENSEG_CLCK_PORT, SEVENSEG_CLCK_PIN
	nop
	sbi   SEVENSEG_CLCK_PORT, SEVENSEG_CLCK_PIN

	pop   R_TMP2
	pop   R_TMP

	ret

; ----- copy 6 bytes from SRAM at pos OVERFLOW to SRAM at pos TMP -----

CopyData:
	push  R_TMP2
	push  R_TMP	

	ldi   XH, 0
	ldi   YH, 0
	mov   XL, R_OVERFLOW
	mov   YL, R_TMP
	ldi   R_TMP2, 0

CopyData_Loop:
	ld    R_TMP, X+
	st    Y+, R_TMP

	inc   R_TMP2
	cpi   R_TMP2, 6
	brge  CopyData_Ret
	rjmp  CopyData_Loop

CopyData_Ret:
	pop   R_TMP
	pop   R_TMP2
	ret

; ----- print out the current time & date to the 7 segment LED display -----

PrintTimeAndDate:

	push  R_TMP
	push  R_TMP2
	push  R_OVERFLOW

	; Set the values that should be shown. This is the current time or time and date of some temperature max/min.
	lds   R_TMP, therm_counter
	cpi   R_TMP, 0
	breq  PrintTimeAndDate_NoDec
	dec   R_TMP
	sts   therm_counter, R_TMP

PrintTimeAndDate_NoDec:
    ; thermometer 0=show time, 1..3=show min in, 4..6=show max in, 7..9=show min out, 10..12=show max out
	
	; assume to show current time
	lds   R_TMP2, t_s ; show current sec
	sts   t_s_shown, R_TMP2
	ldi   R_OVERFLOW, therm_out
	cpi   R_TMP, 1 ; if (s >= 1) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	rjmp  PrintTimeAndDate_CopyData

	; assume to show min in
	ldi   R_TMP2, 0 ; show 0 as sec for min/max times
	sts   t_s_shown, R_TMP2
	ldi   R_OVERFLOW, minin_therm_out
	cpi   R_TMP, 4 ; if (s >= 4) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	rjmp  PrintTimeAndDate_CopyData

	; assume to show max in
	ldi   R_OVERFLOW, maxin_therm_out
	cpi   R_TMP, 7 ; if (s >= 7) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	rjmp  PrintTimeAndDate_CopyData

	; assume to show min out
	ldi   R_OVERFLOW, minout_therm_out
	cpi   R_TMP, 10 ; if (s >= 10) then go on, return otherwise
	in    R_TMP2, SREG
	sbrc  R_TMP2, 4
	rjmp  PrintTimeAndDate_CopyData

	; show max out
	ldi   R_OVERFLOW, maxout_therm_out

PrintTimeAndDate_CopyData:
	; copy 6 Bytes from SRAM beginning at R_OVERFLOW to SRAM beginning at therm_out_shown
	ldi   R_TMP, therm_out_shown

	rcall CopyData

	; convert temperatures
	lds   R_TMP, therm_in_shown
	rcall TempLookup
	sts   therm_in_shown, R_TMP
	lds   R_TMP, therm_out_shown
	rcall TempLookup
	sts   therm_out_shown, R_TMP

	; print second 10ths
	lds	  R_TMP, t_s_shown
	rcall DivideBy10
	mov   R_7SEG_DIGIT, R_TMP2
	ldi   R_7SEG_DIGIT_NR, 1
	rcall PrintDigit

	; print second 1ths
	mov   R_TMP, R_7SEG_DIGIT
	rcall MultiplyBy10
	lds	  R_TMP, t_s_shown
	sub   R_TMP, R_TMP2 ; R_TMP now stores the 1ths seconds
	mov   R_7SEG_DIGIT, R_TMP
	ldi   R_7SEG_DIGIT_NR, 0
	rcall PrintDigit

	; print minute 10ths
	lds	  R_TMP, t_m_shown
	rcall DivideBy10
	mov   R_7SEG_DIGIT, R_TMP2
	ldi   R_7SEG_DIGIT_NR, 3
	rcall PrintDigit

	; print minute 1ths
	mov   R_TMP, R_7SEG_DIGIT
	rcall MultiplyBy10
	lds	  R_TMP, t_m_shown
	sub   R_TMP, R_TMP2 ; R_TMP now stores the 1ths minutes
	mov   R_7SEG_DIGIT, R_TMP
	ldi   R_7SEG_DIGIT_NR, 2
	rcall PrintDigit

	; print hours 10ths
	lds	  R_TMP, t_h_shown
	rcall DivideBy10
	mov   R_7SEG_DIGIT, R_TMP2
	ldi   R_7SEG_DIGIT_NR, 5
	rcall PrintDigit

	; print hours 1ths
	mov   R_TMP, R_7SEG_DIGIT
	rcall MultiplyBy10
	lds	  R_TMP, t_h_shown
	sub   R_TMP, R_TMP2 ; R_TMP now stores the 1ths hours
	mov   R_7SEG_DIGIT, R_TMP
	ldi   R_7SEG_DIGIT_NR, 4
	rcall PrintDigit

	; print days 10ths
	lds	  R_TMP, d_d_shown
	rcall DivideBy10
	mov   R_7SEG_DIGIT, R_TMP2
	ldi   R_7SEG_DIGIT_NR, 7
	rcall PrintDigit

	; print days 1ths
	mov   R_TMP, R_7SEG_DIGIT
	rcall MultiplyBy10
	lds	  R_TMP, d_d_shown
	sub   R_TMP, R_TMP2 ; R_TMP now stores the 1ths days
	mov   R_7SEG_DIGIT, R_TMP
	ldi   R_7SEG_DIGIT_NR, 6
	rcall PrintDigit

	; print months 10ths
	lds	  R_TMP, d_m_shown
	rcall DivideBy10
	mov   R_7SEG_DIGIT, R_TMP2
	ldi   R_7SEG_DIGIT_NR, 9
	rcall PrintDigit

	; print months 1ths
	mov   R_TMP, R_7SEG_DIGIT
	rcall MultiplyBy10
	lds	  R_TMP, d_m_shown
	sub   R_TMP, R_TMP2 ; R_TMP now stores the 1ths months
	mov   R_7SEG_DIGIT, R_TMP
	ldi   R_7SEG_DIGIT_NR, 8
	rcall PrintDigit

PrintTimeAndDate_TempIn:
	; print temp in 10ths
	lds	  R_TMP, therm_in_shown

	cpi   R_TMP, NOTEMP_VALUE
	breq  PrintTimeAndDate_TempInHide

	rcall DivideBy10
	mov   R_7SEG_DIGIT, R_TMP2
	mov   R_OVERFLOW, R_TMP2 ; misuse R_OVERFLOW
	; if zero, print out a 10, which turns off this digit because of the CMOS4543
	cpi   R_7SEG_DIGIT, 1
	brge  PrintTimeAndDate_ok1
	ldi   R_7SEG_DIGIT, 10
PrintTimeAndDate_ok1:
	ldi   R_7SEG_DIGIT_NR, 11
	rcall PrintDigit

	; print temp in 1ths
	mov   R_TMP, R_OVERFLOW
	rcall MultiplyBy10
	lds	  R_TMP, therm_in_shown
	sub   R_TMP, R_TMP2 ; R_TMP now stores the 1ths months
	mov   R_7SEG_DIGIT, R_TMP
	ldi   R_7SEG_DIGIT_NR, 10
	rcall PrintDigit
	rjmp  PrintTimeAndDate_TempOut

PrintTimeAndDate_TempInHide: ; show nothing
	ldi   R_7SEG_DIGIT, 10 ; 4543 makes it display nothing
	ldi   R_7SEG_DIGIT_NR, 11
	rcall PrintDigit
	ldi   R_7SEG_DIGIT_NR, 10
	rcall PrintDigit

PrintTimeAndDate_TempOut:
	; print temp out 10ths

	; assume minus sign is off
	lds   R_DELAY1, portx ; use R_DELAY1 as portx value
	andi  R_DELAY1, 0b11111001

	; temp is positive?
	lds	  R_TMP, therm_out_shown

	cpi   R_TMP, NOTEMP_VALUE
	breq  PrintTimeAndDate_TempOutHide

	cpi   R_TMP, 128
	brlo  PrintTimeAndDate_TempIsPositive
	; negative, switch minus sign on
	ori   R_DELAY1, 0b00000110
	neg   R_TMP
	sts   therm_out_shown, R_TMP ; save the temp as positive value

PrintTimeAndDate_TempIsPositive:
	rcall DivideBy10
	mov   R_7SEG_DIGIT, R_TMP2
	; if zero, print out a 10, which turns off this digit because of the CMOS4543
	cpi   R_7SEG_DIGIT, 1
	brge  PrintTimeAndDate_10thExist
	; no 10th
	ldi   R_7SEG_DIGIT, 10
	andi  R_DELAY1, 0b11111011 ; switch extra minus sign off
	rjmp  PrintTimeAndDate_ok2
PrintTimeAndDate_10thExist:
	ori   R_DELAY1, 0b00000010
	; switch minus sign of 10th display off, if R_7SEG_DIGIT is in {1, 7}
	cpi   R_7SEG_DIGIT, 1
	breq  PrintTimeAndDate_10thMinusOff
	cpi   R_7SEG_DIGIT, 7
	breq  PrintTimeAndDate_10thMinusOff
	rjmp  PrintTimeAndDate_ok2

PrintTimeAndDate_10thMinusOff:
	andi  R_DELAY1, 0b11111101 ; switch 10th minus sign off

PrintTimeAndDate_ok2:
	ldi   R_7SEG_DIGIT_NR, 13
	rcall PrintDigit

	; print temp out 1ths
	mov   R_TMP, R_TMP2
	rcall MultiplyBy10
	lds	  R_TMP, therm_out_shown
	sub   R_TMP, R_TMP2 ; R_TMP now stores the 1ths months
	mov   R_7SEG_DIGIT, R_TMP
	ldi   R_7SEG_DIGIT_NR, 12
	rcall PrintDigit
	rjmp  PrintTimeAndDate_PrintMinusSign

PrintTimeAndDate_TempOutHide: ; show nothing
	ldi   R_7SEG_DIGIT, 10 ; 4543 makes it display nothing
	ldi   R_7SEG_DIGIT_NR, 13
	rcall PrintDigit
	ldi   R_7SEG_DIGIT_NR, 12
	rcall PrintDigit

PrintTimeAndDate_PrintMinusSign:
	sts   portx, R_DELAY1
	rcall OutPORTX


	pop   R_OVERFLOW
	pop   R_TMP2
	pop   R_TMP
	ret

; ----- lookup the temp for the measured time in EEPROM -----
; IN:  R_TMP (measured time)
; OUT: R_TMP (temperature, signed)
; REGISTER USAGE: none

TempLookup:
	cpi  R_TMP, NOTEMP_VALUE
	breq TempLookup_Ret
	
	push R_TMP2
	push R_OVERFLOW

	; set EEPROM read addres low byte (high byte is always 0, because eeprom not used somewhere else)
	ldi   R_TMP2, 0

TempLookup_Loop:
	out   EEARL, R_TMP2
	sbi   EECR, EERE ;set EEPROM Read strobe

	;This instruction takes 4 clock cycles since
	;it halts the CPU for two clock cycles

	in    R_OVERFLOW, EEDR ;get data
	
	cp	  R_OVERFLOW, R_TMP
	brlo  TempLookup_Found
	inc   R_TMP2
	rjmp  TempLookup_Loop      ; repeat until value found

TempLookup_Found:
	; R_TMP2 is the address in EEPROM last read
	; let's substract 20, then we have the temperature in °C (because value for -20°C is stored in EEPROM location 0)
	subi  R_TMP2, 20
	mov   R_TMP, R_TMP2

	pop   R_OVERFLOW
	pop   R_TMP2

TempLookup_Ret:
	ret

; ----- measure the temperature -----

GetTempRaw:
	rcall Delay890ms

	; disable charging capacitor
	sbi   LED_PORT, LED_PIN

	ldi   R_TMP, 60
	sts   therm_in, R_TMP
	sts   therm_out, R_TMP

	; now count till the temp input is high
	ldi   R_TMP, 0

GetTempRaw_Count:
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	inc   R_TMP

	sbic  TEMP1_IN_PORT, TEMP1_IN_PIN ; Skip next inst. if bit 0 in Port D set
	rjmp  GetTempRaw_Count

	; charge capacitor
	cbi   LED_PORT, LED_PIN

	; lower 4 bit
	mov   R_TMP2, R_TMP
	andi  R_TMP2, 0b00001111
	sts   t_s, R_TMP2

	; higher 4 bit
	mov   R_TMP2, R_TMP
	lsr   R_TMP2
	lsr   R_TMP2
	lsr   R_TMP2
	lsr   R_TMP2
	sts   t_m, R_TMP2

	rcall PrintTimeAndDate
	
	rjmp GetTempRaw

; ----- measure the temperature -----

GetTemp:
	; disable charging capacitor
	sbi   LED_PORT, LED_PIN

	; now count till the temp input is high
	ldi   R_TMP, 0
	ldi   R_TMP2, 0

GetTemp_Count:
	sbis  TEMP1_IN_PORT, TEMP1_IN_PIN ; Skip next inst. if bit in Port cleared
	rjmp  GetTemp_1Done
	sbis  TEMP2_IN_PORT, TEMP2_IN_PIN ; Skip next inst. if bit in Port cleared
	rjmp  GetTemp_2Done

	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us

	inc   R_TMP
	inc   R_TMP2
	rjmp  GetTemp_Count

GetTemp_1Done:
	sbis  TEMP2_IN_PORT, TEMP2_IN_PIN ; Skip next inst. if bit in Port cleared
	rjmp  GetTemp_BothDone

	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us

	inc   R_TMP2
	rjmp  GetTemp_1Done

GetTemp_2Done:
	sbis  TEMP1_IN_PORT, TEMP1_IN_PIN ; Skip next inst. if bit in Port cleared
	rjmp  GetTemp_BothDone

	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us
	rcall Delay100us

	inc   R_TMP
	rjmp  GetTemp_2Done

GetTemp_BothDone:

	; charge capacitor
	cbi   LED_PORT, LED_PIN

	sts   therm_in, R_TMP
	sts   therm_out, R_TMP2

GetTemp_CheckMaxIn: ; is temp > max in temp?
	lds   R_TMP2, therm_in
	lds   R_TMP, maxin_therm_in ; if TMP <= TMP2 then save, if TMP2 < TMP, then branch
	cp    R_TMP, R_TMP2
	brlo  GetTemp_CheckMinIn
	
	; overwrite max in temp
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, maxin_therm_out
	rcall CopyData
	ldi   R_TMP, NOTEMP_VALUE ; store NOTEMP_VALUE in SRAM so that PrintTimeAndDate doesn't show this temp
	sts   maxin_therm_out, R_TMP

GetTemp_CheckMinIn: ; is temp < min in temp?
	lds   R_TMP, minin_therm_in
	cp    R_TMP2, R_TMP
	brlo  GetTemp_CheckMaxOut
	
	; overwrite max in temp
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, minin_therm_out
	rcall CopyData
	ldi   R_TMP, NOTEMP_VALUE ; store NOTEMP_VALUE in SRAM so that PrintTimeAndDate doesn't show this temp
	sts   minin_therm_out, R_TMP

GetTemp_CheckMaxOut: ; is temp > max in temp?
	lds   R_TMP2, therm_out
	lds   R_TMP, maxout_therm_out
	cp    R_TMP, R_TMP2
	brlo  GetTemp_CheckMinOut
	
	; overwrite max out temp
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, maxout_therm_out
	rcall CopyData
	ldi   R_TMP, NOTEMP_VALUE ; store NOTEMP_VALUE in SRAM so that PrintTimeAndDate doesn't show this temp
	sts   maxout_therm_in, R_TMP

GetTemp_CheckMinOut: ; is temp < min in temp?
	lds   R_TMP, minout_therm_out
	cp    R_TMP2, R_TMP
	brlo  GetTemp_Ret
	
	; overwrite max in temp
	ldi   R_OVERFLOW, therm_out
	ldi   R_TMP, minout_therm_out
	rcall CopyData
	ldi   R_TMP, NOTEMP_VALUE ; store NOTEMP_VALUE in SRAM so that PrintTimeAndDate doesn't show this temp
	sts   minout_therm_in, R_TMP

GetTemp_Ret:
	ret

; ----- check if it's sync time (So. 4:00:50 h), result in R_TMP (1 if sync time, 0 otherwiese) -----
CheckSyncTime:
	lds	  R_TMP2, t_s
	cpi   R_TMP2, SYNCTIME_S
	brne  CheckSyncTime_False

	lds	  R_TMP2, t_m
	cpi   R_TMP2, SYNCTIME_M
	brne  CheckSyncTime_False

	lds	  R_TMP2, t_h
	cpi   R_TMP2, SYNCTIME_H
	brne  CheckSyncTime_False

	lds	  R_TMP2, d_w
	cpi   R_TMP2, SYNCTIME_W
	brne  CheckSyncTime_False

CheckSyncTime_True:
	ldi   R_TMP, 1
	ret

CheckSyncTime_False:
	ldi   R_TMP, 0
	ret

; ----- start of main program -----
Demo:
	rcall ClearCurrentTimeAndTemp
	rcall Reset_Temp
DemoLoop:
	rcall ClockTick
	rcall PrintTimeAndDate
	rcall Delay5ms
	rjmp  DemoLoop

Start:
	rcall ScanTime
	rcall GetTemp
	rcall Reset_Temp

MainLoop:
	rcall ClockTick
	rcall WaitForTick
	rcall PrintTimeAndDate

	; check if 04:00:50 sun
	rcall CheckSyncTime
	sbrc  R_TMP, 0
	rcall ScanTime

	; check if ??:??:00
	lds	  R_TMP, t_s
	cpi   R_TMP, 0
	brne  MainLoop
	rcall GetTemp

	rjmp  MainLoop