Hallo zusammen, habe mal eine frage zu dem "#define" Befehl. Die Idee ist jedem PIN am Mikrokontroller einen Namen zuzuweisen. bsp: #include <avr/io.h> #define LED PC0 //PortC Pin0 int main (void) { LED=1; // <= die Wertezuweisung mag der Compiler nicht } Wie kann ich dieses realisieren??? Gruß Dominik
Dominik, im Define fand bereits eine Zuweisung statt (sie bedeutet, dass "LED" eine bestimmte Pin-Adresse verwendet), die kann man nicht einfach überschreiben. Willst Du diese LED einschalten bzw. den Port High legen, geht das z. B. über die Zeile output_bit(LED,1) oder output_high(LED) Dieter
#define ist eine Präprozessor-Anweisung und kein Befehl. #define sagt dem Präprozessor, dass er eine Textersetzung vornehmen soll. In diesem Fall wird er an jeder Stelle, an der im Quellcode "LED" auftaucht, stattdessen "PC0" einsetzen. "PC0" ist aber an anderer Stelle (im Device-spezifischen Header-File) ebenfalls per #define definiert, und zwar steht da
1 | #define PC0 0
|
0 ist aber schlicht und ergreifend eine Zahl, und der kannst Du mit "=" keinen anderen Wert zuweisen! Nach der Bearbeitung durch den Präprozessor steht in main nämlich
1 | 0 = 1; |
Und dass das nicht sein kann, sollte klar sein... Die von Dir beabsichtigte Schreibweise funktioniert ohne weiteres gar nicht. Dazu müsstest Du dem Compiler Bitzugriffe beibringen (manche kommerziellen Compiler machen das auch als nicht standardkonforme Erweiterung, aber AVR-GCC ist ein ANSI-C-Compiler und tut selbiges nicht).
Dominik Boine wrote: > #include <avr/io.h> > #define LED PC0 //PortC Pin0 > int main (void) > { > LED=1; // <= die Wertezuweisung mag der Compiler nicht > } "PC0" ist auch nur mit #define vereinbart worden, und zwar i.d.R. so: #define PC0 0 Jetzt steht da also "0 = 1" in der Main-Routine...! Deine Idee ist mit #define nicht direkt zu lösen; alles was du mit #define festlegst, wird einfach nur ersetzt, bevor der Compiler deinen Quelltext zu sehen bekommt.
Machs so: #include <avr/io.h> struct bits { char b0:1; char b1:1; char b2:1; char b3:1; char b4:1; char b5:1; char b6:1; char b7:1; } __attribute__((_packed_)); #define LED ((*(volatile struct bits*)&PORTC).b0) Dann kannst du schreiben: int main (void) { LED=1; }
Hallo zusammen! @Benedikt: Ist __attribute__((packed)) ein von dir erfundener Name oder gibt es da noch eine Besonderheit? Dann zu der define-Zeile: Habe ich das so richtig verstanden? (volatile struct bits*)&PORTC --> Cast der Adresse von PORTC in einen Pointer vom Typ [volatile struct bits]. ((*(volatile struct bits*)&PORTC).b0) ^ | Dieser Stern ist dann der Inhaltsoperator -Richtig? Bitte um Korrektur wenn ich was falsch verstanden habe. Ansonsten wieder was gelernt - Danke!
Etwas flexibler: Struktur wie bei Benedikt K., Makro wie hier: Beitrag "Re: sbit macro für avr-gcc" (Ersetze "test" durch "bits")
mandrake wrote: > Hallo zusammen! > > @Benedikt: > Ist __attribute__((packed)) ein von dir erfundener Name oder gibt es > da noch eine Besonderheit? Das sagt dem Compiler, dass er die Bits so eng wie möglich packen soll, und das ganze nicht z.B. aus Geschwindigkeitsgründen optimieren soll. > Dann zu der define-Zeile: > Habe ich das so richtig verstanden? > > (volatile struct bits*)&PORTC --> Cast der Adresse von PORTC in einen > Pointer vom Typ [volatile struct bits]. So in etwa. volatile verbietet dem Compiler hier wieder einige Optimierungsmöglichkeiten, so dass er diesen Befehl nicht wegoptimiert. Wenn man z.B. schreibt LED=1; LED=0; denkt der Compiler: Am Ende kommt 0 raus, also ist die Zeile LED=1 überflüssig und lässt diese weg. Mit dem volatile verbietet man dies dem Compiler. > ((*(volatile struct bits*)&PORTC).b0) > ^ > | > Dieser Stern ist dann der Inhaltsoperator -Richtig? Ja. > Ansonsten wieder was gelernt - Danke! Das ganze stammt übrigends nicht von mir, sondern taucht immer wieder hier im Forum auf. Keine Ahnung von wem das Orginal stammt. Das ganze ist nicht unbedingt eine Vorbildliche Lösung, da der Code schwerer portierbar wird, es macht den Code meiner Meinung nach aber besser lesbar.
Das packed-Attribute braucht man (zumindest bei neueren GCCs) nicht. GCC 4.2.3 und 4.3.0 geben sogar eine Warnung aus: '_packed_' attribute directive ignored Bei einem Bitfeld sind die einzelnen Elemente sowieso immer gepackt solange sie alle in einem einzelnen char/int-Wert Platz haben. Zu beachten wäre noch, dass beim Zugriff auf I/O-Bits mit der obigen Methode für
1 | LED = 0; // Output |
2 | LED = 1; |
3 | |
4 | if(BUTTON) { ... } // Input |
5 | if(!BUTTON) { ... } |
bestmöglicher Code erzeugt wird, nicht jedoch für
1 | LED = value; // value in {0, 1} |
2 | |
3 | value = BUTTON; |
was teilweise zu aufwendigen Schiebeoperationen führt. Hier ist es meist besser,
1 | if(value) |
2 | LED = 1; |
3 | else
|
4 | LED = 0; |
5 | |
6 | if(BUTTON) |
7 | value = 1; |
8 | else
|
9 | value = 0; |
zu schreiben. Auch wenn es in C komplizierter aussieht, wird es im kompilierten Code kürzer und schneller.
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.