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
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
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.)
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 ;)
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).
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
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
@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.
@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
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?
@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.
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.