Forum: Compiler & IDEs Port, Pin auf 1 oder null setzen


von Jörn (Gast)


Lesenswert?

Hallo,

Ich habe volgendes problem:

PORTB = 0xff;

funktioniert ohne probleme mit WinAVR, aber

PA0 = 1;

will einfach nicht, ich bekomme dannn folgenden fehler:

error: invalid lvalue in assignment

Woran kann das liegen???

PS: Ich hab die neuste version von winAVR

MFG Jörn

von Christian Schifferle (Gast)


Lesenswert?

Siehste, dass ist jetzt genau so ein Fehler, der durch die
furchterregende Programmiertechnik mit direkter Hardware-Adressierung
herrührt, obwohl Atmel diese Schreibweise neuerdings ja propagiert.
Aber nicht alles, was der Hersteller sagt, muss auch zwangsläufig gut
sein.
Aber so oder so
PORTB bezeichnet einen Port. Auf einen Port darf man mit direkter
Zuweisung zugreifen.
PA0 bezeichnet hingegen einen einzelnen Portpin. Auf diesen kannst du
nicht direkt zugreifen.
Um ein Bit auf dem Port zu setzen kannst du z.B. folgende Anweisung
verwenden:
PORTA |= (1 << PA0);
Dabei bleiben die restlichen Pins unberührt.
Um ein Bit zu löschen nimmst du entsprechend
PORTA &= ~(1 << PA0);

Gruss
Christian

von Joerg Wunsch (Gast)


Lesenswert?

Christian, Deine Polemik in allen Ehren, aber Du willst doch nicht
ernsthaft behaupten, daß

outp(1 << PA0, PORTA);

wesentlich einleuchtender und weniger error-prone war. ;-)
Erstens wäre da die unsinnige vertauschte Argumentreihenfolge,
zweitens kann man genauso schöne Verständnisfehler machen wie

outp(PA0, PORTA);

:-)

Nee, Du, an der direkten Zuweisung liegt's wirklich nicht.  Eher
daran, daß es ziemlich blödsinnig ist, für ein und dieselbe Zahl
0 so viele verschiedene #defines zu haben, daß kein Mensch mehr
weiß, welche davon wirklich gebraucht werden...  Was bitte soll
der Unterschied zwischen PA0, PINA0, DDRA0 usw. sein?  Das Ganze
dann nochmal mit PORTB, PORTC, PORTD, PORTE, PORTF, und ein
ATmega128 hat auch noch PORTG...  21 verschiedene Varianten, die
Ziffer 0 zu schreiben.

Wenn man den Unfug nicht benutzt (auch wenn der ebenfalls aus
den Atmel-Datenblättern stammt), wird der Fehler dann auch
sofort offensichtlich:

0 = 1;

kann nicht funktionieren. ;-)

PORTA |= _BV(0);

dagegen wohl schon eher.  (Wer _BV() nicht mag, kann es ja ruhig
ausschreiben, aber ich finde, daß es die Lesbarkeit etwas verbessert,
vor allem wenn man mehr als ein Bit setzen will.)

von Christoph (Gast)


Lesenswert?

Ich bin auch noch ein ziemlich Anfänger, aber ich mach das atm z.b. so:

sbi(PORTD,PD6);

Ob das stylistisch so gut ist weiß ich nicht, aber zumindest ich komme
damit gut zurecht ;)

von Joerg Wunsch (Gast)


Lesenswert?

Es ist abgekündigt. ;-)

Naja, noch nicht ganz, aber es läuft unter `deprecated'.  Vom
generierten Code her ist es identisch zu

PORTD |= 1 << PD6;

(wie Du Dir in den Macros selbst ansehen kannst).

von Jörn (Gast)


Lesenswert?

Hi

erstmal danke für die antworten!!

Ich versteh aber trotzdem nicht warum PA0 = 1; in vielen anderen C
Programmen funktioniert die ich mir als Beispiel angeschaut habe.

Liegt das am Compiler? AVR-GCC?

MFG Jörn

von Peter D. (peda)


Lesenswert?

Ich denke, das ist alles nur eine Gewöhnungssache.


Obwohl ich zugeben muß, daß mir die Keil-C51 Lösung besser gefällt:

sbit GRAY_A  = P1^1;

Da ist dann in einem Namen sowohl die Byteadresse als auch die
Bitnummer mit drin. Ich kann es also wie jede andere Variable
ansprechen, z.B.:

GRAY_A = 1;


Peter

von Joerg Wunsch (Gast)


Lesenswert?

@Jörn

wer schreibt denn PA0 = 1 irgendwo?  Habe ich noch nicht gesehen.

Die aktuelle avr-gcc Version folgt schlicht der Atmel-Konvention, und
die wiederum dürfte in Zusammenarbeit mit IAR entstanden sein.

Was ich (für andere Controller) schon gesehen habe, ist sowas wie

PORTX.0 = 1;

Dabei ist mir aber die C-syntaktische Auflösung des Knotens unklar.
Nach einem Punkt müßte ein struct tag folgen, aber eine Zahl oder
Ziffer ist kein gültiger struct tag.

@Peter

Hmm, wäre sicher machbar, Du kannst dann eben nur nicht mehrere
Bits eines Registers in einer Anweisung setzen, oder übersehe ich
da was?  Anyway, Atmel hat sich das halt nicht so ausgedacht.

von Christoph (Gast)


Lesenswert?

Wusste gar nicht das sbi() deprecated ist, zumindest stehts so nicht in
meiner libc Beschreibung, die bei WinAVR dabei war ;)

von Joerg Wunsch (Gast)


Lesenswert?

Ja, es ist noch keiner dazu gekommen, das endlich mal aufzuschreiben.
;-)

von Jörn (Gast)


Angehängte Dateien:

Lesenswert?

@Joerg Wunsch

In dem angehängten programm zum Beispiel:

#define RESET PORTD.5

RESET = 1;

RESET = 0;


So wie da würd ich das auch gerne Programmieren und statt der Zahl
eventuell eine Variable einsetzen die 1 oder 0 enthält. Funktioniert
aber leider nur mit einem kompletten port.

MFG Jörn

von Joerg Wunsch (Gast)


Lesenswert?

Ist aber nicht das, was Du weiter oben geschrieben hast, sondern
vielmehr das, was ich selbst auch als ,,unklare C-Syntax''
beschrieben habe.  Ich weiß wirklich nicht, wie man das innerhalb
der C-Syntax unterbekommt.  Nichtsdestotrotz machen es einige
Compilerhersteller so.  War mir bisher nur in der MCS51-Welt
untergekommen, bei AVR noch nicht.  Für welchen Compiler ist das
denn?

von Jörn (Gast)


Lesenswert?

@Joerg Wunsch

Leider weis ich selbst nicht für welchen compiler das prog ist, ich hab
das zufällig in der codesammlung gefunden.

MFG Jörn

von Schmittchen (Gast)


Lesenswert?

@Jörg:
Habe mal ein paar Codeabrisse gesammelt, die das von Jörn gewünschte
Verhalten beschreiben.
Die von dir angesprochen "unklare C-Syntax" läßt sich prima (und
sauber) über #defines herstellen.


Greenhills C-Compiler für NEC:
---------------------------------------
struct bitf {
        unsigned char bit00:1;
        unsigned char bit01:1;
[usw.]
};

#define P0      *((volatile unsigned char *)0xfffff000)
#define P0_0    ((volatile struct bitf *)0xfffff000)->bit00

dann:
P0_0=1;
---------------------------------------

Codewarrior für Motorola:
---------------------------------------
extern volatile PORTBSTR _PORTB @(REG_BASE + 0x00000001);
#define PORTB _PORTB.Byte
#define PORTB_BIT0 _PORTB.Bits.BIT0
Zugriff über:
PORTB_BIT0=1;
---------------------------------------

Softune für Fujitsu:
---------------------------------------
typedef union{   /*  PORT DATA Registers */
    IO_BYTE     byte;
    struct{
    IO_BYTE P00 :1;
    IO_BYTE P01 :1;
[usw.]
  }bit;
 }PDR0STR;
__IO_EXTERN __io PDR0STR _pdr0;   /*  PORT DATA Registers */
#define PDR0 _pdr0.byte
#define PDR0_P00 _pdr0.bit.P00

Zugriff über:
PDR0_P00=1;
---------------------------------------


Vorteil (wie von Jörn schon geäußert):
Direkter Zugriff auch auf Portbits mittels Zuweisung.
Keine "Kunstgriffe" wie _BV() oder Bitschiebereien.

Widerspricht hierbei was der C-Syntax?

Warum kann das AVR-GCC nicht? Liegt es daran, daß auf die IO-Register
nicht wie auf RAM zugegriffen werden kann und folglich auch kein
Bitfeld darübergestülpt werden kann?

Schmittchen.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Das würde mit dem GCC funktionieren, wird auch im MSP430-Port so ähnlich
gemacht. Dagegen spricht, dass ein Compiler die Bits theoretisch in
belibiger Reihenfolge im Speicher anordnen darf.

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.