Forum: Mikrocontroller und Digitale Elektronik #define aber wie?


von Dominik B. (dominik123)


Lesenswert?

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

von Unbekannter (Gast)


Lesenswert?

> Wie kann ich dieses realisieren???

So? Gar nicht!

von Dieter S. (bulova)


Lesenswert?

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

von Johannes M. (johnny-m)


Lesenswert?

#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).

von Sven P. (Gast)


Lesenswert?

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.

von Benedikt K. (benedikt)


Lesenswert?

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;
}

von mandrake (Gast)


Lesenswert?

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!

von yalu (Gast)


Lesenswert?

Etwas flexibler: Struktur wie bei Benedikt K., Makro wie hier:

Beitrag "Re: sbit macro für avr-gcc"

(Ersetze "test" durch "bits")

von Benedikt K. (benedikt)


Lesenswert?

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.

von yalu (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.