Forum: Mikrocontroller und Digitale Elektronik ATmega / falsche delay-Zeiten


von __Son´s B. (bersison)


Lesenswert?

Hallo, finde folgenden Fehler nicht heraus;
(1) LED blinkt nicht im 200ms- sondern im 2Sek-Takt
(2) Warnmeldungen bei den Variablen, Bsp: "conflicting types for 
'warte_ms'
(3) Kann man alle Variablen-Def., zur besseren main-Lesbarkeit in einer 
"Variablen"-Funktion unterbringen?
_____________________________
#include  <avr/io.h>
#define    F_CPU 8000000Hz
#include  <util/delay.h>

int main(void)
{
  DDRA = 0x00;
  DDRB = 0xFF;
  int led_nr =0;
  int mil_sek =0;
  int zaehler =0;

  start:;
  PORTB = 0b11111111;

  while (PINA != 0b11111110)
  {
      blink_led(0);
  }

  goto start;
  return 0;
}


void blink_led(led_nr)
{
  PORTB ^= (1<<led_nr); // toggel
  warte_ms(200); //200ms
}

void warte_ms(mil_sek)
{
  for (int zaehler=0; zaehler<=mil_sek; zaehler++)
    _delay_ms(1); //1ms
}

von Karl H. (kbuchegg)


Lesenswert?

__Son´s Bersi__ schrieb:
> Hallo, finde folgenden Fehler nicht heraus;
> (1) LED blinkt nicht im 200ms- sondern im 2Sek-Takt

Das kann man mit zugekniffenem Auge als einen Faktor 8 werten.


> #define    F_CPU 8000000Hz

Womit diese Angabe unglaubwürdig wird.
Dein AVR läuft nicht mit 8Mhz sondern mit 1Mhz. Also 8-mal langsamer als 
gedacht. Und dann stimmt wieder alles.

Also. Fuses kontrollieren. Bei F_CPU kannst du hinschreiben was dir 
gefällt. Das juckt den AVR wenig. Der richtet sich nach seinen Fuses wie 
schnell er wirklich läuft. Und nur dann, wenn F_CPU mit dieser Realität 
übereinstimmt, dann stimmen auch die delay Zeiten.

von Karl H. (kbuchegg)


Lesenswert?

Und kauf dir ein C-Buch und arbeit6e es von vorne bis ungefähr zum Ende 
des ersten Drittels durch.
Du kannst nicht einfach Dinge hinschreiben wie du sie denkst und hoffen, 
dass der Compiler schon was draus machen wird. Auch Programmiersprachen 
haben so etwas wie eine Grammatik, die man lernen muss.

von Karl H. (kbuchegg)


Lesenswert?

1
#define    F_CPU 8000000
2
3
#include  <avr/io.h>
4
#include  <util/delay.h>
5
#include  <stdint.h>
6
7
void warte_ms(int mil_sek)
8
{
9
  for (int zaehler = 0; zaehler < mil_sek; zaehler++)
10
    _delay_ms( 1 ); //1ms
11
}
12
13
void blink_led(uint8_t led_nr)
14
{
15
  PORTB ^= (1<<led_nr); // toggle
16
  warte_ms( 200 );
17
}
18
19
int main(void)
20
{
21
  DDRA = 0x00;
22
  DDRB = 0xFF;
23
24
  while( 1 )
25
  {
26
    PORTB = 0b11111111;
27
28
    while ( PINA != 0b11111110 )
29
    {
30
      blink_led( 0 );
31
    }
32
  }
33
34
  return 0;
35
}



In deinem eigenen Interesse streichst du jetzt erst mal das Wort 'goto' 
aus deinem Wortschatz. Wenn du in einem halben Jahr etwas Erfahrung 
gesammelt hast, kannst du es wieder mit aufnehmen. Aber dann wirst du 
gelernt haben, dass du es eigentlich nie brauchst. Es gibt derartige 
Fälle - sie sind aber selten. Ich hab in 30 Jahren 
Industrieprogrammierung ein einziges mal einen goto eingesetzt. Und 
selbst der war eigentlich unnötig und in 5 Minuten ausgebaut und durch 
etwas besseres ersetzt.

von __Son´s B. (bersison)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Du kannst nicht einfach Dinge hinschreiben wie du sie denkst und hoffen,

Wenn du die Variabl. meinst, die wollte ich blockartig = übersichtlicher 
deklarieren. Fehler?

Zur weiteren Transparenz, hatte ich das main nach oben geschrieben. 
Fehler?

von Mike R. (thesealion)


Lesenswert?

__Son´s Bersi__ schrieb:
> Karl Heinz Buchegger schrieb:
> Wenn du die Variabl. meinst, die wollte ich blockartig = übersichtlicher
> deklarieren. Fehler?

Kurz: Ja
Etwas länger: So wie du deine Variablen deklariert hast machen sie 
keinen Sinn. 100% davon sind in main sogar unnötig und werden überhaupt 
nicht verwendet.

> Zur weiteren Transparenz, hatte ich das main nach oben geschrieben.
> Fehler?

Kurz: Ja
Länger: Eigentlich müsste dir der Compiler hier einige Warnung zeigen, 
da er von oben nach unten arbeitet und damit zum Beispiel "blink_led()" 
nicht kennt, wenn du es in main aufrufst.

von Stefan (Gast)


Lesenswert?

Variablen, die Du innerhalb einer Funktion deklarierst, sind auch nur 
dort erreichbar. Sie liegen im STACK Bereich des RAM. Dass heisst, 
sobald die Funktion verlassen wird, gibt's die Variablen auch nicht 
mehr. Ihre Werte gehen verloren. Diese Variablen werden nicht 
automatisch initialisiert, wenn Du keinen Startwert angibst.

Variablen, die Du außerhalb jeder Funktion deklarierst, sind im ganzen 
Programm erreichbar. Sie werden VOR dem Start der main() Funktion 
automatisch initialisiert, auch wenn Du keinen Startwert angibst 
(Default=0).

Parameter von Funktionen müssen einen Typ haben, deswegen erhälst Du 
eine Fehlermeldung.

Falsch: void warte_ms(mil_sek)

Richtig: void warte_ms(int mil_sek)

Goto führt in größeren Programmen sehr oft zu mangelhafter Lesbarkeit. 
Deswegen lernt man, goto wie die Pest zu vermeiden. Endlosschleifen kann 
man alternativ so schreiben (erzeugt den selben Maschinencode):

while (1) {
  ...
}

Oder:

for (;;) {
 ...
}

Wobei die Variante mit while häufiger anzutreffen ist.

von Stefan (Gast)


Lesenswert?

By the way:

_delay_ms kann auch 200ms lang warten. Die Doku sagt dazu:

> The maximal possible delay is 262.14 ms / F_CPU in MHz.

Und weiter heisst es:

> When the user request delay which exceed the maximum possible one,
> delay_ms() provides a decreased resolution functionality ...
> providing delays up to 6.5535 seconds.

von Karl H. (kbuchegg)


Lesenswert?

__Son´s Bersi__ schrieb:
> Karl Heinz Buchegger schrieb:
>> Du kannst nicht einfach Dinge hinschreiben wie du sie denkst und hoffen,
>
> Wenn du die Variabl. meinst, die wollte ich blockartig = übersichtlicher
> deklarieren. Fehler?

Die erste Frage lautet: brauchst du denn die Variablen überhaupt?
Schau dir mein Programm an: Weit und breit nichts von diesen Variablen 
zu sehen.


Der nächste Punkt ist: Variablen haben einen Gültigkeitsbereich und 
damit gekoppelt einen Sichtbarkeitsbereich. Grob gesagt: Variablen sind 
in dem Block gpltig und sichtbar, in dem sie definiert sind (und in 
allen darin enthaltenen Blöcken. Der Block begrenzt die Sichtbarkeit - 
ausserhalb des Blockes existiert die Variable schlicht und ergreifend 
einfach nicht.
1
void foo()
2
{     // <----- hier beginnt ein Block, Block A
3
4
  int wert;    // <--- diese Variable ist nur innerhalb des Blockes
5
               //      bekannt, in dem sie definiert wurde
6
7
  if( ... )
8
  {              // ein weiterer Block (in den aeusseren reingeschachtelt)
9
                 // beginnt. Block B
10
11
    int j;       // diese Variable ist innerhalb von Block B definiert.
12
                 // Ihre Lebensdauer und damit ihre SIchtbarkeit wird
13
                 // durch diesen Block begrenzt.
14
15
    j = wert;    // das ist ok. j ist innerhalb von Block B definiert
16
                 // und wert ist eine Blockebene 'höher' definiert, weil
17
                 // ja Block B in Block A eingeschachtelt ist.
18
                 // Man kann es auch so sagen: einfach die Blockstruktur
19
                 // nach 'aussen' verfolgen und nachsehen ob es in diesem
20
                 // Block die angegebene Variable gibt
21
22
  }           // <--- hier wied Block B (der vom if) wieder geschlossen
23
              //      Alle Variablen in diesem Block existieren danach
24
              //      nicht mehr.
25
              //      In diesem konkreten Beispiel gibt es daher
26
              //      danach keine Variable j mehr
27
28
}         // <---- Der Block A wird geschlossen. Alle in diesem BLock
29
          //       enthaltenen Variablen gibt es danach nicht mehr.
30
          //       D.h. hier endet die Lebensdauer und damit auch
31
          //       Sichtbarkeit von wert. Ausserhalb dieses Blocks gibt
32
          //       es keine Variable 'wert' und wenn es doch eine Variable
33
          //       dieses Namens gibt, dann handelt es sich dabei
34
          //       um eine andere Variable.

> Zur weiteren Transparenz, hatte ich das main nach oben geschrieben.
> Fehler?

Lies deinen Code von oben nach unten. So wie es auch der Compiler macht. 
Und halte dich an den einfachen Grundsatz: Benutzt werden kann nur das, 
was auch bekannt ist. Wenn du eine Funktion aufrufen willst, dann hat 
die eine Funktionssignatur. Die muss bekannt sein, ehe man sie aufruft.
Durch die Reihenfolge
1
void foo( void )
2
{
3
  ...
4
}
5
6
int main()
7
{
8
  foo();
9
}

ist automatisch die Funktionssignatur dem Compiler bekannt gemacht 
worden, ehe die Funktion benutzt wird. Schreibst du das anders rum
1
int main()
2
{
3
  foo();
4
}
5
6
void foo( void )
7
{
8
  ....
9
}

dann zwingst du den Compiler dazu, Standardannahmen zu treffen, wenn der 
den Aufruf der Funktion behandeln soll, ehe er die Funktion selbst zu 
Gesicht bekommt. Und in deinem Fall waren diese Standardannahmen eben 
falsch.

Lösen kann man das entweder durch Umdrehen der Reihenfolge, oder in dem 
man mittels eines Prototypen dem Compiler die Funktionssignatur bekannt 
gibt, ehe man die Funktion das erste mal aufrufen will
1
void foo( void );     // Ein Protoyp. Es gibt eine Funktions namens foo
2
                      //  und so sieht ihr Funktionskopf aus
3
4
int main()
5
{
6
  foo();              // Durch den Protoypen weiß der Compiler, wie er
7
                      // das hier behandeln muss und braucht keine
8
                      // ANnahmen treffen
9
}
10
11
void foo( void )      // Aber irgendwann muss natürlich auch mal die
12
{                     // Funktion selbst kommen. Bisher war da ja nur
13
   ...                // der Prototyp
14
}



Aber warum erklär ich dir das eigentlich (halbherzig), wo du das in 
jedem noch so grindigem C-Buch auf dutzenden Seiten in aller 
Ausführlichkeit nachlesen kannst?
Kauf dir ein C-Buch!

von __Son´s B. (bersison)


Lesenswert?

DANKE euch Beiden! Sehr aufschlussreich.

Toller Tip: while(1) statt goto

Hatte Warnmeldungen ignoriert, da hex-Programme einwandfrei liefen - 
werde ich ab jetzt korrekt schreiben.

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.