Hallo, ich versuche gerade eine ATMEGA644 mit AVR Studio und WINAVR in C zu programmieren. Allerdings bekomme ich immer folgende Fehlermeldung, sobald ich Register des Controllers setzen will: error: expected identifier or '(' before 'volatile' Ich habe den Code zum debuggen auf ein Minimum reduziert: [c] #ifndef F_CPU #define F_CPU 20E6; #endif #include <AVR\interrupt.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <AVR\iom644.h> //#include <AVR\io.h> //#include "subroutines.c" //#include "interrupt_table.c" // Define data types typedef uint8_t BYTE; typedef uint16_t WORD; typedef uint32_t DWORD; typedef uint64_t QWORD; // define switch Positions fopr various Antenna testing #define Ant12 0b00100000; #define Ant13 0b10000000; #define Ant14 0b11000000; #define Ant21 0b00000100; #define Ant23 0b10000100; #define Ant24 0b11000100; #define Ant31 0b00010000; #define Ant32 0b00110000; #define Ant34 0b11010000; #define Ant41 0b00011000; #define Ant42 0b00111000; #define Ant43 0b10011000; #define setbit(PORT,BIT) ((PORT) |= (1<<(BIT))); #define clearbit(PORT,BIT) ((PORT) &= ~(1<<(BIT))); #define togglebit(PORT,BIT) ((PORT) ^= (1<<(BIT))); // Enable interrupts //sei(); // Enable Watchdog timer // WDCTCSR = 0b11001111 //********************************************************************** ************** DDRA = 0b10000000; //DDRB = 0x00; //DDRC = 0x00; //DDRD = 0b11111110; int main() { BYTE temp = 1; while (1<10) temp = temp; return 1; } [\c] Fehlermeldungen: ../test.c:51: error: expected identifier or '(' before 'volatile' ../test.c:51: error: expected ')' before '(' token Zeile 51 ist die DDRA = 0b10000000; Ich hoffe ihr könnt mir weiterhelfen.
> #define F_CPU 20E6; Da ist der erste Fehler. Und von der Sorte hat es in Deinem Code ein knappes Dutzend. Präprozessor-Anweisungen werden nicht mit einem Semikolon abgeschlossen! > DDRA = 0b10000000; Und das ist der eigentliche Fehler, der zu der Fehlermeldung führt. Ausführbarer Code (also jedwede Anweisung, ausgenommen Initialisierung globaler Variablen) darf in C nur innerhalb von Funktionen stehen. Diese Anweisung steht aber im Niemandsland. Schnapp Dir bitte ein C-Grundlagenbuch und fange Schritt für Schritt mit den Basics an, bevor Du mit irgendwelchen wilden Großprojekten anfängst. Und das AVR-GCC-Tutorial ist auch empfehlenswerter Lesestoff. Die Zeile > #include <AVR\iom644.h> ist z.B. auch falsch, die Device-spezifischen Header werden nie direkt eingebunden. Das müsste eigentlich auch zumindest eine Warnmeldung geben. Es wird nur die avr/io.h eingebunden. Der verwendete Controllertyp wird im Makefile bzw. in den Projekt-Konfigurations-Einstellungen angegeben.
> DDRA = 0b10000000;
Die Schreibweise der Konstanten 0b10000000 ist hier das Problem; in C
gibt es diese Schreibweise nicht.
Manche Compiler lassen das als Erweiterung des Sprachumfanges zu, aber
eben nur manche.
Du musst schon Oktal-, Dezimal- oder Hexadezimalzahlen verwenden:
DDRA = 0200;
DDRA = 128;
DDRA = 0x80;
Das kann dann auch jeder C-Compiler.
Rufus t. Firefly wrote: >> DDRA = 0b10000000; > > Die Schreibweise der Konstanten 0b10000000 ist hier das Problem; in C > gibt es diese Schreibweise nicht. Der AVR-GCC kennt diese Schreibweise mittlerweile aber auch! Der Fehler ist die falsche Platzierung der Anweisung außerhalb von main().
Wo lernt man eigentlich heutzutage, dass man alles koennen kann indem man einfach ein paar Beispiele aus dem Web zusammenklatscht? Anders kann ich mir die hilflosen Versuche hier im Forum, mal schnell C-Programme ohne jede Grundlagenarbeit (z.B: Buch kaufen + lesen) zu entwickeln, kaum erklaeren :-(
Und das hier
>
1 | > //#include "subroutines.c" |
2 | > //#include "interrupt_table.c" |
3 | >
|
ist zwar noch nicht scharfgeschaltet, wird aber zur nächsten Todsünde führen, wenn es denn mal aktiv wird.
> Der AVR-GCC kennt diese Schreibweise mittlerweile aber auch!
Auch wenn er das können sollte, angewöhnen sollte man sich derartiges
nicht.
Ja, das Codefragment strotzt nur so vor weiteren Fehlern.
Hätte der Threadersteller statt [\c] korrekt [/c] geschrieben, wäre sein
Code auch etwas lesbarer geworden.
1 | [c] |
2 | #ifndef F_CPU
|
3 | #define F_CPU 20000000;
|
4 | #endif
|
5 | |
6 | #include <AVR/interrupt.h> |
7 | #include <stdint.h> |
8 | #include <stdio.h> |
9 | #include <stdlib.h> |
10 | #include <math.h> |
11 | #include <AVR/iom644.h> |
12 | //#include <AVR/io.h>
|
13 | |
14 | //#include "subroutines.c"
|
15 | //#include "interrupt_table.c"
|
16 | |
17 | // Define data types
|
18 | typedef uint8_t BYTE; |
19 | typedef uint16_t WORD; |
20 | typedef uint32_t DWORD; |
21 | typedef uint64_t QWORD; |
22 | |
23 | |
24 | |
25 | // define switch Positions fopr various Antenna testing
|
26 | #define Ant12 0b00100000;
|
27 | #define Ant13 0b10000000;
|
28 | #define Ant14 0b11000000;
|
29 | #define Ant21 0b00000100;
|
30 | #define Ant23 0b10000100;
|
31 | #define Ant24 0b11000100;
|
32 | #define Ant31 0b00010000;
|
33 | #define Ant32 0b00110000;
|
34 | #define Ant34 0b11010000;
|
35 | #define Ant41 0b00011000;
|
36 | #define Ant42 0b00111000;
|
37 | #define Ant43 0b10011000;
|
38 | |
39 | #define setbit(PORT,BIT) ((PORT) |= (1<<(BIT)));
|
40 | #define clearbit(PORT,BIT) ((PORT) &= ~(1<<(BIT)));
|
41 | #define togglebit(PORT,BIT) ((PORT) ^= (1<<(BIT)));
|
42 | |
43 | |
44 | int main() |
45 | {
|
46 | BYTE temp = 1; |
47 | |
48 | // Enable interrupts
|
49 | //sei();
|
50 | |
51 | // Enable Watchdog timer
|
52 | // WDCTCSR = 0b11001111
|
53 | |
54 | DDRA = 0b10000000; |
55 | //DDRB = 0x00;
|
56 | //DDRC = 0x00;
|
57 | //DDRD = 0b11111110;
|
58 | |
59 | while (1<10) |
60 | temp = temp; |
61 | |
62 | return 1; |
63 | }
|
Die eigenen Datentypen sollte man sich gar nicht erst angewöhnen; wofür bitte sind denn die "neuen" definierten uint8_t etc. eingeführt worden? Desweiteteren wird die "Warteschleife" wegoptimiert; um das zu vermeiden, sollte "temp" als volatile deklariert werden. Und was macht "return 1" am Ende von main()? Wohin springt das Programm dort?
Vielen Dank für die Antworten. Ich hatte bisher immer nur in Assembler programmiert, deshalb hatte ich die initialisierung vor der main-Funktion angesetzt. Die Warteschleife habe ich nur programmiert um zu sehen ob der compiler die main-Funktion akzeptiert. War wohl einfach zu nah am Assemblercode... Zu den eigenen Datentypen: Diese Definitionen hatte ich aus einem Tutorial für AVR-GCC programmierung übernommen. Aber ihr habt wohl Recht damit, dass das ganze überflüssig ist. Ich hatte sie mir halt wegen der (für mich) besseren Lesbarkeit definiert. Hab die Initialisierung jetzt in eine eigene Funktion gepackt und jetzt läuft auch das ganze Programm. Vielen Dank für die Hilfe.
Rufus t. Firefly wrote: > Die eigenen Datentypen sollte man sich gar nicht erst angewöhnen; wofür > bitte sind denn die "neuen" definierten uint8_t etc. eingeführt worden? Wohl wahr. Aber wer kein C-Buch bzw. C-Tutorial liest, der weiß sowas eben nicht. > Desweiteteren wird die "Warteschleife" wegoptimiert; Nein, die wird nicht wegoptimiert. Wenn leere while(1)-Schleifen am Ende von main() wegoptimiert würden, gäbe es bei anderen Programmen auch Probleme. > Und was macht "return 1" am Ende von main()? Wohin springt das Programm > dort? Solange 1 kleiner als 10 ist, wird gar nicht gesprungen. Und zu einer Funktion vom Typ int gehört nunmal genau genommen ein Rückgabewert (auch wenn man ihn hier tatsächlich weglassen könnte). EDIT: Gerade mal getestet: Ohne while-Schleife am Ende von main steht da im Output ein einfaches ret, das natürlich nirgends hinführen kann. Mit
1 | while(1 < 10); |
steht da korrekterweise ein
1 | rjmp .-2 |
....Auch wenn er das können sollte, angewöhnen sollte man sich derartiges nicht..... Warum dat denn nicht, was? Wenn die Binärzahlen als Schreibweise jetzt mit drin sind. Programmierst wohl erst seit gestern , was? Solche Leute wie dich erschweren das Wirtschaftswunder. mfg
Johannes M. wrote: >> Die eigenen Datentypen sollte man sich gar nicht erst angewöhnen; wofür >> bitte sind denn die "neuen" definierten uint8_t etc. eingeführt worden? > Wohl wahr. Aber wer kein C-Buch bzw. C-Tutorial liest, der weiß sowas > eben nicht. Eigene Datentypen sind an sich keine schlechte Idee. Wenn man beispielsweise Module schreibt, die sowohl auf AVR als auch auf ARM funktionieren sollen, dann kann das sinnvoll sein. Für Daten, die in 8 Bits passen und als Parameter oder skalare Variablen verwendet werden, ist bei AVR ein 8 Bit Typ effizienter, bei ARM jedoch ein 32 Bit Typ. Nur sollten solche Typen dann als eigene Typen erkennbar sein und nicht mit Standarddatentypen aus stdint.h kollidieren.
> Und was macht "return 1" am Ende von main()? Wohin springt das Programm > dort? Kurz und knapp, eine nervende und unnötige Warnung eliminieren! >> Die eigenen Datentypen sollte man sich gar nicht erst angewöhnen; wofür >> bitte sind denn die "neuen" definierten uint8_t etc. eingeführt worden? > Wohl wahr. Aber wer kein C-Buch bzw. C-Tutorial liest, der weiß sowas > eben nicht. In den meisten C-Büchern steht nichts von uint8_t und Co. drin. Ein Blick in das µC-Tutorial sollte für die meisten Anfangsprobleme die passendste Lösung darstellen.
Nur so nebenbei: Johannes M. wrote: > Wenn leere while(1)-Schleifen am Ende > von main() wegoptimiert würden, gäbe es bei anderen Programmen auch > Probleme. Nein. (siehe unten) > Ohne while-Schleife am Ende von main steht da im Output ein einfaches > ret, das natürlich nirgends hinführen kann. Klar führt das irgendwo hin, nämlich zu dem Punkt im Startup-Code, wo main aufgerufen wurde. Dort wird nach main standardkonform zur Funktion _exit gesprungen. Und das Default-_exit aus der AVR-Libc enthält dann ein cli und eine Endlosschleife, hält den µC also sozusagen an.
@Stefan Ernst: Das ist mir soweit klar, aber mir ging es um die Feststellung, dass die while-Schleife keinesfalls, wie behauptet, wegoptimiert wird, sondern sehr wohl an der entsprechenden Stelle im Output auftaucht. > Und das Default-_exit aus der AVR-Libc enthält dann > ein cli und eine Endlosschleife, hält den µC also sozusagen an. Und das führt zu einem komplett anderen Verhalten als mit while-Schleife.
Johannes M. wrote: > Das ist mir soweit klar, ... Warum schreibst du dann "das natürlich nirgends hinführen kann.", das ist schlicht falsch. > Und das führt zu einem komplett anderen Verhalten als /mit/ > while-Schleife. Ach ja? Und was genau ist der Unterschied in diesem konkreten Fall (also mit auskommentiertem sei)?
Stefan Ernst wrote: > Ach ja? Und was genau ist der Unterschied in diesem konkreten Fall (also > mit auskommentiertem sei)? Mit auskommentiertem sei() natürlich keiner.
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.