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 }
__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.
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.
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.
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?
__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.
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.
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.
__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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.