summaryrefslogtreecommitdiff
path: root/ERICH_VER_0.1.ASM
blob: 1ae2a7b76d85351b39819c4a23232341292943c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
; #define Mengenlehreuhr

#include <P16f872.INC>

 __CONFIG 0x3B39

Stunde     Equ 0x20     ; aktuelle Stunde
Minute     Equ 0x21     ; aktuelle Minute
Sekunde    Equ 0x22     ; aktuelle Sekunde
dreiMSL    Equ 0x23     ; 3ms-Zaehler (eigtl. 10/3 ms) low-Teil
dreiMSH    Equ 0x24     ; 3ms-Zaehler (eigtl. 10/3 ms) high-Teil
weiterDML  Equ 0x25     ; Sollwert fuer 3ms-Zaehler beim Warten low-Teil
weiterDMH  Equ 0x26     ; Sollwert fuer 3ms-Zaehler beim Warten high-Teil
weiterT1L  Equ 0x27     ; Sollwert fuer Timer1Zaehler beim Warten low-Teil
weiterT1H  Equ 0x28     ; Sollwert fuer Timer1Zaehler beim Warten high-Teil
tara       Equ 0x29     ; zum Tarieren der Zeitkonstante
dZFlL      Equ 0x2A     ; 3ms-Zaehlerstand bei letzter Flanke low-Teil
dZFlH      Equ 0x2B     ; 3ms-Zaehlerstand bei letzter Flanke high-Teil
Stati      Equ 0x2C     ; 0: letzter/aktueller Pegel der DCF77-Empfängers
                        ; 1: Fehler innerhalb der letzten Funkminute
                        ; 2: MEZ/MESZ-Umstellung am Ende der Stunde
                        ; 3: MESZ?
                        ; 4: Schaltsekunde am Ende der Stunde
                        ; 6: letzte Minute kam per Funk
                        ; 7: letzte Stunde kam per Funk
tmpL       Equ 0x2D     ; temporaerer Speicher
tmpH       Equ 0x2E     ; temporaerer Speicher
Spalten    Equ 0x2F     ; zu aktivierende Spalten
Zeilen     Equ 0x30     ; zu aktivierende Zeile(n)
dat0       Equ 0x31     ; Funkdaten, Bit 0..7
dat1       Equ 0x32     ; Funkdaten, Bit 8..15
dat2       Equ 0x33     ; Funkdaten, Bit 16..23
dat3       Equ 0x34     ; Funkdaten, Bit 24..31
dat4       Equ 0x35     ; Funkdaten, Bit 32..39
dat5       Equ 0x36     ; Funkdaten, Bit 40..47
dat6       Equ 0x37     ; Funkdaten, Bit 48..55
dat7       Equ 0x38     ; Funkdaten, Bit 56..58 bzw. 63

 GOTO  Anfang
 RETFIE

Anfang                  ; nach den Interrupts

 BCF   STATUS, RP0
 BCF   STATUS, RP1      ; Bank0

 CLRF  Stunde           ; eigene Variablen initialisieren
 CLRF  Minute
 CLRF  Sekunde
 MOVLW 0x12
 MOVWF Stunde
 MOVLW 0x34
 MOVWF Minute
 MOVLW 0x56
 MOVWF Sekunde

 CLRF  dat0
 CLRF  dat1
 CLRF  dat2
 CLRF  dat3
 CLRF  dat4
 CLRF  dat5
 CLRF  dat6
 CLRF  dat7

 CLRF  dreiMSH
 CLRF  dreiMSL
 MOVLW 0x2C
 MOVWF weiterDML
 MOVLW 0x01
 MOVWF weiterDMH
 CLRF  weiterT1L
 CLRF  weiterT1H
 CLRF  Stati
 BSF   Stati, 1
 MOVLW 0x85
 MOVWF tara             ; eigentlich 5 1/3 (die 0x80 entspricht einer Null!)

 CLRF  PORTA            ; I/O initialisieren
 CLRF  PORTB
 CLRF  PORTC

 BSF   STATUS, RP0      ; Bank 1

 MOVLW 0x06             ; Port-A digital
 MOVWF ADCON1
 MOVLW 0x38             ; alles Ausgaenge bis auf A3, A4 und A5
 MOVWF TRISA
 CLRF  TRISB            ; alles Ausgaenge
 CLRF  TRISC            ; alles Ausgaenge

 BCF   PIE1, TMR1IE     ; Interrupt für Timer deaktivieren

 BCF   STATUS, RP0      ; Bank 0

 MOVLW 0x01             ; Timer1 initialisieren
 MOVWF T1CON
; MOVLW 0xC0
; MOVWF INTCON

Multiplex

#ifdef Mengenlehreuhr
 MOVF  Minute, 0
 CALL  BCD2Un
 MOVWF Spalten
 SWAPF Spalten, 1
 MOVF  Minute, 0
 CALL  BCD2Un5H
 IORWF Spalten, 1       ; anzuzeigende Minutenteile

; BTFSC Stati, 1         ; Funkfehler?
; GOTO  SekTaktAnzeigen

 MOVF  Stati, 0
 MOVWF tmpL
 RRF   Stati, 0
 ANDWF tmpL, 1          ; tmpL<6> = Stati<6> & Stati<7> (Funk korrekt?)
 BTFSC Stati, 1
 BCF   tmpL, 6          ; tmpL<6> = Stati<6> & Stati<7> & NOT Stati<1> (Funk korrekt?)
 RLF   PORTA, 0
 XORWF tmpL, 1          ; tmpL<6> = (Stati<6> & Stati<7> & NOT Stati<1>) XOR PORTA<5>
 BTFSC tmpL, 6          ; Funksignal auf Sekunden-LED geben
; BTFSC PORTA, 5
 BSF   Spalten, 3
 GOTO  ErsteZeileSetzen
SekTaktAnzeigen
 BTFSC Sekunde, 0       ; Sekunde auf Sekunden-LED geben
 BSF   Spalten, 3
ErsteZeileSetzen
#else
 MOVF  Sekunde, 0       ; Sekunde als nächstes anzeigen
 MOVWF Spalten
#endif
 MOVLW 0x4
 MOVWF Zeilen
 CALL  Wait

#ifdef Mengenlehreuhr
 MOVF  Minute, 0
 CALL  BCD2Un5L
 MOVWF Spalten
#else
 MOVF  Minute, 0
 MOVWF Spalten          ; Minute als nächstes anzeigen
#endif
 MOVLW 0x2
 MOVWF Zeilen
 CALL  Wait

#ifdef Mengenlehreuhr
 MOVF  Stunde, 0
 CALL  BCD2Un5L
 ANDLW 0xF0
 MOVWF Spalten
 MOVF  Stunde, 0
 CALL  BCD2Un
 IORWF Spalten, 1
#else
 MOVF  Stunde, 0
 ANDLW 0x3F
 MOVWF Spalten          ; Stunde als nächstes anzeigen
 MOVF  Stati, 0
 MOVWF tmpL
 RRF   Stati, 0
 ANDWF tmpL, 1
 RLF   PORTA, 0
 XORWF tmpL, 1
 BTFSC tmpL, 6
 BSF   Spalten, 6       ; Funksignal auf ZusatzLED geben
#endif
 MOVLW 0x1
 MOVWF Zeilen
 CALL  Wait

 GOTO  Multiplex

; Unterprogramme

Sek                     ; Sekunde eins weiter stellen

 BTFSC PORTA, 3         ; Tastendruck?
 CALL  Std
 BTFSC PORTA, 4
 CALL  Min

 INCF  Sekunde, 1
 MOVLW 0x0F             ; 0x0F-Teil von Sekunde anschauen
 ANDWF Sekunde, 0
 SUBLW 0x0A             ; = A ?
 BTFSC STATUS, Z
 GOTO  Sek10            ; neue 10Sek!

 RETURN                 ; Sek erfolgreich erhöht

Sek10
 MOVLW 0x10             ; Sekundenzehner weiter stellen
 ADDWF Sekunde, 1
 MOVLW 0xF0             ; Sekundeneiner löschen
 ANDWF Sekunde, 1
 MOVLW 0x60             ; = 60 ?
 SUBWF Sekunde, 0
 BTFSC STATUS, Z
 GOTO  Min              ; neue Minute!

 RETURN                 ; erfolgreiche neue 10Sek

Min                     ; Minute eins weiter stellen
 MOVLW 0x3F
 ANDWF Stati, 1         ; Funkmin. & Funkstd. zurücksetzen
 CLRF  Sekunde
 INCF  Minute, 1
 MOVLW 0x0F             ; 0x0F-Teil von Minute anschauen
 ANDWF Minute, 0
 SUBLW 0x0A             ; = A ?
 BTFSC STATUS, Z
 GOTO  Min10            ; neue 10Min!

 RETURN                 ; Min erfolgreich erhöht

Min10
 MOVLW 0x10             ; Minutenzehner weiter stellen
 ADDWF Minute, 1
 MOVLW 0xF0             ; Minuteneiner löschen
 ANDWF Minute, 1
 MOVLW 0x60             ; = 60 ?
 SUBWF Minute, 0
 BTFSC STATUS, Z
 GOTO  Std              ; neue Stunde!

 RETURN                 ; erfolgreiche neue 10Min

Std                     ; Stunde eins weiter stellen
 BTFSC Stati, 4         ; Schaltsekunde?
 INCF  Sekunde, 1
 BCF   Stati, 4         ; und rücksetzen

 BTFSS Stati, 2         ; ME(S)Z-Umstellung?
 GOTO keineSZUmstellung
 BCF   Stati, 2         ; rücksetzen
 MOVLW 0x08
 XORWF Stati, 1         ; ME(S)Z-Merker umschalten
 BTFSC Stati, 3
 INCF  Stunde, 1        ; etwas rabiat, sollte bei einer Umstellung zwischen
                        ; 2 und 3 Uhr aber funktionieren
 BTFSS Stati, 3
 DECF  Stunde, 1        ; dito

keineSZUmstellung

 CLRF  Minute
 INCF  Stunde, 1
 MOVLW 0x0F             ; 0x0F-Teil von Stunde anschauen
 ANDWF Stunde, 0
 SUBLW 0x0A             ; = A ?
 BTFSC STATUS, Z
 GOTO  Std10            ; neue 10Std!

 MOVLW 0x24             ; = 24 ?
 SUBWF Stunde, 0
 BTFSC STATUS, Z
 CLRF  Stunde           ; neuer Tag

 RETURN                 ; Std erfolgreich erhöht

Std10
 MOVLW 0x10             ; Stundenzehner weiter stellen
 ADDWF Stunde, 1
 MOVLW 0xF0             ; Stundeneiner löschen
 ANDWF Stunde, 1

 RETURN                 ; erfolgreiche neue 10Std

Wait
 MOVF  tara, 0
 ADDWF weiterT1L, 1     ; + (0x00;tara)
 BTFSC STATUS, C
 INCF  weiterT1H, 1

 MOVLW 0x80
 ADDWF weiterT1L, 1     ; + (0x00;0x80)
 BTFSC STATUS, C
 INCF  weiterT1H, 1

 MOVLW 0x0C             ; + (0x0C;0x00)
 ADDWF weiterT1H, 1     ; Solltimerstand setzen (für 300Hz)

WLoop
 MOVF  weiterT1H, 0
 MOVWF tmpL

 MOVF  TMR1L, 0
 SUBWF weiterT1L, 0
 BTFSS STATUS, C
 DECF  tmpL, 1
 MOVF  TMR1H, 0
 SUBWF tmpL, 1
 BTFSS tmpL, 7          ; weiterT1 - TMR1 >= 0x8000 ("<0"), dann skippen

 GOTO WLoop

 MOVLW 0xF8
 ANDWF PORTA, 1
 MOVF  Spalten, 0
 MOVWF PORTB
 MOVF  Zeilen, 0
 IORWF PORTA, 1

 MOVLW 0xFF
 BTFSS PORTA, 5
 MOVLW 0x00
 XORWF Stati, 0
 ANDLW 0x01
 BTFSS STATUS, Z
 CALL  FlankeGefunden

 INCF  dreiMSL, 1       ; 3MS zählen
 BTFSC STATUS, Z
 INCF  dreiMSH, 1       ; 3*256MS zählen

 MOVF  weiterDMH, 0     ; weiterDM = dreiMS ?
 SUBWF dreiMSH, 0
 BTFSS STATUS, Z
 RETURN                 ; nein !

 MOVF  weiterDML, 0
 SUBWF dreiMSL, 0
 BTFSS STATUS, Z
 RETURN                 ; nein !
                        ; ja !
 CALL  setzeWeiterDM    ; neue Marke setzen
 CALL  Sek              ; neue Sekunde
 
 RETURN                 ; Wait

FlankeGefunden
 MOVF  dZFlH, 0
 SUBWF dreiMSH, 0
 MOVWF tmpH
 MOVF  dZFlL, 0
 SUBWF dreiMSL, 0
 BTFSS STATUS, C
 DECF  tmpH, 1
 MOVWF tmpL             ; tmp:= dreiMS - dzFl
 BTFSS Stati, 0
 GOTO  warLow
 BCF   Stati, 0         ; war High-Pegel
 MOVF  tmpH, 0
 BTFSS STATUS, Z        ; tmp >= 0x0100 ?
 GOTO  periodenFehler   ; Fehler!
 MOVF  tmpL, 0
 SUBLW 0x4B             ; tmp > 75? (entspricht 250 ms)
 BTFSS STATUS, C
 GOTO  periodenFehler   ; Fehler!
 MOVLW 0x0A             ; tmp < 10? (entspricht 33 ms)
 SUBWF tmpL, 0
 BTFSS STATUS, C
 GOTO  periodenFehler   ; Fehler!
 MOVLW 0x28
 SUBWF tmpL, 0          ; tmp >= 40? (entspricht 133 ms) -> empfangenes Bit
 RRF   dat0, 1
 RRF   dat1, 1
 RRF   dat2, 1
 RRF   dat3, 1
 RRF   dat4, 1
 RRF   dat5, 1
 RRF   dat6, 1
 RRF   dat7, 1
                        ; die Pegellänge interessiert bei low nicht
 RETURN
warLow
 BSF   Stati, 0         ; war Low-Pegel

 MOVF  tmpH, 0
 BTFSC STATUS, Z        ; tmp <= 0x00FF ? (= 0,85 s)
 GOTO  keineNeueFunkMinute
 SUBLW 0x02
 BTFSS STATUS, C        ; tmp > 0x02FF ? (= 2,56 s)
 GOTO  periodenFehler   ; Fehler!

 BTFSS tmpH, 1          ; tmp <= 0x01FF ? (= 1,70 s)
 GOTO  keineNeueFunkMinute

 BTFSS Stati, 1         ; wenn kein Fehler, dann
 CALL  neueFunkMinute
 CLRF  dat0             ; Funk-Werte initialisieren
 CLRF  dat1
 CLRF  dat2
 CLRF  dat3
 CLRF  dat4
 CLRF  dat5
 CLRF  dat6
 CLRF  dat7
 BSF   dat0, 7
 BCF   Stati, 1         ; Fehler zurücksetzen
keineNeueFunkMinute

 MOVF  dreiMSH, 0       ; Überprüfung, ob neue Sekunde eingeleitet werden muss
 SUBWF weiterDMH, 0
 MOVWF tmpH
 MOVF  dreiMSL, 0
 SUBWF weiterDML, 0
 BTFSS STATUS, C
 DECF  tmpH, 1
 MOVWF tmpL             ; tmp := weiterDM - dreiMS

 MOVF  tmpH, 0
 BTFSS STATUS, Z        ; wenn tmp >= 0x0100
 GOTO  keineExtraSek    ; dann gab's schon 'ne neue Sekunde vom Quarz
 MOVF  tmpL, 0
 SUBLW 0x96
 BTFSS STATUS, C        ; wenn tmp >= 0x0096 (= 150)
 GOTO  keineExtraSek    ; dann gab's schon 'ne neue Sekunde vom Quarz

 BTFSS Stati,1          ; wenn der Funk spinnt, wird nicht an der Zeit gespielt!
 CALL  Sek
keineExtraSek
 BTFSS Stati,1          ; wenn der Funk spinnt, wird nicht an der Zeit gespielt!
 CALL  setzeWeiterDM    ; neue Marke setzen
 GOTO  FlankenZeitSpeichern

periodenFehler          ; wenn die Pegelperiode nicht stimmt, muss
                        ; trotzdem mindestens die Zeitmarke gesetzt werden
 BSF   Stati, 1
FlankenZeitSpeichern
 MOVF  dreiMSL, 0
 MOVWF dZFlL
 MOVF  dreiMSH, 0
 MOVWF dZFlH
 RETURN                 ; FlankeGefunden

neueFunkMinute
 MOVLW 0x10             ; dat7, 5 ist das 0. Bit in Wikipediazählweise
 XORWF dat7, 0
 ANDLW 0x3F
 BTFSS STATUS, Z        ; Anfang nicht korrekt durchgeschoben?
 RETURN

 BTFSS dat4, 1          ; 20. Bit sollte immer 1 sein!
 RETURN

 BCF   Stati, 2
 BTFSC dat5, 5          ; 16. Bit (MEZ/MESZ-Umstellung)
 BSF   Stati, 2

 MOVLW 0xC0
 ANDWF dat5, 0
 XORLW 0x40
 BTFSC STATUS, Z        ; 17. & 18. Bit -> Sommerzeit!
 BSF   Stati, 3
 XORLW 0xC0
 BTFSC STATUS, Z        ; 17. & 18. Bit -> keine Sommerzeit!
 BCF   Stati, 3         ; Im Falle von Fehlern werden diese Bits ignoriert!

 BCF   Stati, 4
 BTFSC dat4, 0          ; 19. Bit -> Schaltsekunde am Ende der Stunde?
 BSF   Stati, 4

 RRF   dat3, 0
 MOVWF tmpH
 RRF   dat4, 0
 MOVWF tmpL             ; (dat3;dat4) eins verschoben merken
 RRF   tmpH, 1
 RRF   tmpL, 1          ; noch eins verschieben
 MOVF  tmpL, 0          ; -> bit21..bit28 (Minute mit Parität)
 MOVWF tmpH             ; Parität prüfen:
 RRF   tmpH, 1
 XORWF tmpH, 1          ; benachbarte Bits XORen
 MOVF  tmpH, 0
 RRF   tmpH, 1
 RRF   tmpH, 1
 XORWF tmpH, 1          ; Übernächste Nachbarn XORen
 MOVF  tmpH, 0
 RRF   tmpH, 1
 RRF   tmpH, 1
 RRF   tmpH, 1
 RRF   tmpH, 1
 XORWF tmpH, 1          ; üüübernächste Nachbarn XORen
 BTFSC tmpH, 0          ; gerade Parität!
 GOTO  Funkminutenfehler
 MOVF  tmpL, 0
 ANDLW 0x0F
 SUBLW 0x09
 BTFSS STATUS, C        ; Minuteneiner >9 ?
 GOTO  Funkminutenfehler
 MOVF  tmpL, 0
 ANDLW 0x70
 SUBLW 0x50
 BTFSS STATUS, C        ; Minutenzehner >5 ?
 GOTO  Funkminutenfehler
 MOVF  tmpL, 0
 ANDLW 0x7F             ; Parität löschen
 MOVWF Minute           ; Minute setzen
 CLRF  Sekunde          ; Sekunde auf 0
 CALL  setzeWeiterDM    ; Sekunde auf ,0
 BSF   Stati, 6
Funkminutenfehler

 RRF   dat2, 0
 RRF   dat3, 0
 MOVWF tmpL             ; (dat3;dat4) eins verschoben merken
 RRF   tmpL, 0          ; noch eins verschieben
 ANDLW 0x7F             ; falsche Bits löschen
 MOVWF tmpL             ; -> bit29..bit25 (Stunde mit Parität)
 MOVWF tmpH             ; Parität prüfen:
 MOVWF tmpH
 RRF   tmpH, 1
 XORWF tmpH, 1          ; benachbarte Bits XORen
 MOVF  tmpH, 0
 RRF   tmpH, 1
 RRF   tmpH, 1
 XORWF tmpH, 1          ; Übernächste Nachbarn XORen
 MOVF  tmpH, 0
 RRF   tmpH, 1
 RRF   tmpH, 1
 RRF   tmpH, 1
 RRF   tmpH, 1
 XORWF tmpH, 1          ; üüübernächste Nachbarn XORen
 BTFSC tmpH, 0          ; gerade Parität!
 GOTO  Funkstundenfehler
 MOVF  tmpL, 0
 ANDLW 0x0F
 SUBLW 0x09
 BTFSS STATUS, C        ; Stundeneiner >9 ?
 GOTO  Funkstundenfehler
 MOVF  tmpL, 0
 ANDLW 0x30
 SUBLW 0x20
 BTFSS STATUS, C        ; Stundenzehner >2 ?
 GOTO  Funkstundenfehler
 MOVF  tmpL, 0
 ANDLW 0x3F
 SUBLW 0x23
 BTFSS STATUS, C        ; Stunde >23 ? (ohne Einerüberprüfung!)
 GOTO  Funkstundenfehler
 MOVF  tmpL, 0
 ANDLW 0x3F
 MOVWF Stunde           ; Stunde setzen
 BSF   Stati, 7
Funkstundenfehler

 RETURN                 ; neueFunkMinute

setzeWeiterDM           ; setzt weiterDM-Zähler auf nächste 1/300s-Zeit
 MOVLW 0x01
 ADDWF dreiMSH, 0
 MOVWF weiterDMH        ; high-Teil + 1
 MOVLW 0x2C
 ADDWF dreiMSL, 0       ; low-Teil + 44
 BTFSC STATUS, C
 INCF  weiterDMH, 1     ; Übertrag
 MOVWF weiterDML
                        ; -> /300

 RETURN                 ; setzeWeiterDM

#ifdef Mengenlehreuhr
BCD2Un5L                ; bcd zu unär (5er, low-teil)
 SUBLW 0x09
 SUBLW 0x04
 BTFSC STATUS, DC       ; 5er an?
 GOTO BCD2Un5LUng
 ADDLW 0x05
 ANDLW 0xF0
 BTFSC STATUS, Z        ; =0 ?
 RETLW 0x00
 XORLW 0x10
 BTFSC STATUS, Z        ; =10 ?
 RETLW 0xC0
 XORLW 0x30
 BTFSC STATUS, Z        ; =20 ?
 RETLW 0xF0
 XORLW 0x10
 BTFSC STATUS, Z        ; =30 ?
 RETLW 0xFC
 RETLW 0xFF             ; >=40
BCD2Un5LUng             ; 5er muss gesetzt werden
 ANDLW 0xF0
 BTFSC STATUS, Z        ; =5 ?
 RETLW 0x80
 XORLW 0x10
 BTFSC STATUS, Z        ; =15 ?
 RETLW 0xE0
 XORLW 0x30
 BTFSC STATUS, Z        ; =25 ?
 RETLW 0xF8
 XORLW 0x10
 BTFSC STATUS, Z        ; =35 ?
 RETLW 0xFE
 RETLW 0xFF             ; >=40

BCD2Un5H                ; bcd zu unär (5er, high-teil)
 SUBLW 0x09
 SUBLW 0x04
 BTFSC STATUS, DC       ; 5er an?
 GOTO BCD2Un5HUng
 ADDLW 0x05
 ANDLW 0xF0
 XORLW 0x50
 BTFSC STATUS, Z        ; =50 ?
 RETLW 0x06
 RETLW 0x00             ; <=40
BCD2Un5HUng             ; 5er muss gesetzt werden
 ANDLW 0xF0
 XORLW 0x40
 BTFSC STATUS, Z        ; =45 ?
 RETLW 0x04
 XORLW 0x10
 BTFSC STATUS, Z        ; =55 ?
 RETLW 0x07
 RETLW 0x00             ; <=40

BCD2Un                  ; bcd zu unär (1er)
 ANDLW 0x0F
 BTFSC STATUS, Z        ; =0 ?
 RETLW 0x00
 XORLW 0x01
 BTFSC STATUS, Z        ; =1 ?
 RETLW 0x08
 XORLW 0x03
 BTFSC STATUS, Z        ; =2 ?
 RETLW 0x0C
 XORLW 0x01
 BTFSC STATUS, Z        ; =3 ?
 RETLW 0x0E
 XORLW 0x07
 BTFSC STATUS, Z        ; =4 ?
 RETLW 0x0F
 XORLW 0x01
 BTFSC STATUS, Z        ; =5 ?
 RETLW 0x00
 XORLW 0x03
 BTFSC STATUS, Z        ; =6 ?
 RETLW 0x08
 XORLW 0x01
 BTFSC STATUS, Z        ; =7 ?
 RETLW 0x0C
 XORLW 0x0F
 BTFSC STATUS, Z        ; =8 ?
 RETLW 0x0E
 RETLW 0x0F

#endif

 END