Hallo,
ich habe versucht mir einen DCF77-Empfänger zu programmieren. sobald das
L-Signal vom Empfänger kommt wird ein interrupt an PD2 ausgelöst, das
programm zählt ca 100ms und prüft ob das Signal immer noch L ist, um
eine 1 oder eine 0 im Signal festzustellen, dies wird dann im T-Bit
gespeichert und je nach sekundenzahl ins passende Register geschoben.
Die Pause in der 59. sekunde soll von einem Compare interrupt am Timer1
erkannt werden und den sekundenzähler wieder auf 0 setzen, dass Problem
liegt allerdings darin, dass das ganze Programm nicht mehr funktioniert,
sobald ich den Timer im Programm einschalte, er scheint viel zu schnell
zu Zählen, kann mir jemand sagen was ich falsch mache?
Im Programm habe ich einige Ausgabebefehle integriert, in der hoffnung,
dass ich den Fehler finde, allerdings vergebens...
Quelltext:
.include "m16def.inc"
.org 0000
rjmp init
.org int0addr
rjmp int0routine
.org OC1Aaddr
rjmp secpause
.equ xtal = 8000000
.def minute = r24
.def stunde = r23
init:
ldi r16, low(ramend)
out spl, r16
ldi r16, high(RAMEND)
out sph, r16
ldi r16, 0xff ;Portb->Ausgang
out ddrb, r16
out ddrc, r16 ;auch
out ddra, r16 ;nochmal
ldi r16, 0x00 ;Portd->Eingang
out ddrd, r16
ldi r16, 0b00000010 ;INT0 konfigurieren
out MCUCR, r16
ldi r16, 0b01000000 ;INT0 aktivieren
out GICR, r16
ldi r16, 0b00000101 ;Timer1 aktivieren, teiler 1024
out tccr1b, r16
ldi r16, 0b00010000 ;Interrupt bei Compare A Match
out timsk, r16
ldi r16, 0xff ;Compare A Match wert festlegen
out ocr1al, r16
ldi r16, 0x20
out ocr1ah, r16
ldi r25, 0xff
ldi r16, 0b01010101
out porta, r16
sei
loop:
;bld r16, 5
;com r16
in r20, porta
mov r16, r25
com r16
out portb, r16
mov r16, minute
com r16
out portc, r16
rjmp loop
;***************************Entscheidung über 1 oder
0*******************
;100ms 0V = Logisch 0 200ms 0V = Logisch 1
int0routine:
cli
;push r16
ldi r16, 0x00
out tcnt1h, r16
out tcnt1l, r16
rcall count
;pop r16
inc r25 ;sekundenzähler erhöhen
clt ;T-Flag wird gelöscht
sbis portd, 2
set ;T-Flag wird gesetzt
rjmp savedcf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Hier wird anhand des Sekundenzählers der richtige speicherort
;für jedes bit bestimmt.
savedcf:
cpi r25, 0
breq ausgabe
cpi r25, 21
brlo end
breq min1
cpi r25, 22
breq min2
cpi r25, 23
breq min4
cpi r25, 24
breq min8
cpi r25, 25
breq min10
cpi r25, 26
breq min20
cpi r25, 27
breq min40
cpi r25, 28
breq end
cpi r25, 29
breq std1
cpi r25, 30
breq std2
cpi r25, 31
breq std4
cpi r25, 32
breq std8
cpi r25, 33
breq std10
cpi r25, 34
breq std20
rjmp end ;35 aufwärts un 1-20 wird ausgeblendet
min1:
bld minute, 0
rjmp end
min2:
bld minute, 1
rjmp end
min4:
bld minute, 2
rjmp end
min8:
bld minute, 3
rjmp end
min10:
bld minute, 4
rjmp end
min20:
bld minute, 5
rjmp end
min40:
bld minute, 6
rjmp end
std1:
bld stunde, 0
rjmp end
std2:
bld stunde, 1
rjmp end
std4:
bld stunde, 2
rjmp end
std8:
bld stunde, 3
rjmp end
std10:
bld stunde, 4
rjmp end
std20:
bld stunde, 5
rjmp end
end:
sei
reti
ausgabe:
;out portb, stunde
ldi stunde, 0x00
ldi minute, 0x00
sei
reti
;Verzögerung
count:
ldi r16, 0x00
ldi r17, 0x00
count_1:
inc r16
cpi r16, 0xff
brne count_1
inc r17
cpi r17, 90
brne count_1
ret
;*********************secPause******************************
secpause:
;push r16
ldi r16, 0x00
out tcnt1h, r16
out tcnt1l, r16
ldi r25, 0xff
;pop r16
com r20
out porta, r20
reti
Gruß
Jochen
Hi > ldi r16, 0xff ;Compare A Match wert festlegen > out ocr1al, r16 > ldi r16, 0x20 > out ocr1ah, r16 Datenblatt: To do a 16-bit write, the high byte must be written before the low byte. For a 16-bit read, the low byte must be read before the high byte. In fast allen Datenblättern gibt es einen Punkt:'Accessing 16-bit Registers' MfG Spess
Danke, das hat mir schon um einiges weitergeholfen, allerdings zählt mein sekundenzähler relativ warlos, an was kann das liegen, evtl. an empfangsstörungen? Gruß Jochen
Hi Ich nehme an, das deine 100ms Abfrage kritisch ist. Also evtl. zu knapp. Ich habe das damals anders gelöst: Bei der Startflanke wird der Zähler auf Null gesetzt. Dann wird das Ende des Impulses abgewartet und danach der Zählerstand abgefragt. Zwischen 50 und 150 ms eine Null, bei >150 und <250 eine Eins. >250 Schaltsekunde. Nur so vom Prinzip her. MfG Spess
Ich mach es auch so ähnlich wie Spess, allerdings pin-change interrupt da int0/1 schon belegt sind. damit ist auch die zustands/flanken sache egal und es ist auch egal ob der high- oder low-aktive ausgang des dcf-modules verwendet wird. dann einen timer der alle 10ms um 1 hochzählt und im pinchange-int den zähler wert testen. hat den vorteil das ich auch einfach empfangsstörungen ausbügeln kann, z.b. alles kleiner als 80ms kann nur eine störung sein, alles über etwa 240ms bis 780ms kann auhc nur eine störung sein. erreicht der timer 255 ist es ein time-out und somit kein signalempfang. den timer resete ich nicht am ende des 100/200ms puls sondern beim beginn der des nächsten 100/200ms puls, damit lässt sich der minuten-puls über 1800 bzw. 1900ms auch detektieren. die bits shifte ich einfach aus dem carry in den sram und beim minuten-puls dann von dort wieder per shift um x stellen bis zur gewünschten info, konvertieren, weitershiften bis zur nächsten. parity lässt sich damit auch recht einfach prüfen. funktioniert in wien mit schlechtem empfang nicht mal so schlecht, einzig in den abendstunden wenn rundherum die tv-geräte laufen klappt es öfter mal nicht. aja und das ganze in asm auf einem mega168 mit 20mhz. wobei die hohe taktfrequenz freilich nicht notwendig ist für dcf, klar.
Hi Viele Wege führen nach Rom. Mein Verfahren ist auch nicht unbedingt das Nonplusultra. Ich hatte nur im Rahmen dieser 'DCF... Wetter...'-Diskussion mal eigene Aufzeichnungen gemacht und dafür schnell was 'zusammengeschossen'. Hat aber erstaunlich gut funktioniert. MfG Spess
Guten Morgen, Ist im Prinzip eh sehr einfach... außer man hat schlechten empfang und immer wieder störungen im signal. Und da find ich das verfahren das du ja auch anwendest (timer und vergangene Zeit auswerten) am einfachsten, auswertung im hintergrund via isr-routinen ist möglich und es lässt sich einfach erweitern um eben die störsignale mithilfe von zeitfenstern zu ignorieren. kommt natürlich ein störsignal innerhalb eines "gültigen" zeitfensters und das 2x dann kanns mit der parity auch schon schwierig werden. -> plausibilitätstests wie 0<=sek/min=<59 usw. helfen dann auch noch. aber bei gutem empfang ist die sache ja eigentlich sehr einfach, bzw. in der praxis welche der theorie noch am ehesten entspricht ;) schönen tag, mfg, Martin.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.