MSPGCC Bit setzen mit einem Befehl

Persönliche Seite #669097
Lesenswert?

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.
Moderator Persönliche Seite #669132
Lesenswert?

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.
Gast #669161
Lesenswert?

>>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);
Gast #669181
Lesenswert?

>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
static bit KEY  @ ((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.
Gast #669331
Lesenswert?

> 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.
Gast #669367
Lesenswert?

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
#669379
Lesenswert?

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.
Moderator Persönliche Seite #669468
Lesenswert?

Andreas Kaiser wrote:

> Denn weil der Kram mit
> gutem Grund volatile ist, darf der Compiler das nicht zusammenfassen.

Theoretisch geht das hier:
1
const struct xy1con xy1con_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
#669483
Lesenswert?

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?
Admin Persönliche Seite #669793
Lesenswert?

In Ada könnte man zum Beispiel schreiben:
1
xy1con := (en => 1, mode => 1, wide => 1, foobar => 5, others => 0);
2
...
3
xy1con.en := 0;
...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>
Gast #670264
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren