mikrocontroller.net

Forum: Compiler & IDEs MSPGCC Bit setzen mit einem Befehl


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
static bit KEY  @ ((unsigned)&PORTA*8+4);

oder der Keil-Compiler
#define DATA P1_1
#define SCK P1_0

SCK = 1;
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.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> (...) 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.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Der msp430 hat so etwas nicht, und daher wäre ein Bit-Datentyp in C kaum
>sinnvoll zu implementieren.

Das erklärt dann einiges. Schade eigentlich.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Marcus Overhagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Marcus,

eine sehr edle Lösung.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:

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

Theoretisch geht das hier:
const struct xy1con xy1con_initializer = {
  .EN = 1, .MODE = 1, .HAPPY = 0, .WIDE = 1
};
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

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dir kann's egal sein. Aber wenn ich mir für den MCP2515 oder ENC28J60 
ein Headerfile bastele, dann möglichst nicht noch für jeden Compiler 
anders.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In Ada könnte man zum Beispiel schreiben:
xy1con := (en => 1, mode => 1, wide => 1, foobar => 5, others => 0);
...
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>

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Wolfgang-G (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was spricht gegen:
   P2OUT &= ~BIT1;   // aus
   P2OUT |=  BIT1;   // an

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich mir das Disassembly anschaue, steht da schon die Konstante 
drin. Muss natürlich zur Kompilierzeit feststehen.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.