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
|