Hallo,
ist es möglich, mit dem mspgcc ein einzelnes Bit zu setzen?
Z.B. möchte ich definieren, dass OUT auf Port 2.1 liegt, sodass ich den
Portpin mit OUT=1 setzen und OUT=0 löschen kann. M.E. nach geht das im
avrgcc.
Der AVR kennt eine Bit-Adressierung, die kennt der MSP430 nicht.
Deine Operation lässt sich dennoch in einer Anweisung verpacken:
P2OUT &= ~0x02; // aus
P2OUT |= 0x02; // an
Statt der für manche nicht selbsterklärenden Schreibweise 0x02 kann man
auch die gerade bei AVR-Programmierern sehr beliebte
Bitshift-Schreibweise verwenden:
P2OUT &= ~(1 << 2); // aus
P2OUT |= 1 << 2; // an
Allerdings sollte man sich nicht dazu verleiten lassen, diese Notation
mit den Bitkonstanten aus den mit msp430-C-Compilern gelieferten
Headerdateien zu verwenden: im Gegensatz zur AVR-Konvention, bei der
eine Bitkonstante die Nummer des Bits enthält, enthält sie bei der
msp430-Konvention den Wert des Bits.
Naja, wirklich ,,beliebt'' sind diese 1<<-Konstrukte auch bei den
AVR-Programmierern eher nicht... Sie sind eben nur in häufiger
Benutzung dort, weil Atmel die Bits als Bitnummern statt -masken
vorgegeben hat, was im Wesentlichen ein Tribut an die Mitnutzung
der Headerdateien durch Assemblerprogrammierer (innerhalb von
SBI/CBI/SBIC/SBIS-Befehlen) sein dürfte.
>P2OUT &= ~0x02; // aus>P2OUT |= 0x02; // an
Diese "Krücken" benutze ich gerade. Sind zwar nicht übersichtlich, aber
wenigstens verwendet der Compiler dafür die Bit-Set- und -Clear-Befehle.
>>P2OUT &= ~0x02; // aus>>P2OUT |= 0x02; // an>> Diese "Krücken" benutze ich gerade. Sind zwar nicht übersichtlich, aber> wenigstens verwendet der Compiler dafür die Bit-Set-und -Clear-Befehle.
Wieso "Krücken"? Das ist die normale Schreibweise, um das in C zu
machen. Wenn dir das lieber ist, kannst du ja auch sowas machen:
#define SET(port, val) (port |= val)
#define CLR(port, val) (port &= ~val)
CLR(P2OUT, 0x02);
SET(P2OUT, 0x02);
>Wieso "Krücken"? Das ist die normale Schreibweise, um das in C zu>machen.
Das mag für ANSI-C zu sein, für C für µC ist es mehr als unpraktisch.
Beispielsweise sei hier der HITECH-Compiler für PIC genannt, der sogar
den Datentyp Bit kennt.
z.B.
1
staticbitKEY@((unsigned)&PORTA*8+4);
oder der Keil-Compiler
1
#define DATA P1_1
2
#define SCK P1_0
3
4
SCK=1;
5
Data=0;
oder eben auch der besagte avrgcc.
Bei vielen µC-Compilern ist eben auch der C-Dialekt recht assemblernah.
Wünschenswert wäre eine Schreibweise, die genau das sichbar macht, was
es machen soll, nämlich den Portpin setzen oder löschen. Vielleicht ist
das ja durch ein makro machbar.
> (...) der sogar den Datentyp Bit kennt.
Das mag bei µCs sinnvoll sein, die Bitadressierung unterstützen, wie
MCS-51, AVRs oder PICs.
Der msp430 hat so etwas nicht, und daher wäre ein Bit-Datentyp in C kaum
sinnvoll zu implementieren.
> static bit KEY @ ((unsigned)&PORTA*8+4);
Äußerst skurrile Syntax.
> oder eben auch der besagte avrgcc.
Der kennt keine Bittypen.
> Bei vielen µC-Compilern ist eben auch der C-Dialekt recht assemblernah.
Ich bin eigentlich eher dagegen, irgendwelche speziellen Dialekte zu
verwenden, sondern mag es lieber standardmäßig. Dann muß man nicht für
jeden Compiler wieder eine andere Syntax lernen, und falls das Programm
mit mehr als einem Compiler übersetzbar sein muß, muß man nicht
massenweise Fallunterscheidungen mit #define einbauen.
> Wünschenswert wäre eine Schreibweise, die genau das sichbar macht, was> es machen soll, nämlich den Portpin setzen oder löschen. Vielleicht ist> das ja durch ein makro machbar.
In C++ kann man sich eine Klasse dafür schreiben. Das geht z.B. mit
avr-g++ ganz prima.
Der Bitweise AND bzs. OR Befehl braucht doch auch nur einen Takt, wo
liegt also das Problem? Um ein bestimmtes Bit zu setzen oder
rückzusetzen tun´s doch ganz prima Präprozessor-Makros.
Hallo,
mit C kannst du auch Bitfelder definieren, und kannst den
einzelnen Bits auch eigene Namen geben, hier z.B. "onoff".
Dann definierst du einen Pointer auf die Adresse die das
Byte enthält das du ändern willst, und kannst dann auf
das Byte zugreifen.
Wenn du anstatt eines Pointer ein Makro verwendest
spart du den Speicherplatz für den Pointer ein.
Dann kannst du Sachen schreiben wie PA.onoff = 1;
typedef struct {
unsigned char bit0 : 1;
unsigned char bit1 : 1;
unsigned char bit2 : 1;
unsigned char onoff : 1;
unsigned char bit4 : 1;
unsigned char bit5 : 1;
unsigned char bit6 : 1;
unsigned char bit7 : 1;
} _attribute_ ((packed)) porta_t;
#define PA (*(volatile porta_t *)&PORTA)
PA.bit6 = 1;
PA.onoff = 0;
PA.onoff = 1;
oder nicht dereferenziert:
#define PB ((volatile porta_t *)&PORTB)
PB->onoff = 1;
(die Reihenfolge der Bits im Bitfeld ist compilerabhängig,
also ggf. ausprobieren)
Gruss
Marcus
Blöd an Bitfeldern ist nur, dass man die Arbeit doppelt hat, wenn man im
Header sowohl die Bitfelder als auch die Bitmasken/Nummern deklariert.
Denn wenn man nur die Bitfelder deklariert (wie z.B. Microchip das
macht), dann findet man im Code doch wieder öfter die klassische
Kurzform
XY1CON = 0xD425;
für
XY1CONbits.EN = 1;
XY1CONbits.MODE = 1;
XY1CONbits.HAPPY = 0;
XY1CONbits.WIDE = 1;
...
weil der Programmierer es unlustig fand, beliebig viele Bits einzeln zu
setzen und dafür zig Bytes Code zu verschwenden. Denn weil der Kram mit
gutem Grund volatile ist, darf der Compiler das nicht zusammenfassen.
Andreas Kaiser wrote:
> Denn weil der Kram mit> gutem Grund volatile ist, darf der Compiler das nicht zusammenfassen.
Theoretisch geht das hier:
1
conststructxy1conxy1con_initializer={
2
.EN=1,.MODE=1,.HAPPY=0,.WIDE=1
3
};
4
XY1CONbits=xy1con_initializer;
Habe ich mal mit einer angedachten Lösung für Bitfelder in der avr-libc
probiert. GCC 4.x hat hier nur einen Bug (*) wodurch er das beim
Auftreten von mehr als einem Bitfeld nicht mehr durch eine konstante
Zahl ersetzt. Das funktionierte aber unter GCC 3.x noch, und man
sollte annehmen, dass das wieder repariert wird.
(*) http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32901
Habe ich mir auch schon überlegt. Ist zwar mittlerweile standardkonform
möglich nachdem das lange Zeit auf GCC beschränkt war, aber wieviele
Microcontroller-Compiler kriegen sonst noch gebacken? C99 scheint mir da
nicht allzu weit verbreitet zu sein. Und wenn - wie sieht dann der Code
aus?
Naja, da die avr-libc inherent zum AVR-GCC gehört, mache ich mir da
keine zu großen Gedanken. ;-)
Aber das alte byteorientierte Interface wird's natürlich auch noch
geben.
...und aus der Typdefinition von xy1con weiß der Compiler, wie die
einzelnen Elemente zu einem Byte (oder auch zu einem ganzen
Speicherblock!) zusammenzufügen sind.
Eigentlich schade dass sich C überall durchgesetzt hat. Wenn man es
genau betrachtet ist C völlig ungeeignet für µC-Programmierung: es gibt
keine binären Literale, das Typen-/Speichermodell ist zu inflexibel,
Bitfelder sind kaum nutzbar weil die Abbildung auf den Speicher nicht
definiert ist, usw... und für High Level Programmierung ist es genauso
ungeeignet, weil das Speicherhandling jedes Programm zum Minenfeld
macht. </rant>
> Eigentlich schade dass sich C überall durchgesetzt hat. Wenn man es> genau betrachtet ist C völlig ungeeignet für µC-Programmierung:
Ack. Mir wäre Ada auch lieber. Aber da ist nix mehr zu machen.
>Was spricht gegen:> P2OUT &= ~BIT1; // aus> P2OUT |= BIT1; // an
Die Schreibweise. BIT1 = 0; oder BIT1 = 1; ist sofort ersichtlich. Es
soll genau das gemacht werden, was es darstellt und nicht das, was der
Compiler anschließend daraus macht. In dem bekannten Fall würde erst das
Bit invertiert und dann anschließend mit dem Port UND-Verknüpft werden.
Diese Art ist von hinten durch die Brust.
Das Invertieren des Bits macht schon der Präprozessor. Es ist am Ende
auch nur ein Befehl der ausgeführt wird. Und die Gründe dafür sind ja
nun schon mehrfach erläutert: Keine Bitweise Adressierung am MSP.
> Das Invertieren des Bits macht schon der Präprozessor.
Verbreiteter Irrtum. gcc -E zeigt dir was der Präprozessor draus macht.
Rechnen tut er jedenfalls nicht, das macht der Compiler selbst.
Christian Richter wrote:
> Wenn ich mir das Disassembly anschaue, steht da schon die Konstante> drin.
Trotzdem macht es nicht der Preprozessor...
> Muss natürlich zur Kompilierzeit feststehen.
Eben. Der Compiler rechnet den konstanten Ausdruck aus.