Forum: Mikrocontroller und Digitale Elektronik AVR-C Problem


von Tony (Gast)


Lesenswert?

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
int dcf_high = 0, dcf_low = 0;    //DCF-Pegelzeiten
21
22
int main(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
void dcf_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!

von holger (Gast)


Lesenswert?

dcf_sync() ruft sich selber auf. Das ist Mist.
1
void dcf_sync(){
2
  
3
  if (dcf_in & (1<<dcf_pin))
4
  {
5
    if (dcf_low >= 1600)
6
    {
7
...
8
    }
9
    else
10
    {
11
 ...
12
     dcf_sync();
13
    }
14
  }
15
  else
16
  {
17
    dcf_sync();
18
  }
19
}

von Hubert G. (hubertg)


Lesenswert?

Tony schrieb:
> (dcf_high >= 60 & dcf_high <= 140)

Schon mal über den Unterschied & und && nachgelesen?
Kommt des öfteren vor.

von Tony (Gast)


Lesenswert?

@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! :)

von holger (Gast)


Lesenswert?

>Das ist gewollt! Dcf_synch ruft sich solange selber auf, bis die
>Synchronisation abgeschlossen ist.

Vermutlich ist vorher der Stack übergelaufen.

von Hansi (Gast)


Lesenswert?

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?

von Tony (Gast)


Lesenswert?

@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!

von Bastler (Gast)


Lesenswert?

>Welcher Stack? Und was sollte das für Auswirkungen haben.

Setzen, sechs!

von Tony (Gast)


Lesenswert?

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

von Achim K. (aks)


Lesenswert?

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.

von Hansi (Gast)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

>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.

von Tony (Gast)


Lesenswert?

@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

von Tony (Gast)


Lesenswert?

..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!

von Tony (Gast)


Lesenswert?

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 :)

von Achim K. (aks)


Lesenswert?

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.

von Tony (Gast)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

>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);

von holger (Gast)


Lesenswert?

>>Ganz Klar: Lernen!
>
>Dann fang mal an mit Bitmanupilation.

Und ich les noch mal den Duden;)

von Tony (Gast)


Lesenswert?

holger schrieb:
> Und ich les noch mal den Duden;)

Is ja Kein Problem (:
Danke!

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
Noch kein Account? Hier anmelden.