Hallo
ich habe ein Problem was mich mittlerweile echt verrückt macht!
Folgendes Programm:
1
/*
2
* TLW_DCF77.c
3
*
4
* Created: 28.02.2014 16:15:07
5
* Author: Tony Bauer
6
*/
7
8
#define F_CPU 16000000L
9
#define byte unsigned char
10
#define dcf_in PINB
11
#define dcf_pin PINB2
12
13
#include<util/delay.h>
14
#include<avr/io.h>
15
#include<stdlib.h>
16
#include<stdint.h>
17
#include<avr/interrupt.h>
18
19
//Variablen
20
intdcf_high=0,dcf_low=0;//DCF-Pegelzeiten
21
22
intmain(void)
23
{
24
//PORT-SetUp
25
DDRB=0x00;
26
DDRD=0xFF;
27
DDRC=0x00;
28
29
//Timer0 Initialisierung
30
TCCR0=0x05;//TimerCounterControlRegister Calibrierung des Prescale
31
TCNT0=0xEF;//TimerCouNTer-Wert, Hier: Vorspannen um 1ms Schritte zu erhalten
32
TIMSK=0x01;//TimerInterruptMaSK
33
sei();//Global Interrupts erlauben
34
35
36
dcf_sync();
37
38
while(1)
39
{
40
if(!(dcf_in&(1<<dcf_pin))){
41
if(dcf_high>=60&dcf_high<=140)
42
{
43
PORTD=(0<<PD5);
44
dcf_high=0;
45
}
46
47
if(dcf_high>=170&dcf_high<=230)
48
{
49
PORTD=(1<<PD5);
50
dcf_high=0;
51
}
52
}
53
54
if((dcf_high+dcf_low)>=1000)
55
{
56
//dcf_decoder();
57
}
58
}
59
}
60
61
62
ISR(TIMER0_OVF_vect){
63
TCNT0=0xEF;
64
65
if(dcf_in&(1<<dcf_pin))
66
{
67
dcf_high++;
68
}
69
else
70
{
71
dcf_low++;
72
}
73
74
}
75
76
voiddcf_sync(){
77
78
if(dcf_in&(1<<dcf_pin))
79
{
80
if(dcf_low>=1600)
81
{
82
dcf_high=0;
83
dcf_low=0;
84
PORTD=(1<<PD5);
85
_delay_ms(500);
86
PORTD=(0<<PD5);
87
_delay_ms(500);
88
}
89
else
90
{
91
dcf_low=0;
92
dcf_high=0;
93
dcf_sync();
94
}
95
}
96
else
97
{
98
dcf_sync();
99
}
100
}
Wenn ich dcf_sync() aufrufe soll dann eine LED Kurz bescheid geben
(durch blinken, an PD5) das die Synchro statt gefunden hat.
Danach sollte der µC ja eigentlich in die Main-Loop (while(1)) gehen..
Alles in Betrieb genommen blinkt die LED Aber durchgängig, was erstens
komisch is, da der Wert von LOW eigentlich nur einmal in der Minute über
die knapp 1600(ms) kommt, und vorallem: Wenn das blinken ausgeführt
wurde, dann sollte die Funktion eig. zu Ende gehen und (da vor der
Main-Loop) nicht wieder aufgerufen werden..
Wo Liegt Hier Mein Fehler?
Viele Grüße!
PS.: Wie ihr durch scharfes Hinsehen bemerken Könnt handelt es sich um
ein DCF-Projekt.. Verwendet wird das Modul von Pollin, daher is das
absenken der Frequenz invertiert und das am µC Pin liegt bei "0" 100ms
HIGH an und bei "1" 200ms HIGH. Dessweiteren wurde eine
Pegelwandlerschaltung an zwischen DCF Modul und AVR gehängt, es liegen
mit dem OSZI gemessen 5,01V am AVR Pin der selbst auf 5,02V Läuft.. also
eindeutig Klares HIGH.
Hab auserdem die HIGH- Flanke des DCF-Signals am AVR mit ner Zeitbasis
von 5µs angeschaut um auszuschliesen, dass da irgendwas schwingt.
So jetz aber:) Danke!
@Holger:
Das ist gewollt! Dcf_synch ruft sich solange selber auf, bis die
Synchronisation abgeschlossen ist. Das is dann der Fall, wenn das Signal
(59. Bit) bis mindestens 1600ms abgesenkt bleibt. Solang das nicht der
Fall ist, soll die Funktion schleife laufen.
Deshalb ist dies der einzige Teil der If-Schleife indem das dcf_sync()
nicht vorkommt :)
@Hubert:
Ja :)
Tut ja hier leider noch gar nicht zur Sache, da die While(1) Loop gar
nicht erst erreicht wird. Habe allerdings diesen Teil der Main-Loop
bereits getestet und er Funktioniert! :)
Ich drehe ja scheinbar runden in der dcf_sync... und zwar dummerweise in
dem Teil der Funktion, in dem eigentlich das verlassen Ebendieser
Funktion geschehen soll.
Es ist Programmtechnisch eigentlich nicht möglich, es sei denn das
Programm läuft nach verlassen der Funktion nicht da weiter wo es in die
Funktion gesprungen ist, sonder wieder bei void main()... und das ist
soweit ich weis NICHT der Fall bei C.. liege ich richtig?
Viele Grüße und vielen Dank für die schnelle Antwort! :)
Bin ja immer wieder erstaunt, wenn man mal Code von anderen Leuten
sieht, die komplett anders denken als man selbst. @Tony: Warum baust du
denn dein Programm so merkwürdig verschachtelt und kompliziert auf.
Meinste nicht das geht auch einfacher?
@Holger:
Welcher Stack? Und was sollte das für Auswirkungen haben.
@Hansi:
Ja das kann schon sein Hansi :D
Vorschläge wie ich das 59. Bit einfacher erkennen kann und so eine
Synchro durchführen kann BEVOR das Programm im eigentlichen vor sich hin
werkelt und vorallem alles so, dass ich später per Funktionsaufruf
einfach eine Synchro wiederholen kann ohne den Chip zu reseten.. Sollte
ja möglich sein falls es mal zu Empfangsproblemen kommt. ;)
Viele Grüße!
Bastler schrieb:> Setzen, sechs!
Danke, ich steh lieber!
Das Hier ist ein Forum!! Wenn du es weist, bitte kläre mich auf und spar
dir deine sinnfreien Kommentare!
Ich weis das nach dem LIFO Prinzip mit Daten gehandelt wird im µC! Doch
das sollte bei diesem Programm zu keinen Problemen Führen! Deshalb die
Frage "welcher" Stack hier gemeint ist!
Viele Grüße
Tony schrieb:> @Holger:> Welcher Stack? Und was sollte das für Auswirkungen haben.>
Der "Stack" ist ein Speicher (meist ein Bereich im RAM), indem das
Programm die Rücksprungadresse ablegt und die Variablen und Parameter
anlegt, die lokal in einer Funktion (in C nicht static) definiert
werden. Wenn Du eine rekursive Funktion hast, dann wird der Bereich
x-mal benötigt.
Je nach Prozessor hat man aber nur sehr wenig RAM (z.B. 128, 256 Bytes).
Da können 59 rekursive Funktionsaufrufe schnell das "Ende" des
deterministischen Programmablaufs bedeuten.
Aber man kann eine Rekursion auch in eine Resourcen schonende Iteration
umwandeln.
Lies dir doch deine Daten in ein struct ein, dann ist Schluss mit Bits
zählen. Wenn du INT0/1 benutzt dann kriegst du die Flankenerkennung
geschenkt. Und das Togglen der LED packste in eine extra Funktion. Mach
die Rekursion weg.
>Ich weis das nach dem LIFO Prinzip mit Daten gehandelt wird im µC! Doch>das sollte bei diesem Programm zu keinen Problemen Führen!
Das tut es aber. Man ruft Funktionen nicht ungestraft rekursiv auf.
Mit jedem Aufruf der Funktion wandert der Stack ein wenig im RAM
runter und zerstört dir irgendwann den Datenbereich. Wobei
irgendwann bei dir nur ein paar Mikrosekunden bedeutet.
@Achim:
Vielen Dank! Das macht Sinn. :)
Aber wie kann ich das in diesem Fall so lösen, dass die Funktion bis zur
Synchro Läuft und dann trotzdem noch die Rücksprungadresse vorhanden
ist?
Könnte ich das ganze einfach mit Übergabe der dcf_* Parameter und mit
return werten lösen? Weil dann wären die Variablen ja nicht im Stack,
hab ich das richtig verstanden?
Danke für diese qualifizierte Antwort!
Viele Grüße
..Tschuldigung nicht schnellgenug:
Das mit dem INT habe ich bewusst nicht gemacht, da hierbei noch eine RTC
ins Spiel kommt später, die dann über den ms Takt des Timers läuft...
Ungenauigkeit hin oder her.. wird ja wieder mit dem DCF Synchronisiert.
Wie ist das mit STRUCT gemeint? Habe da noch nicht so die Erfahrung!
Danke!
Und nochmal, sorry wegen MultiPost.
Kann ich quasi einfach so ein struct Datentyp verwenden für meine
dcf_low, dcf_high Werte und diese dann viel Pointer aufrufen?
Umgehe ich damit das Problem?
Danke auch den Übrigen :)
Tony schrieb:> @Achim:>> Vielen Dank! Das macht Sinn. :)> Aber wie kann ich das in diesem Fall so lösen, dass die Funktion bis zur> Synchro Läuft und dann trotzdem noch die Rücksprungadresse vorhanden> ist?> Könnte ich das ganze einfach mit Übergabe der dcf_* Parameter und mit> return werten lösen? Weil dann wären die Variablen ja nicht im Stack,> hab ich das richtig verstanden?>> Danke für diese qualifizierte Antwort!> Viele Grüße
Sobald Du eine Funktion aufrufst, wird zumindest die Rücksprungadresse
vom Compiler im Stack gespeichert. Und auch Pointer Parameter benötigen
Platz im Stack. Da Deine Rekursion auch sehr schnell sich Rekursiv
aufruft, hast Du keine Chance, Du musst diese in eine Iteration
überführen. Beim "wie" möchte ich Dir einfach eine Gegenfrage stellen:
möchtest Du Lernen oder brauchst Du nur einen DFC77
Empfänger/Dekodierer? Solche Programme findet man hier im Forum durchaus
auch fertig (und sogar mit Filter, damit Störungen nicht zu stark
durchschlagen). Wenn Du Lernen willst, das mit der Rekursion / Iteration
findet man sicher über google.
> int dcf_high = 0, dcf_low = 0;
Wenn Du dann Deine Rekursion umgebaut hast, lese doch mal
http://www.mikrocontroller.net/articles/FAQ
besonders "10 Was hat es mit volatile auf sich" durch.
Achim K. schrieb:> Beim "wie" möchte ich Dir einfach eine Gegenfrage stellen:> möchtest Du Lernen oder brauchst Du nur einen DFC77> Empfänger/Dekodierer?
Ganz Klar: Lernen!
Ich werde mich Morgen mal damit befassen, danke für die Hilfe. Wenn sich
nochwas ergibt an Fragen, melde ich mich nochmal.
Schön Abend!
Bis Später
Over an Out.
>Ganz Klar: Lernen!
Dann fang mal an mit Bitmanupilation.
http://www.mikrocontroller.net/articles/Bitmanipulation
Vieleicht verstehst du dann das diese beiden Zeilen
nicht unbedingt das tun was du möchtest.
PORTD = (1<<PD5);
PORTD = (0<<PD5);