www.mikrocontroller.net

Forum: Compiler & IDEs error: expected identifier or '(' before 'volatile' bei AVR Programmierung


Autor: Christoph Neeb (webreaper)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> #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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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().

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-(

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und das hier

>
> //#include "subroutines.c"
> //#include "interrupt_table.c"
> 

ist zwar noch nicht scharfgeschaltet, wird aber zur nächsten Todsünde 
führen, wenn es denn mal aktiv wird.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.
[c]
#ifndef F_CPU
#define F_CPU 20000000;
#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)));


int main()
{
  BYTE temp = 1;

  // Enable interrupts
  //sei();

  // Enable Watchdog timer
  // WDCTCSR = 0b11001111

  DDRA = 0b10000000;
  //DDRB = 0x00;
  //DDRC = 0x00;
  //DDRD = 0b11111110;

  while (1<10)
    temp = temp;

  return 1;
}

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?

Autor: Christoph Neeb (webreaper)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
while(1 < 10);
steht da korrekterweise ein
rjmp .-2

Autor: bastler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
....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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: du (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.