DCF77.asm


1
;################################################################################
2
;#                                        #
3
;#                  Funkuhr                    #
4
;#                                                                              #
5
;# Ressourcen:                                                                  #
6
;# atMEGA8 @ 4MHz                                                               #
7
;# ELV Zeitzeichenempfänger an PD7                        #
8
;# LCD an Port B nach Tutorial von www.mikrocontroller.net im 4Bit Modus        #
9
;# 13 Register r2-r4, r11, r15-r23                                              #
10
;# Timer1 im Comparemodus löst alle 10msec eine Interrupt aus          #
11
;# SRAM Adressen von 0x60 bis  0x6C als Puffer für den Kausalitätstest      #
12
;#                                                                              #
13
;# Was macht es:                                                                #
14
;# Das ist eine FunkUhr die das Zeitzeichen DCF77 empängt auswertet und anzeigt  #
15
;# An PC0 hängt eine LED(rot) die leuchtet wenn die Uhr aktiv ist        #
16
;# An PC1 hängt eine LED(gelb) diese blinkt im Rhythmus des Zeitzeichens    #
17
;# wenn die Uhr nicht synchron läuft                      #
18
;# An PC2 hängt eine LED(grün) diese leuchtet wenn die Uhr synchron läuft    #
19
;#                                        #
20
;# Kontakt: cabal@thelastinstance.de                                            #
21
;#                                        #
22
;# Homepage: http://www.thelastinstance.de                                      #
23
;#                                                                              #
24
;# Version: 2.00                                                                #
25
;#                                                                              #
26
;################################################################################
27
28
.include "m8def.inc"        ; Definitionsdatei einbinden
29
30
; Speicheradressen im SRAM
31
.dseg
32
.org  0x60
33
; Werte des aktuellen Zeitzeichens
34
dcfmin_1:  .byte  1        ; DCF Minute
35
dcfhour_1:  .byte  1        ; DCF Stunde
36
dcfday_1:  .byte  1        ; DCF Tag
37
dcfwday_1:  .byte  1        ; DCF Wochentag
38
dcfmonth_1:  .byte  1        ; DCF Monat
39
dcfyear_1:  .byte  1        ; DCF Jahr
40
; Werte des vorherigen Zeitzeichens
41
dcfmin_2:  .byte  1        ; DCF Minute
42
dcfhour_2:  .byte  1        ; DCF Stunde
43
dcfday_2:  .byte  1        ; DCF Tag
44
dcfwday_2:  .byte  1        ; DCF Wochentag
45
dcfmonth_2:  .byte  1        ; DCF Monat
46
dcfyear_2:  .byte  1        ; DCF Jahr
47
48
; Register-Definition/Beschreibung
49
.def sekunde = r2          ; enthält die sekunde b0-3=einer b4-7=zehner
50
.def minute  = r3          ; enthält die minute b0-3=einer b4-7=zehner
51
.def stunde  = r4          ; enthält die stunde b0-3=einer b4-7=zehner
52
53
.def dcfcnt  = r11          ; DCF77-Zähler, Impuls-Zählung (Zyklen 10ms)
54
.def intreg  = r15          ; Zwischenspeicher für SREG
55
.def temp1   = r16          ; Allround-Variable
56
.def temp2   = r17          ; 2te Allround-Variable
57
.def temp3   = r18          ; 3te Allround-Variable
58
.def secount = r19          ; Zähler zur Sekunden Erkennung
59
.def flags   = r20          ; Register flags Inhalt:
60
                  ;   Bit 0: akueller DCF77-Zustand
61
                  ;   Bit 1: vorheriger DCF77-Zustand
62
                  ;   Bit 2: Beginn einer neuen Minute
63
                  ;   Bit 3: set wenn gültige Zeit empfangen
64
                  ;   Bit 4: 1 = sync / 0 = unsync
65
                  ;   Bit 5: set wenn eine Sekunde vorbei
66
                  ;   Bit 6: set wenn eine Minute vorbei
67
                  ;   Bit 7: set wenn eine Stunde vorbei
68
.def timeout = r21          ; Übergabe an die Zeitausgabe
69
.def dcfbuf  = r22          ; Puffer für eingehende DCF Zeichen
70
.def timeslot= r23          ; Zähler zur Zeitschlitzerkennung
71
72
; Konstanten festlegen
73
.equ tm1end = 40000          ; Timer1 Endwert (entspricht 100 Interrupts/s
74
                  ; oder Zykluszeit 10ms)
75
76
77
78
; Interrupt Vektoren
79
.cseg                ; Codesegment
80
.org 0x00              ; Interrupt Vektoren ab Adresse
81
                  ; 0x00 im Codesegment des AVR
82
reset:      rjmp start      ; Programmstart
83
exint0:      reti        ; nicht genutzt
84
exint1:      reti        ; nicht genutzt
85
timer2_comp:  reti        ; nicht genutzt
86
timer2_ovf:    reti        ; nicht genutzt
87
timer1_capt:  reti        ; nicht genutzt
88
timer1_compa:  rjmp t1int      ; Timer1 Interrupt alle 10msec
89
timer1_compb:  reti        ; nicht genutzt
90
timer1_ovf:    reti        ; nicht genutzt
91
timer0_ovf:    reti        ; nicht genutzt
92
spi_stc:    reti        ; nicht genutzt
93
usart_rxc:    reti        ; nicht genutzt
94
uart_udre:    reti        ; nicht genutzt
95
usart_txc:    reti        ; nicht genutzt
96
adc_complete:  reti        ; nicht genutzt
97
ee_rdy:      reti        ; nicht genutzt
98
ana_comp:    reti        ; nicht genutzt
99
twi:      reti        ; nicht genutzt
100
spm_rdy:    reti        ; nicht genutzt
101
102
103
; Initalisierung
104
start:
105
  wdr                ; Watchdog zurücksetzen
106
  ldi  temp1, 1<<WDE        ; Watchdog aktivieren, 15ms
107
  out  wdtcr, temp1        ; ausgeben
108
109
                  ; Stackpointer initialisieren
110
  ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
111
  out SPL, temp1
112
  ldi temp1, HIGH(RAMEND)      ; HIGH-Byte der obersten RAM-Adresse
113
  out SPH, temp1
114
115
  ldi temp1, 0xFF          ; Port B = Ausgang
116
  out DDRB, temp1
117
118
  clr secount            ; Sekundenzähler auf 0
119
  clr flags            ; flags auf 0
120
  clr dcfbuf            ; dcfbuf auf null
121
  clr timeslot          ; timeslot auf null
122
  clr sekunde            ; setze sekunde auf null
123
  clr minute            ; setze minute auf null
124
  clr stunde            ; setze stunde auf null
125
126
  ldi temp1, 0x00          ; temp1 mit 0x00 laden
127
  out DDRD, temp1          ; PortD ist ein Eingang
128
  ldi temp1, 0xFF          ; lade FF ins register temp
129
  out PORTD, temp1        ; aktiviere die internen Pull-Ups von PD
130
  ldi temp1, 0xFF          ; temp1 mit 0xFF laden
131
  out DDRC, temp1          ; PortC ist ein Ausgang
132
  out PORTC, temp1        ; Alle LEDs aus
133
134
  ldi  temp1, high(tm1end)      ; Timer1 Endwert1 H
135
  out  ocr1ah, temp1        ; ausgeben
136
  ldi  temp1, low(tm1end)      ; Timer1 Endwert1 L
137
  out  ocr1al, temp1        ; ausgeben
138
  clr  temp1            ; Timer1 kein PWM, kein Comp-Out
139
  out  tccr1a, temp1
140
  ldi  temp1, (1<<WGM12)+(1<<CS10)  ; Timer1 Löschen nach Vergleich
141
  out  tccr1b, temp1        ; und Vorteiler=1 setzen
142
143
  rcall lcd_init          ; Display initialisieren
144
  rcall lcd_clear          ; Display löschen
145
146
;  - Interrupt aktivieren
147
  clr  temp1
148
  out  gimsk, temp1        ; externe Interrupts sperren
149
  ldi  temp1, 1<<OCIE1A
150
  out  timsk, temp1        ; Timer1 Vergleich1 freigeben
151
  sei
152
153
  cbi PORTC,0            ; powerLED(rot) einschalten
154
  sbi PORTC,2            ; sync LED(grün) aus = Uhr unsynchron
155
  rcall pon_mess          ; Anzeigen der PowerOn Message
156
157
premain:              ; Vor start des Haupprgramms
158
  bst flags, 2          ; auf Minutenbeginn warten
159
  brtc premain          ; branch if T is cleared
160
  ldi  temp1, 0b11111011      ; Bitmaske in temp laden
161
  and  flags, temp1        ; logisch und um bit 2 zu löschen
162
  rcall lcd_clear          ; Display löschen
163
164
; Hauptprogramm
165
main:
166
  bst flags,5            ; prüfen ob eine Sekunde um ist
167
  brtc mainjmp0          ; wenn nicht dann ende
168
  rcall incsek          ; sonst starte sekunden handling
169
170
  bst flags,6            ; prüfen ob eine Minute um ist
171
  brtc mainjmp1          ; wenn nicht dann ende
172
  rcall incmin          ; sonst starte minuten handling
173
174
  bst flags,7            ; prüfen ob eine Stunde um ist
175
  brtc mainjmp1          ; wenn nicht dann ende
176
  rcall incstd          ; sonst starte stunden handling
177
178
mainjmp1:
179
  rcall lcd_cursorhome      ; setze Cursor an den Anfang erste Zeile
180
  rcall header          ; ">>  "ins Display schreiben
181
  mov timeout, stunde        ; Stunden nach timeout
182
  rcall timeout_func        ; Stunden ans Display senden
183
  rcall doubledot          ; schreibt ein doppelpunkt ins Display
184
  mov timeout, minute        ; Minuten nach timeout
185
  rcall timeout_func        ; Minuten ans Display senden
186
  rcall doubledot          ; singledot schreibt einen punkt ins Display
187
  mov timeout, sekunde      ; Sekunden nach timeout
188
  rcall timeout_func        ; Sekunden ans Display senden
189
  rcall trailer          ; "  <<"ins Display schreiben
190
mainjmp0:
191
rjmp main
192
193
; Timer1 Interruptroutine
194
t1int:
195
  in  intreg,sreg          ; CPU-Flags sichern
196
  wdr                ; Watchdog zurücksetzen
197
  inc secount            ; sekundenzähler um eins erhöhen
198
  cpi secount, 0x64        ; ist eine sekunde vorbei
199
  brne t1jmp0            ; wenn nicht dann ende
200
  clr secount            ; ansonsten secount auf null
201
  set                ; setze das T-Flag
202
  bld flags,5            ; wert von T nach Bit 5 in flags
203
t1jmp0:
204
  sbi PORTC,1            ; setze portc1 gelbe led aus
205
  bst flags,4            ; wenn die Uhr synchron ist
206
  brts t1jmp1            ; überspringe dcfreceive
207
  rcall dcfreceive        ; DCF Zeichenerkennung starten
208
t1jmp1:
209
  out  sreg,intreg          ; CPU-Flags wiederherstellen
210
reti
211
212
; Wandelt DCF Zeichen in 0 und 1 um detektiert das Minutenende
213
dcfreceive:
214
  in temp1, PIND          ; lese DCF Status
215
  bst temp1, 7          ; DCF77-Status holen
216
  bld flags, 0          ; und in Flags speichern
217
  inc dcfcnt            ; DCF77-Zähler erhöhen
218
  bst flags, 0          ; akuellen DCF77-Status prüfen
219
  brts recjmp1          ; kein Signal -> springe zu recjmp1
220
  cbi PORTC,1            ; lösche portc1 gelbe led an
221
  bst flags, 1          ; sonst vorh. DCF-Status prüfen
222
  brtc recjmp2          ; vorher kein Signal? springe zu recjmp2
223
  ldi temp1, 150          ; lade temp mit 150
224
  cp dcfcnt, temp1        ; länger als 1,5 sek kein signal?
225
  brcs recjmp3          ; nein -> springe zu recjmp3
226
  bld flags, 2          ; sonst Rahmenende setzen
227
  clr dcfbuf            ; dcfbuf auf null
228
  clr timeslot          ; timeslot auf null
229
  bst flags, 3          ; prüfen ob die Zeit vollständig ist
230
  brtc recjmp3          ; wenn zeit nicht vollständig dann springen
231
  lds minute, dcfmin_1      ; speicher nach register
232
  lds stunde, dcfhour_1      ; speicher nach register
233
  rcall dateout          ; Datum ausgeben
234
  ldi  temp1, 0b11110111      ; Bitmaske in temp1 laden
235
  and  flags, temp1        ; logisch und um bit 3 zu löschen
236
  cbi PORTC,2            ; grüne LED an uhr synchron
237
  set               ; t flag setzen
238
  bld flags,4            ; Uhr auf synchron setzen
239
recjmp3:
240
  clr dcfcnt            ; DCF77-Zähler löschen
241
  rjmp recjmp2          ; Ende
242
recjmp1:
243
  sbi PORTC,1            ; setze portc1 gelbe led aus
244
  bst  flags,1            ; vorherigen DCF-Status prüfen
245
  brts recjmp2          ; vorher kein Signal? ja -> Ende
246
  ldi temp1, 15          ; wie lang war das Signal?
247
  cp dcfcnt, temp1        ; Signal kürzer als 150msec ?
248
  brcs recjmp4          ; ja -> dann springe zu recjmp4
249
  ; Aktion für eine empfangene Eins
250
  sec                ; set carry
251
  ror dcfbuf            ; schiebe carry oben rein
252
  inc timeslot          ; erhöhe timeslot um eins
253
  rcall dcf_handling        ; DCF Daten bearbeiten
254
  rjmp recjmp2          ; ende
255
recjmp4:
256
  ; Aktion für eine empfangene Null
257
  clc                ; clear carry
258
  ror dcfbuf            ; schiebe carry oben rein
259
  inc timeslot          ; erhöhe timeslot um eins
260
  rcall dcf_handling        ; DCF Daten bearbeiten
261
recjmp2:
262
  bst flags, 0          ; aktuellen DCF77-Status holen
263
  bld flags, 1          ; und als neuen Status speichern
264
  ret
265
266
; Routine zum Stundenhandling
267
incstd:
268
  clt                ; lösche t flag
269
  bld flags,4            ; setze Uhr auf unsynchron
270
  sbi PORTC,2            ; grüne LED aus uhr unsynchron
271
  ldi timeslot, 0x02        ; verhindert verfrühtes sekunden sync
272
  ldi  temp1, 0b01111111      ; Bitmaske in temp laden
273
  and  flags, temp1        ; logisch und um bit 2 zu löschen
274
  inc stunde            ; erhöhe stunde um eins
275
  mov temp1, stunde        ; stunde nach temp1
276
  ldi  temp2, 0b00001111      ; Bitmaske in temp laden
277
  and  temp1, temp2        ; logisch und um obere 4 bit zu löschen
278
  cpi temp1, 0x0A          ; ist stunde 10 (einerüberlauf)
279
  brne incstdjmp0          ; wenn nicht dann springen
280
  ldi  temp1, 0b11110000      ; sonst Bitmaske in temp laden
281
  and  stunde, temp1        ; logisch und um untere 4 bit zu löschen
282
  swap stunde            ; nibbles verdrehen
283
  inc stunde            ; eins dazu
284
  swap stunde            ; nibbles zurück
285
incstdjmp0:
286
  mov temp1, stunde        ; stunde nach temp1
287
  cpi temp1, 0x24          ; ist Stunde = 24
288
  brne incstdjmp1          ; wenn nicht dann springen
289
  clr stunde            ; sonst Stunde auf null
290
incstdjmp1:
291
  ret
292
293
; Routine zum Minutenhandling
294
incmin:
295
  ldi  temp1, 0b10111111      ; Bitmaske in temp laden
296
  and  flags, temp1        ; logisch und um bit 1 zu löschen
297
  inc minute            ; erhöhe minute um eins
298
  mov temp1, minute        ; minute nach temp1
299
  ldi  temp2, 0b00001111      ; Bitmaske in temp laden
300
  and  temp1, temp2        ; logisch und um obere 4 bit zu löschen
301
  cpi temp1, 0x0A          ; ist minute 10 (einerüberlauf)
302
  brne incminjmp0          ; wenn nicht dann springen
303
  ldi  temp1, 0b11110000      ; sonst Bitmaske in temp laden
304
  and  minute, temp1        ; logisch und um untere 4 bit zu löschen
305
  swap minute            ; nibbles verdrehen
306
  inc minute            ; eins dazu
307
  mov temp1, minute        ; minute nach temp1
308
  ldi  temp2, 0b00001111      ; Bitmaske in temp laden
309
  and  temp1, temp2        ; logisch und um obere 4 bit zu löschen
310
  cpi temp1, 0x06          ; ist sekunde gleich 6 (zehnerüberlauf)
311
  brne incminjmp1          ; wenn nicht dann springen
312
  ldi  temp2, 0b11110000      ; Bitmaske in temp laden
313
  and  minute, temp2        ; logisch und um obere 4 bit zu löschen
314
  set
315
  bld flags,7            ; wert von T nach Bit 7 in flags
316
incminjmp1:
317
  swap minute
318
incminjmp0:
319
ret
320
321
; Routine zum Sekundenhandling
322
incsek:
323
  ldi  temp1, 0b11011111      ; Bitmaske in temp laden
324
  and  flags, temp1        ; logisch und um bit 0 zu löschen
325
  inc sekunde            ; erhöhe sekunde um eins
326
  mov temp1, sekunde        ; sekunde nach temp1
327
  ldi  temp2, 0b00001111      ; Bitmaske in temp laden
328
  and  temp1, temp2        ; logisch und um obere 4 bit zu löschen
329
  cpi temp1, 0x0A          ; ist sekunde 10 (einerüberlauf)
330
  brne incsekjmp0          ; wenn nicht dann springen
331
  ldi  temp1, 0b11110000      ; Bitmaske in temp laden
332
  and  sekunde, temp1        ; logisch und um untere 4 bit zu löschen
333
  swap sekunde          ; nibbles verdrehen
334
  inc sekunde            ; eins dazu
335
  mov temp1, sekunde        ; sekunde nach temp1
336
  ldi  temp2, 0b00001111      ; Bitmaske in temp laden
337
  and  temp1, temp2        ; logisch und um obere 4 bit zu löschen
338
  cpi temp1, 0x06          ; ist sekunde gleich 6 (zehnerüberlauf)
339
  brne incsekjmp1          ; wenn nicht dann springen
340
  ldi  temp2, 0b11110000      ; Bitmaske in temp laden
341
  and  sekunde, temp2        ; logisch und um obere 4 bit zu löschen
342
  set
343
  bld flags,6            ; wert von T nach Bit 6 in flags
344
incsekjmp1:
345
  swap sekunde
346
incsekjmp0:
347
  ret
348
349
; schreibt ein doppelpunkt ins Display
350
doubledot:
351
  ldi temp1, 0x3A
352
  rcall lcd_data
353
ret
354
355
; schreibt einen punkt ins Display
356
singledot:
357
  ldi temp1, 0x2E
358
  rcall lcd_data
359
ret
360
361
; ">>  "ins Display schreiben
362
header:
363
  ldi temp1, 0x3E
364
  rcall lcd_data
365
  ldi temp1, 0x3E
366
  rcall lcd_data
367
  ldi temp1, 0x20
368
  rcall lcd_data
369
  ldi temp1, 0x20
370
  rcall lcd_data
371
ret
372
373
374
; "  <<"ins Display schreiben
375
trailer:
376
  ldi temp1, 0x20
377
  rcall lcd_data
378
  ldi temp1, 0x20
379
  rcall lcd_data
380
  ldi temp1, 0x3C
381
  rcall lcd_data
382
  ldi temp1, 0x3C
383
  rcall lcd_data
384
ret
385
386
; Ausgeben der Zeit
387
timeout_func:
388
  swap timeout
389
  mov temp1, timeout        ; sekunde nach temp1 kopieren
390
  ldi  temp2, 0b00001111      ; Bitmaske in temp laden
391
  and  temp1, temp2        ; logisch und um obere 4 bit zu löschen
392
  ldi temp2, 0x30          ; lade temp2 mit 0x30
393
  add temp1, temp2        ; 0x30 plus temp1 offset zu ascii 0
394
  rcall lcd_data          ; temp1 ans display
395
  swap timeout
396
  mov temp1, timeout        ; sekunde nach temp1 kopieren
397
  ldi  temp2, 0b00001111      ; Bitmaske in temp laden
398
  and  temp1, temp2        ; logisch und um obere 4 bit zu löschen
399
  ldi temp2, 0x30          ; lade temp2 mit 0x30
400
  add temp1, temp2        ; 0x30 plus temp1 offset zu ascii 0
401
  rcall lcd_data          ; temp1 ans display
402
ret
403
404
; sendet ein Datenbyte an das LCD
405
lcd_data:
406
  mov temp2, temp1        ; "Sicherungskopie" für
407
                                 ; die Übertragung des 2.Nibbles
408
  swap temp1                     ; Vertauschen
409
  andi temp1, 0b00001111         ; oberes Nibble auf Null setzen
410
  sbr temp1, 1<<4                ; entspricht 0b00010000
411
  out PORTB, temp1              ; ausgeben
412
  rcall lcd_enable               ; Enable-Routine aufrufen
413
                                 ; 2. Nibble, kein swap da es schon
414
                                 ; an der richtigen stelle ist
415
  andi temp2, 0b00001111         ; obere Hälfte auf Null setzen 
416
  sbr temp2, 1<<4                ; entspricht 0b00010000
417
  out PORTB, temp2               ; ausgeben
418
  rcall lcd_enable               ; Enable-Routine aufrufen
419
  rcall delay50us                ; Delay-Routine aufrufen
420
  ret                            ; zurück zum Hauptprogramm
421
; sendet einen Befehl an das LCD
422
lcd_command:                        ; wie lcd_data, nur ohne RS zu setzen
423
  mov temp2, temp1
424
  swap temp1
425
  andi temp1, 0b00001111
426
  out PORTB, temp1
427
  rcall lcd_enable
428
  andi temp2, 0b00001111
429
  out PORTB, temp2
430
  rcall lcd_enable
431
  rcall delay50us
432
  ret
433
434
; erzeugt den Enable-Puls
435
lcd_enable:
436
  sbi PORTB, 5                   ; Enable high
437
  nop                            ; 3 Taktzyklen warten
438
  nop
439
  nop
440
  cbi PORTB, 5                   ; Enable wieder low
441
  ret                            ; Und wieder zurück                     
442
443
; Pause nach jeder Übertragung
444
delay50us:                          ; 50us Pause
445
  ldi  temp1, $42
446
delay50us_:
447
  dec  temp1
448
  brne delay50us_
449
  ret                            ; wieder zurück
450
451
; Längere Pause für manche Befehle
452
delay5ms:                           ; 5ms Pause
453
  ldi  temp1, 0x21        ; 0x21
454
WGLOOP0:
455
  wdr                ; Watchdog zurücksetzen
456
  ldi  temp2, 0xC9        ; 0xC9
457
WGLOOP1:
458
  dec  temp2
459
  brne WGLOOP1
460
  dec  temp1
461
  brne WGLOOP0
462
  ret                            ; wieder zurück
463
464
; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
465
lcd_init:
466
  ldi  temp3,50
467
powerupwait:
468
  rcall  delay5ms
469
  dec  temp3
470
  brne  powerupwait
471
  ldi temp1, 0b00000011          ; muss 3mal hintereinander gesendet
472
  out PORTB, temp1               ; werden zur Initialisierung
473
  rcall lcd_enable               ; 1
474
  rcall delay5ms
475
  rcall lcd_enable               ; 2
476
  rcall delay5ms
477
  rcall lcd_enable               ; und 3!
478
  rcall delay5ms
479
  ldi temp1, 0b00000010          ; 4bit-Modus einstellen
480
  out PORTB, temp1
481
  rcall lcd_enable
482
  rcall delay5ms
483
  ldi temp1, 0b00101000          ; noch was einstellen...
484
  rcall lcd_command
485
  ldi temp1, 0b00001100          ; ...nochwas...
486
  rcall lcd_command
487
  ldi temp1, 0b00000100          ; endlich fertig
488
  rcall lcd_command
489
  ret
490
491
; Sendet den Befehl zur Löschung des Displays
492
lcd_clear:
493
  ldi temp1, 0x01           ; Display löschen
494
  rcall lcd_command
495
  rcall delay5ms
496
  ret
497
498
; Returns cursor to home position
499
lcd_cursorhome:
500
  ldi temp1, 0x02           ; Cursor Home
501
  rcall lcd_command
502
  rcall delay5ms
503
  ret
504
505
; DCF Daten bearbeiten
506
dcf_handling:
507
  cpi timeslot, 0x01        ; erstes Zeichen Sekunde Null
508
  brne dcfjmp            ; wenn nicht den springen
509
  clr sekunde            ; sonst sekunde löschen
510
dcfjmp:                ; die nächsten 20 zeichen ignorieren
511
  cpi timeslot, 0x15        ; 21 Zeichen empfangen
512
  brne dcfjmp0          ; wenn nicht den springen
513
  clr dcfbuf            ; sonst puffer löschen
514
dcfjmp0:              ; als nächstes kommen die minuten
515
  cpi timeslot, 0x1C        ; 28 Zeichen empfangen
516
  brne dcfjmp1          ; wenn nicht den springen
517
  clc                ; sonst Carryflag löschen
518
  ror dcfbuf            ; noch eins weiter schieben
519
  sts dcfmin_1, dcfbuf      ; die minute in ihren Speicher laden
520
  clr dcfbuf            ; puffer löschen
521
dcfjmp1:              ; jetzt sind die stunden dran
522
  cpi timeslot, 0x23        ; 35 Zeichen empfangen
523
  brne dcfjmp2          ; wenn nicht den springen
524
  clc                ; sonst Carryflag löschen
525
  ror dcfbuf            ; noch eins weiter schieben
526
  clc                ; sonst Carryflag löschen
527
  ror dcfbuf            ; noch eins weiter schieben
528
  sts dcfhour_1, dcfbuf      ; die stunde in ihren Speicher laden
529
  clr dcfbuf            ; puffer löschen
530
dcfjmp2:              ; jetzt der tag
531
  cpi timeslot, 0x2A        ; 42 Zeichen empfangen
532
  brne dcfjmp3          ; wenn nicht den springen
533
  clc                ; sonst Carryflag löschen
534
  ror dcfbuf            ; noch eins weiter schieben
535
  clc                ; sonst Carryflag löschen
536
  ror dcfbuf            ; noch eins weiter schieben
537
  sts dcfday_1, dcfbuf      ; den tag in seinen Speicher laden
538
  clr dcfbuf            ; puffer löschen
539
dcfjmp3:              ; jetzt kommt der wochentag
540
  cpi timeslot, 0x2D        ; 45 Zeichen empfangen
541
  brne dcfjmp4          ; wenn nicht den springen
542
  clc                ; sonst Carryflag löschen
543
  ror dcfbuf            ; noch eins weiter schieben
544
  clc                ; sonst Carryflag löschen
545
  ror dcfbuf            ; noch eins weiter schieben
546
  clc                ; sonst Carryflag löschen
547
  ror dcfbuf            ; noch eins weiter schieben
548
  clc                ; sonst Carryflag löschen
549
  ror dcfbuf            ; noch eins weiter schieben
550
  clc                ; sonst Carryflag löschen
551
  ror dcfbuf            ; noch eins weiter schieben
552
  sts dcfwday_1, dcfbuf      ; den wochentag in seinen Speicher laden
553
  clr dcfbuf            ; puffer löschen
554
dcfjmp4:              ; jetzt kommt der monat
555
  cpi timeslot, 0x32        ; 50 Zeichen empfangen
556
  brne dcfjmp5          ; wenn nicht den springen
557
  clc                ; sonst Carryflag löschen
558
  ror dcfbuf            ; noch eins weiter schieben
559
  clc                ; sonst Carryflag löschen
560
  ror dcfbuf            ; noch eins weiter schieben
561
  clc                ; sonst Carryflag löschen
562
  ror dcfbuf            ; noch eins weiter schieben
563
  sts dcfmonth_1, dcfbuf      ; den monat in seinen Speicher laden
564
  clr dcfbuf            ; puffer löschen
565
dcfjmp5:              ; jetzt kommt das jahr
566
  cpi timeslot, 0x3A        ; 58 Zeichen empfangen
567
  brne dcfjmp6          ; wenn nicht den springen
568
  sts dcfyear_1, dcfbuf      ; das jahr in seinen Speicher laden
569
  clr dcfbuf            ; puffer löschen
570
dcfjmp6:              ; jetzt fertig
571
  cpi timeslot, 0x3B        ; 59 Zeichen empfangen Rahmenende
572
  brne dcfjmp7          ; wenn nicht den springen
573
  clr dcfbuf            ; puffer löschen
574
  rcall validate          ; prüfen ob die werte sinn machen
575
dcfjmp7:              ; jetzt fertig
576
  ret
577
578
; Routine prüft die Daten auf Kausalität
579
validate:
580
  set                ; Transferflag setzen
581
  lds temp1, dcfmin_1        ; minute aktuell holen
582
  lds temp2, dcfmin_2        ; minute alt holen
583
  cp temp1, temp2          ; vergleichen
584
  breq valjmp0          ; wenn nicht gleich
585
  clt                ; lösche das Transferflag
586
valjmp0:
587
  lds temp1, dcfhour_1      ; stunde aktuell holen
588
  lds temp2, dcfhour_2      ; stunde alt holen
589
  cp temp1, temp2          ; vergleichen
590
  breq valjmp1          ; wenn nicht gleich
591
  clt                ; lösche das Transferflag
592
valjmp1:
593
  lds temp1, dcfday_1        ; tag aktuell holen
594
  lds temp2, dcfday_2        ; tag alt holen
595
  cp temp1, temp2          ; vergleichen
596
  breq valjmp2          ; wenn nicht gleich
597
  clt                ; lösche das Transferflag
598
valjmp2:
599
  lds temp1, dcfwday_1      ; wochentag aktuell holen
600
  lds temp2, dcfwday_2      ; wochentag alt holen
601
  cp temp1, temp2          ; vergleichen
602
  breq valjmp3          ; wenn nicht gleich
603
  clt                ; lösche das Transferflag
604
valjmp3:
605
  lds temp1, dcfmonth_1      ; monat aktuell holen
606
  lds temp2, dcfmonth_2      ; monat alt holen
607
  cp temp1, temp2          ; vergleichen
608
  breq valjmp4          ; wenn nicht gleich
609
  clt                ; lösche das Transferflag
610
valjmp4:
611
  lds temp1, dcfyear_1      ; jahr aktuell holen
612
  lds temp2, dcfyear_2      ; jahr alt holen
613
  cp temp1, temp2          ; vergleichen
614
  breq valjmp5          ; wenn nicht gleich
615
  clt                ; lösche das Transferflag
616
valjmp5:
617
618
  bld flags,3            ; schreibe tflag nach bit 3 von flags
619
620
  lds temp1, dcfmin_1        ; minute aktuell holen
621
  inc temp1            ; minute um eins erhöhen
622
  sts dcfmin_2, temp1        ; alte minute überschreiben
623
624
  lds temp1, dcfhour_1      ; stunde aktuell holen
625
  sts dcfhour_2, temp1      ; alte stunde überschreiben
626
627
  lds temp1, dcfday_1        ; tag aktuell holen
628
  sts dcfday_2, temp1        ; alten tag überschreiben
629
630
  lds temp1, dcfwday_1      ; wochentag aktuell holen
631
  sts dcfwday_2, temp1      ; alten wochentag überschreiben
632
633
  lds temp1, dcfmonth_1      ; monat aktuell holen
634
  sts dcfmonth_2, temp1      ; alten monat überschreiben
635
636
  lds temp1, dcfyear_1      ; jahr aktuell holen
637
  sts dcfyear_2, temp1      ; altes jahr überschreiben
638
  ret
639
640
; Gibt das Datum aus
641
dateout:
642
  ldi temp1,0xC0          ; Cursor auf Anfang Zweite Zeile
643
  rcall lcd_command
644
  ldi temp1, ' '          ; Buchstabe anzeigen
645
  rcall lcd_data
646
647
  lds temp1, dcfwday_1      ; Wochentag nach temp1
648
  cpi temp1, 0x01          ; Ist Montag ?
649
  brne datjmp0          ; Wenn nicht springen
650
  ldi temp1, 'M'          ; Buchstabe anzeigen
651
  rcall lcd_data
652
  ldi temp1, 'o'          ; Buchstabe anzeigen
653
  rcall lcd_data
654
datjmp0:
655
  cpi temp1, 0x02          ; Ist Dienstag ?
656
  brne datjmp1          ; Wenn nicht springen
657
  ldi temp1, 'D'          ; Buchstabe anzeigen
658
  rcall lcd_data
659
  ldi temp1, 'i'          ; Buchstabe anzeigen
660
  rcall lcd_data
661
datjmp1:
662
  cpi temp1, 0x03          ; Ist Mittwoch ?
663
  brne datjmp2          ; Wenn nicht springen
664
  ldi temp1, 'M'          ; Buchstabe anzeigen
665
  rcall lcd_data
666
  ldi temp1, 'i'          ; Buchstabe anzeigen
667
  rcall lcd_data
668
datjmp2:
669
  cpi temp1, 0x04          ; Ist Donnerstag ?
670
  brne datjmp3          ; Wenn nicht springen
671
  ldi temp1, 'D'          ; Buchstabe anzeigen
672
  rcall lcd_data
673
  ldi temp1, 'o'          ; Buchstabe anzeigen
674
  rcall lcd_data
675
datjmp3:
676
  cpi temp1, 0x05          ; Ist Freitag ?
677
  brne datjmp4          ; Wenn nicht springen
678
  ldi temp1, 'F'          ; Buchstabe anzeigen
679
  rcall lcd_data
680
  ldi temp1, 'r'          ; Buchstabe anzeigen
681
  rcall lcd_data
682
datjmp4:
683
  cpi temp1, 0x06          ; Ist Samstag ?
684
  brne datjmp5          ; Wenn nicht springen
685
  ldi temp1, 'S'          ; Buchstabe anzeigen
686
  rcall lcd_data
687
  ldi temp1, 'a'          ; Buchstabe anzeigen
688
  rcall lcd_data
689
datjmp5:
690
  cpi temp1, 0x07          ; Ist Sonntag ?
691
  brne datjmp6          ; Wenn nicht springen
692
  ldi temp1, 'S'          ; Buchstabe anzeigen
693
  rcall lcd_data
694
  ldi temp1, 'o'          ; Buchstabe anzeigen
695
  rcall lcd_data
696
datjmp6:
697
  rcall singledot          ; schreibt ein doppelpunkt ins Display
698
  ldi temp1, ' '          ; Buchstabe anzeigen
699
  rcall lcd_data
700
  lds timeout, dcfday_1      ; Tag nach timeout
701
  rcall timeout_func        ; Tag ans Display senden
702
  rcall singledot          ; schreibt ein doppelpunkt ins Display
703
  lds timeout, dcfmonth_1      ; Monat nach timeout
704
  rcall timeout_func        ; Monat ans Display senden
705
  rcall singledot          ; schreibt ein doppelpunkt ins Display
706
  ldi timeout, 0x20        ; Y3K Bug
707
  rcall timeout_func        ; 20 ans Display senden
708
  lds timeout, dcfyear_1      ; Jahr nach timeout
709
  rcall timeout_func        ; Jahr ans Display senden
710
  ret
711
712
; PowerOn Message senden
713
pon_mess:
714
  ldi temp1, ' '          ; Buchstabe anzeigen
715
  rcall lcd_data
716
  ldi temp1, ' '          ; Buchstabe anzeigen
717
  rcall lcd_data
718
  ldi temp1, 'B'          ; Buchstabe anzeigen
719
  rcall lcd_data
720
  ldi temp1, 'i'          ; Buchstabe anzeigen
721
  rcall lcd_data
722
  ldi temp1, 't'          ; Buchstabe anzeigen
723
  rcall lcd_data
724
  ldi temp1, 't'          ; Buchstabe anzeigen
725
  rcall lcd_data
726
  ldi temp1, 'e'          ; Buchstabe anzeigen
727
  rcall lcd_data
728
  ldi temp1, ' '          ; Buchstabe anzeigen
729
  rcall lcd_data
730
  ldi temp1, 'w'          ; Buchstabe anzeigen
731
  rcall lcd_data
732
  ldi temp1, 'a'          ; Buchstabe anzeigen
733
  rcall lcd_data
734
  ldi temp1, 'r'          ; Buchstabe anzeigen
735
  rcall lcd_data
736
  ldi temp1, 't'          ; Buchstabe anzeigen
737
  rcall lcd_data
738
  ldi temp1, 'e'          ; Buchstabe anzeigen
739
  rcall lcd_data
740
  ldi temp1, 'n'          ; Buchstabe anzeigen
741
  rcall lcd_data
742
  ldi temp1,0xC0          ; Anfang Zweite Zeile
743
  rcall lcd_command
744
  ldi temp1, 'F'          ; Buchstabe anzeigen
745
  rcall lcd_data
746
  ldi temp1, 'i'          ; Buchstabe anzeigen
747
  rcall lcd_data
748
  ldi temp1, 'r'          ; Buchstabe anzeigen
749
  rcall lcd_data
750
  ldi temp1, 'm'          ; Buchstabe anzeigen
751
  rcall lcd_data
752
  ldi temp1, 'w'          ; Buchstabe anzeigen
753
  rcall lcd_data
754
  ldi temp1, 'a'          ; Buchstabe anzeigen
755
  rcall lcd_data
756
  ldi temp1, 'r'          ; Buchstabe anzeigen
757
  rcall lcd_data
758
  ldi temp1, 'e'          ; Buchstabe anzeigen
759
  rcall lcd_data
760
  ldi temp1, ':'          ; Buchstabe anzeigen
761
  rcall lcd_data
762
  ldi temp1, ' '          ; Buchstabe anzeigen
763
  rcall lcd_data
764
  ldi temp1, 'v'          ; Buchstabe anzeigen
765
  rcall lcd_data
766
  ldi temp1, '2'          ; Buchstabe anzeigen
767
  rcall lcd_data
768
  ldi temp1, '.'          ; Buchstabe anzeigen
769
  rcall lcd_data
770
  ldi temp1, '0'          ; Buchstabe anzeigen
771
  rcall lcd_data
772
  ldi temp1, '1'          ; Buchstabe anzeigen
773
  rcall lcd_data
774
  ldi temp1, ' '          ; Buchstabe anzeigen
775
  rcall lcd_data
776
  ret