UHR120_4.ASM


1
;************ DCF77 Uhr mit LCD Anzeige auf HD44???? Basis ******************
2
;*
3
;* - Ersteller: U.Hempel   eMail: heausc@aol.com
4
;* - frei für alle, die es nutzen wollen
5
;* - keine Garantie auf Fehler 
6
;* - erstellt: 2/2002 
7
;*
8
;* - Kontroller AT90S1200 mit 4 MHz Quarz
9
;* - 293 Worte
10
;* - Teiler (125(Uhr_ms)x125(tov0)x255(MCUCR)=4MHz->1s
11
;* - Quarzanpassung mit 125 +/- bei tov0 setzen
12
;* - tov0 erzeugt aller 8 ms einen Interrupt(wird auch für LCD_init gebraucht)
13
;* -
14
;* - mit interner Uhrzeit (Uhr_...)
15
;* -
16
;* - mit doppelter Patitätsprüfung!!!!
17
;* -
18
;* - mit Quersumme über alle DCF-Zahlen (Min_einer bis Jahr_zehner)
19
;* - 
20
;* - LCD 4Bit Modus
21
;* - LCD-Modul 2 x 16 Zeichen oben Zeit, unten Tag + Datum
22
;* - LCD-DB4-7 an PortB4-B7
23
;* -
24
;* - Port B0-B3 nur als Eingänge benutzen, die Ausgänge ändert lcdtmp !!!!!
25
;* - R/W an GND (nur schreiben)
26
;* - E = Takt an Port D0
27
;* - RS an Port D1
28
;* - LCD-Adresse 1.Zeile = $80 - $8f
29
;* - LCD-Adresse 2.Zeile = $c0 - $cf
30
;* - Tag->EEPr ab Adr. $02
31
;* - w_tag hat normal ein lsl,wegen EEPr Adr.2(x2) weggelassen
32
;*
33
;* - Werte für EEProm ab Adr. $00
34
;* - $0F,$0F,$1d,$3f,$14,$39,$1d,$39,$14,$3f,$16,$42,$23,$31,$23,$3f (+$30)
35
;**** ? * ? * M   o * D   i * M   i * D   o * F   r * S   a * S   o ******
36
;*
37
;* - Pd0 = Ausgang: E (Takt LCD)
38
;* - Pd1 = Ausgang: RS (Register Set LCD)
39
;* - Pd2 = Eingang: INT0 auf LH-Flanke von DCF-Modul
40
;* - 1.Zeile 2.+3.Zeichen >< für ok , <> für Fehler 
41
;* - Fehlersetzen mit:
42
;* - Nullimp wenn  sek. nicht 59 (DCF fehlt)
43
;* - falsche Parität 3x getestet
44
;* - Quersumme neue Min.<> Quersumme +1 alte Min (Fehler aller 10 Min,9->0)
45
;****************************************************************************
46
47
.include "1200def.inc"
48
49
;***** globale Register Variablen *******************************************
50
51
;*** Rr-Register festlegen
52
.def  h_z  =r0    ;Stunden Zehner(0-2)
53
.def  h_e  =r1    ;Stunden Einer (0-9)
54
.def  min_z  =r2    ;Minuten Zehner(0-5)
55
.def  min_e  =r3    ;Minuten Einer (0-9)
56
.def  k_tag_e  =r4    ;Datumstag Einer(0-9)
57
.def  k_tag_z  =r5    ;Datumstag Zehner(0-3)
58
.def   w_tag  =r6    ;Wochentag Mo(1)-So(7)
59
.def  mon_e  =r7    ;Monat Einer  (0-9)
60
.def  mon_z  =r8    ;Monat Zehner  (0-2)
61
.def  jahr_e  =r9    ;Jahr Einer  (0-9)
62
.def  jahr_z  =r10    ;Jahr Zehner  (0-9)
63
.def  asci  =r11    ;zum ASCI erzeugen ($30)
64
.def  test_Q  =r12    ;alle DCF-Werte+,+1,-neue DCF-Werte=<0>=error
65
66
;*** Rd-Register festlegen
67
.def  temp  =r16    ;allgem. tempor.-Reg.
68
.def  sek  =r17    ;DCF-Sekunden 1-59
69
.def  testhl  =r18    ;test ob T<150ms oder >180ms;>1500ms=sek00
70
.def  set  =r19    ;Reg.zum setzen (übernimmt H/L-Bit als $8/$0)
71
.def  bits  =r20    ;Reg.zum Zusammenbauen des Zahlenwertes
72
.def  lcdtmp  =r21     ;
73
.def  takt  =r22    ;zum erzeugen des LCD-Takt mit TOV0
74
.def  error  =r23    ;Fehlermerker
75
.def  par  =r24    ;Paritätsreg.für H-Bits(exor)
76
.def  isr_tmp  =r25    ;Interrupt- Stack(S-Reg.)
77
.def  uhr_ms  =r26    ;int.Uhr ms, 125 x TOV0 = 1 sek
78
.def  uhr_s  =r27    ;int.Uhr sek(60)
79
.def  uhr_me  =r28    ;int.Uhr Min Einer
80
.def  uhr_mz  =r29    ;int.Uhr Min Zehner
81
.def  uhr_he  =r30    ;int.Uhr Stunden Einer
82
.def  uhr_hz  =r31    ;int.Uhr Stunden Zehner
83
84
;***** EEPromdaten für Wochentage *******************************************
85
.eseg
86
87
.org  0x00
88
.db  $0F,$0F,$1d,$3f,$14,$39,$1d,$39,$14,$3f,$16,$42,$23,$31,$23,$3f
89
;******* ? * ? * M   o * D   i * M   i * D   o * F   r * S   a * S   o ******
90
91
;***** Interrupt Vectoren ***************************************************
92
93
.cseg
94
.org   0x00    
95
  rjmp  RESET    ;Programmbeginn bei Reset 
96
  rjmp  impuls    ;EXT-IRQ (Pd2=LH)Impulsbeginn DCF77
97
  rjmp  tov    ;T0 ovf
98
  rjmp  RESET    ;AN-Comp
99
100
lcd_on:  out  portb,lcdtmp  ;
101
  cbi  portd,0    ;E = 0 = Daten übernehmen(LCD-Hig-Nibbel)
102
T0:  in  temp,TIFR  ;weiter erst wenn TOV0 = 1
103
  tst  temp
104
  breq  T0    ;sonst zurück->T0
105
  sbi  portd,0    ;E = 1
106
  out  tifr,temp  ;TOV0 löschen
107
  swap  lcdtmp    ;Nibbel tauschen
108
lcd_3:  out  portb,lcdtmp  ;unteres Nibbel ausgeben
109
  cbi  portd,0    ;E = 0 = Daten übernehmen(LCD-low-Nibbel)
110
T1:  in  temp,TIFR  ;weiter erst wenn TOV0 = 1
111
  tst  temp
112
  breq  T1    ;sonst zurück->T1
113
  sbi  portd,0    ;E = 1
114
  out  tifr,temp  ;TOV0 löschen
115
  ret  
116
117
RESET:  ldi  temp,$4    ;Vorteiler = 4MHz/256=64µs
118
  out  TCCR0,temp  ;*125(TMR0)=8ms je TOV0 (16,4ms bei lcd_on)
119
  clr  bits
120
  ldi  uhr_ms,125
121
  ldi  uhr_s,60  ;60 sek
122
  clr  uhr_me    ;int. Uhr alles auf null stellen
123
  clr  uhr_mz
124
  clr  uhr_he
125
  clr  uhr_hz
126
  ldi  temp,$30  ;zum ASCI erzeugen
127
  mov  asci,temp  ;umladen
128
  out  portb,bits  ;an Portb alles mit L vorbelegen
129
  ldi  temp,$f0
130
  out  ddrb,temp  ;Port b4-b7 = Ausgang
131
  ldi  error,1    ;
132
  out  portd,error  ;PD0=1(E)+PD1=0(RS)vorbelegen
133
  inc  error    ;Fehler setzen
134
  out  TIFR,error  ;TOV0 sicherheitshalber löschen
135
  ldi  temp,0b00000011  ;temp=$3
136
  out  ddrd,temp  ;PD0+PD1=Ausgang
137
Pause:  in  temp,TIFR  ;weiter erst wenn TOV0 = 1
138
  tst  temp
139
  breq  Pause    ;sonst zurück->Pause (LCD-Einschaltpause)
140
141
LCDinit:ldi   lcdtmp,$28  ;LCDinit(DB4=0;DB5=1)
142
  rcall  lcd_3    ;1.mal LCD_init (nur 1 Nibbel)
143
  rcall  lcd_3    ;DB4= 0 = Datenlänge = 4 Bit(nur Hig-Nibbel)
144
  rcall  lcd_on    ;jetzt komplett
145
  ldi  lcdtmp,$0c  ;Displ an.+ Kursor aus (mit Kurs.=$0e)
146
  rcall  lcd_on
147
  ldi  lcdtmp,1  ;1 = Anz.auf 1.Zeichen + Displ.= cls
148
  rcall  lcd_on
149
  ldi  temp,$3
150
  OUT  TIMSK,temp  ;Timer Int.on
151
  OUT  MCUCR,temp  ;INT0 mit steigende Flanke
152
  ldi  temp,$40
153
  out  gimsk,temp  ;INT0(PB2) ein
154
  sei      ;INT glob.ein
155
  
156
;******* Hauptprogramm **************************
157
158
HP:  ldi  lcdtmp,$82  ;1.Zeile 3. Zeichen
159
  rcall   Fu_set    ;Funktion setzen
160
  tst  error
161
  breq  sig_ok    ;wenn error=0 ->sig_ok
162
  ldi  lcdtmp,$0c  ;$0c+$30= (<)
163
  rcall  Z_set
164
  ldi  lcdtmp,$0e  ;$0e+$30= (>)
165
  rcall  Z_set
166
  rjmp  fe1    ;kein Datum ausgeben,nur int.Uhr
167
sig_ok:  ldi  lcdtmp,$0e  ;$0e+$30= (>)
168
  rcall  Z_set
169
  ldi  lcdtmp,$0c  ;$0c+$30= (<)
170
  rcall  Z_set
171
  ldi  lcdtmp,$c2  ;2. Zeile 3.Zeichen
172
  rcall  Fu_set
173
  mov  lcdtmp,w_tag
174
  rcall  eelese    ;EEProm lesen (Wochentag als Zeichen Mo-So)
175
  rcall  Z_set
176
  mov  lcdtmp,w_tag  ;Adresse nochmal hohlen
177
  inc  lcdtmp    ;+1 (2.Buchstabe)
178
  rcall  eelese
179
  rcall  Z_set
180
  ldi  lcdtmp,$c5  ;2. Zeile 6.Zeichen
181
  rcall  Fu_set
182
  mov  lcdtmp,k_tag_z
183
  rcall  Z_set
184
  mov  lcdtmp,k_tag_e
185
  rcall  Z_set
186
  ldi  lcdtmp,$fe  ;ASCI Punkt($2e)
187
  rcall  Z_set
188
  mov  lcdtmp,mon_z
189
  rcall  Z_set
190
  mov  lcdtmp,mon_e
191
  rcall  Z_set
192
  ldi  lcdtmp,$fe  ;ASCI Punkt (+$30=$2e)
193
  rcall  Z_set
194
  mov  lcdtmp,jahr_z
195
  rcall  Z_set
196
  mov  lcdtmp,jahr_e
197
  rcall  Z_set
198
fe1:  ldi  lcdtmp,$86  ;1.Zeile 7. Zeichen
199
  rcall   Fu_set    ;Funktion setzen
200
  mov  lcdtmp,uhr_hz
201
  rcall  Z_set
202
  mov  lcdtmp,uhr_he
203
  rcall  Z_set
204
  ldi  lcdtmp,$0a  ;Doppelpunkt ($3a)
205
  rcall  Z_set
206
  mov  lcdtmp,uhr_mz  ;min_z
207
  rcall  Z_set
208
  mov  lcdtmp,uhr_me  ;min_e
209
  rcall  Z_set
210
  ldi  error,1    ;Fehler setzen (wird,wenn alles ok,bei syn=0)
211
212
neu:  brtc  neu    ;wenn T-Flag = 0 -> neu
213
  clt      ;sonst T-Flag = 0 (nur eine Ausgabe)
214
  rjmp  HP    ;und Zeiten ausgeben
215
216
;****** ein Zeichen oder eine Funktion setzen *******************************
217
218
Z_set:  sbi  portd,1    ;RS = 1
219
  add  lcdtmp,asci  ;ASCI erzeugen
220
Fu_set:  out  portb,lcdtmp
221
  inc  takt    ;mit TOV0 Takt erzeugen
222
  cbi  portd,0    ;E = 0 = Daten übernehmen(LCD)
223
t4:  tst  takt    ;takt noch 1? ->t4
224
  brne  t4
225
  sbi  portd,0    ;E = 1      
226
  swap  lcdtmp    ;Nibbel tauschen
227
  out  portb,lcdtmp  ;und Low-Nibbel ausgeben
228
  inc  takt    ;mit TOV0 Takt erzeugen
229
  cbi  portd,0    ;E = 0 = Daten übernehmen(LCD)
230
t5:  tst  takt    ;takt noch 1? ->t2
231
  brne  t5
232
  sbi  portd,0    ;E = 1
233
  cbi  portd,1    ;RS = 0
234
  ret
235
236
;****** EEProm lesen *******************************************************
237
238
eelese:  out  eear,lcdtmp  ;Wochentag(1-7)->EEPr. Adresse
239
  sbi  eecr,0    ;EEPr.lesen (eere=1)
240
le1:  sbic  eecr,0    ;warten bis eere = 0 (EEPr-Daten ok)
241
  rjmp  le1
242
  in  lcdtmp,eedr  ;Zeichen holen
243
  ret
244
;****** INT0 (DCF-Signal) bearbeiten ****************************************************
245
246
impuls:  in  isr_tmp,sreg  ;Flagreg.sichern
247
  cpi  testhl,114  ;912ms
248
  brcs  igno    ;wenn kleiner -> igno
249
  clr  testhl    ;Timerreg=0
250
  inc  sek    ;DCF-sek + 1
251
igno:  out  sreg,isr_tmp  ;Flag's zurückschreiben
252
  reti
253
254
;****** TOVO bearbeiten ****************************************************
255
256
;**** 1. -interne Uhr ************
257
258
tov:  in  isr_tmp,sreg  ;Flagreg.sichern  
259
  ldi  temp,$ff-122  ;Quarzanpassung hier in Schritten von 64µs
260
  out  TCNT0,temp  ;(122+1)125 Takte bis TOVO
261
  clr  takt    ;LCD-Takt
262
  dec  uhr_ms
263
  brne  uhr_e    ;wenn nicht 0 ->uhr_e
264
  ldi  uhr_ms,125  ;neu laden
265
  dec  uhr_s
266
  brne  uhr_e    ;wenn nicht 0 ->uhr_e
267
  ori  isr_tmp,$40  ;T-Flag für Ausgabe setzen
268
  ldi  uhr_s,60  ;60 sek
269
  inc  uhr_me    ;min + 1
270
  cpi  uhr_me,10  ;
271
  brcs  uhr_e    ;< 10
272
  clr  uhr_me    ;min einer = 0
273
  inc  uhr_mz    ;min zehner + 1
274
  cpi  uhr_mz,6  ;
275
  brcs  uhr_e    ;< 6
276
  clr  uhr_mz    ;min zehner = 0
277
  inc  uhr_he    ;h einer + 1
278
  cpi  uhr_he,4  ;>=(2)4 Stunden
279
  brne  te_10    ;<>!
280
  cpi  uhr_hz,2  ;Sundenzehner = 2 ?
281
  brcs  te_10
282
  clr  uhr_he
283
  clr  uhr_hz
284
  rjmp  uhr_e
285
te_10:  cpi  uhr_he,10
286
  brcs  uhr_e    ;<10!
287
  clr  uhr_he
288
  inc  uhr_hz    ;Stundenzehner + 1
289
290
;*** 2. -DCF auswerten ***************
291
292
uhr_e:  in  temp,pind  ;Port d->temp (aller 8ms)
293
  andi  temp,4    ;Pd2 ausfiltern
294
  inc  testhl    ;Timerreg. + 1
295
  cpi  testhl,18  ;=144ms ?
296
  breq  bit_hl    ;wenn = 144ms->bit_hl
297
  cpi  testhl,40  ;=320ms ?
298
  breq  bitset    ;wenn 320ms->bitset
299
  cpi  testhl,165  ;1320ms ?
300
  breq  syn    ;wenn 1320ms ->syn (nur wenn INT0 ausbleibt)
301
  rjmp  isrend    ;reti
302
303
bit_hl:  tst  temp    ;
304
  brne  bit_1    ;wenn temp(Pd2) nicht 0->bit_1
305
  mov  set,temp  ;sonst set wird 0
306
  rjmp  isrend    ;reti
307
308
bit_1:  ldi  set,$8    ;sonst wird set=8(Bit3)
309
  eor  par,set    ;aus par=0 wird par=1 und par=1 wird par=0
310
  rjmp  isrend    ;reti;in bitset bei sek 29 muß par=0 sein
311
  
312
313
syn:  add  sek,par    ;3.Paritätstest
314
  add  sek,temp  ;wehe wenn bei syn ein Sign.an Pb2
315
  cpi  sek,59    ;DCF-Sek bei syn = 59?
316
  brne  Fehl_1    ;wenn nein Fehl_1
317
318
  mov  temp,min_e  ;Minuten einer->temp
319
  add  temp,min_z  ;+ Minuten Zehner
320
  add  temp,h_e  ;+ Stunden Einer
321
  add  temp,h_z  ;+ Stunden Zehner
322
  add  temp,w_tag  ;+ Wochentag(2-14)
323
  add  temp,k_tag_z  ;+ Datumstag Zehner(0-3)
324
  add  temp,k_tag_e  ;+ Datumstag Einer(0-9)
325
  add  temp,mon_e  ;+ Monat Einer  (0-9)
326
  add  temp,mon_z  ;+ Monat Zehner  (0-2)
327
  add  temp,jahr_e  ;+ Jahr Einer  (0-9)
328
  add  temp,jahr_z  ;+ Jahr Zehner  (0-9)
329
  cp  temp,test_Q  ;mit altem Wert vergleichen
330
  brne  Fehl_1    ;wenn nicht gleich -> Fehl_1
331
332
;****** DCF Sign.ok! *********************
333
334
  mov  jahr_z,bits  ;Jahr Zehner  (0-9) abspeichern
335
  clr  error    ;wird nach jeder Ausgabe gesetzt
336
  ldi  uhr_s,60  ;int.sek synchronisieren
337
  mov  uhr_hz,h_z  ;DCF-Zeit nach int.Uhr
338
  mov  uhr_he,h_e
339
  mov  uhr_mz,min_z
340
  mov  uhr_me,min_e  ;wenn kein Fehler erkannt
341
  ori  isr_tmp,$40  ;T-Flag für Ausgabe setzen
342
  rjmp  Fehl_2
343
344
Fehl_1:  clr  par    ;Parität reset bei Fehler
345
346
Fehl_2:  clr  sek    ;sek = 0 (59.Sekunde oder Fehler)
347
  inc  temp    ;+1 Min.für test_Q (aller 10 Min.= Fehler!)
348
  mov  test_Q,temp  ;und abspeichern
349
  rjmp  isrend    ;reti  
350
351
;**** Achtung Sek. 60 bringt 1. Zählimpuls deshalb alle Takte +1 ***********
352
353
bitset:  cpi  sek,22
354
  brcs  isrend    ;wenn >,->isrend
355
  cpi  sek,26
356
  brcs  lade1    ;wenn < 25-> lade1 (Min.Einer (0-9))
357
  breq  MZ    ;1.Min.Zehner und Min Einer sichern
358
  cpi  sek,29
359
  brcs  lade1    ;wenn < 29 ->lade1 (Min.Zehner (0-5))
360
  breq  parit    ;wenn =29 ->Paritätstest
361
  cpi  sek,30
362
  breq  STE    ;1.Stunden Einer und Min Zehner sichern
363
  cpi  sek,34
364
  brcs  lade1    ;wenn < 34 ->lade1 (Stunden Einer (0-9))
365
  breq  STZ    ;1.Stunden Zehner und Stunden Einer sichern
366
  cpi  sek,36
367
  brcs  lade1    ;wenn <36 -> lade1 (Stunden Zehner (0-2))
368
  breq  parit    ;2.Paritätstest
369
370
Datum:  cpi  sek,37
371
  breq  KTE    ;1.Kalendertag Einer(Stunden Zehner sichern)
372
  cpi  sek,41
373
  brcs  lade1    ;wenn <41->lade1 (Kalendertag Einer (0-9))
374
  breq  KTZ    ;1.Kalendertag Zehner(Kal.tag Einer sichern)
375
  cpi  sek,43
376
  brcs  lade1    ;wenn < 43->lade1 (Kalendertag Zehner (0-2))
377
  breq  WT    ;1.Wochentag und Kal.tag Zehner sichern
378
  cpi  sek,46
379
  brcs  lade1    ;wenn < 46 ->lade1 (Wochentag 1-7)
380
  breq  MOE    ;1.Monat Einer und Wochentag sichern
381
  cpi  sek,50
382
  brcs  lade1    ;wenn < 50->lade1 (Monat Einer (0-9))
383
  breq  MOZ    ;Monat Zehner (0,1)und Monat Einer sichern
384
  cpi  sek,55
385
  brcs  lade1    ;wenn < 55->lade1 (Jahr Einer (0-9))
386
  breq  JZ    ;1.Jahr Zehner und Jahr Einer sichern
387
  cpi  sek,59
388
  brcs  lade1    ;wenn < 59 ->lade1 (Jahr Zehner (0-9))
389
  rjmp  isrend    ;ende Abfrage
390
391
STZ:  mov  h_e,bits
392
393
lade1:  lsr  bits    ;Ladeprogr.für restliche bits(1xrechts)
394
  or  bits,set  ;8 oder 0 einfügen
395
isrend:  out  sreg,isr_tmp  ;Flag's zurückschreiben
396
  reti
397
398
parit:  tst  par
399
  breq  par_1    ;wenn Parität = 0 ist alles ok.
400
  ldi  sek,60    ;sonst Fehler erzeugen(DCF-sek <>59)
401
par_1:  rjmp  isrend    ;reti
402
403
  
404
MZ:  mov  min_e,bits
405
  rjmp  lade1  
406
407
STE:  lsr  bits    ;1x Stellenkorrektur
408
  mov  min_z,bits
409
  rjmp  lade1
410
411
KTE:  lsr  bits
412
  lsr  bits    ;2x Stellenkorrektur
413
  mov  h_z,bits  ;Stundenzehner
414
  rjmp  lade1
415
416
KTZ:  mov  k_tag_e,bits
417
  rjmp  lade1
418
419
WT:  lsr  bits
420
  lsr  bits    ;2x Stellenkorrektur  
421
  mov  k_tag_z,bits
422
  clr  bits    ;bits müssen null sein weil 1xlsr weggelassen
423
  rjmp  lade1
424
425
MOE:  ;lsr  bits    ;1x Stellenkorrektur (nicht,weil EEAdr*2)
426
  mov  w_tag,bits  ;Wochentag Mo(1)-So(7)bzw.(2-F)
427
  rjmp  lade1
428
429
MOZ:  mov  mon_e,bits  ;Monat Einer  (0-9)
430
  clr  bits
431
  sbrc  set,3    ;wenn Bit3 in set = 0 überspringe
432
  inc  bits    ;bits=1
433
  mov  mon_z,bits  ;Monat Zehner  (0-1)
434
  rjmp  isrend    ;reti
435
436
JZ:  mov  jahr_e,bits  ;Jahr Einer  (0-9)
437
  rjmp  lade1
438
439
440
;******* decodieren Ende *************************************************