www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Einzelne Bits mit WinAvr


Autor: Tarkan D. (gruetzwurschd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

sowohl die Foren- als auch die Googlesuche haben keinen gewünschten 
Erfolg gebracht, daher nun folgende Frage.

Bei den C-Compilern von Microchip gibt es für jeden Prozessor ein 
Headerfile. In diesem .h file sind unter anderem alle 
Special-Funktion-Register als unions hinterlegt (Bitweise oder byteweise 
Lesen und schreiben).

Bei den WinAvr Bibliotheken habe ich so etwas nicht finden können.

Einzelne Bits kann man ja folgendermaßen setzen:

Registername ^= (1<<Registerbit);
Registername &=~(1<<Registerbit);

allerdings bin ich nicht in der lage folgende Konstruktionen mit WinAvr 
hin zu bekommen:

LATAbits.LATA1 = PORTBbits.PORTB1; // dafür finde ich keinen 
gleichwertigen ersatz

Kann mir vielleicht jemand verraten ob ich nur unfähig bin die WinAvr 
Hilfe richtig zu lesen, oder müsste ich mir eine Solche zuweisung selber 
zusammen basteln??

Grüße Tarkan

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tarkan D. schrieb:
> LATAbits.LATA1 = PORTBbits.PORTB1;
Ja. Der PIC-Compiler macht daraus automatisch:
if (PORTBbits&(1<<PORTB1)) LATAbits |=  (1<<LATA1);
else                       LATAbits &= ~(1<<LATA1);
Das mußt du jetzt eben händisch machen (und siehst so, dass 
Bitmanipulation u.U. recht aufwendig sein kann)...

Autor: Geist (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Such mal nach "struct" gehört und "bitfield".

Autor: Frederik Krämer (n0ll4k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ich mich grad frage, was willst du damit eigentlich machen ein Bit 
durch ein anderes setzen?

Aber die Schreibweise von dir ist mir unbekannt. Denke da musst du dir 
selbst was basteln wenn du es so schreiben willst.

edit

war wohl zu langsam

Autor: Tarkan D. (gruetzwurschd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frederik Krämer schrieb:
> Was ich mich grad frage, was willst du damit eigentlich machen ein Bit
> durch ein anderes setzen?
>
> Aber die Schreibweise von dir ist mir unbekannt. Denke da musst du dir
> selbst was basteln wenn du es so schreiben willst.


Die Schreibweise ist standardmäßig bei Microchip Compilern machbar. Ich 
komme aus der Ecke und darf/muss mich jetzt mit Atmels beschäftigen.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geist schrieb:
> Such mal nach "struct" gehört und "bitfield".
Auf Port-Ebene? Viel Spass...

BTW:
Lasst doch mal die ganze Bitpfriemelei auf einem uC aussen vor. Das ist 
für den unglaublich umständlich zu berechnen. In meinen Programmen 
bekommt (solange genug Speicher da ist) jeder Zustand ein eigenes Byte:
  uint8_t schalter, taster, licht;

  schalter = PORTB&(1<<PORTB1);
  taster   = PORTC&(1<<PORTC2);

  if (schalter) licht = 1;
  if (taster)   licht = 0;
   :
Jetzt könnte ein Hacker drauf kommen und alles zusammen in ein Bitfeld 
hacken, das dann natürlich statt 3 Bytes nur noch 1 Byte braucht. Aber 
sieh sich mal einer hinterher das Listing an...

Autor: z.b. so (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uwie schon erwähnt lauten die zauberworte union, bitfield und zusätzlich 
struct und packed struct - wenn du die begriffe an gurgel verfütterst, 
solltest du eigentlich recht leicht auf die lösung kommen...

Autor: Tarkan D. (gruetzwurschd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
z.b. so schrieb:
> uwie schon erwähnt lauten die zauberworte union, bitfield und zusätzlich
> struct und packed struct - wenn du die begriffe an gurgel verfütterst,
> solltest du eigentlich recht leicht auf die lösung kommen...


ich weiß, dass es sowas gibt. Wenn man meine Frage richtig gelesen 
hätte, dann wüsste man, dass ich gefragt habe ob der WinAvr C-Compiler 
sowas in seinen Headerfiles bereit stellt. Dass man soetwas selber 
erstellen kann und wie das geht weiß ich selber

Nur für jedes einzelne SFR mir meine eigene Union zu schreiben fände ich 
etwas aufwändig.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tarkan D. schrieb:
> müsste ich mir eine Solche zuweisung selber
> zusammen basteln??

Ja, es geht unter WINAVR, aber Du mußt es selber machen.

Ich sehe darin allerdings keinen richtigen Sinn, Du ersetzt eine 
Schreibweise durch eine andere, genauso wenig aussagende.

Mich interessiert bei meinen Programmen aber nicht der konkrete Pin, 
sondern die Funktion, die er hat.
Ich mache mir daher Definitionen mit aussagekräftigen Namen, z.B.:
#define LED_ROT  SBIT( PORTB, PB1 )
#define TASTE_OK SBIT( PINC,  PC5 )

void test(void)
{
  LED_ROT = TASTE_OK;
}

Hier noch ein Beispiel mit der Definiton des SBIT-Macro:

http://www.mikrocontroller.net/attachment/30300/lcd_drv.zip



Peter

Autor: Tarkan D. (gruetzwurschd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir kurz jemand erklären was man mit SBIT() macht?Odre wo kann ich 
das nachlesen? Weder AVRStudio hilfe noch WINAVR hilfe noch google geben 
mir eine antwort

möglicherweise ist das der "heilige Gral" nach dem ich gesucht habe!!

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Jetzt könnte ein Hacker drauf kommen und alles zusammen in ein Bitfeld
> hacken, das dann natürlich statt 3 Bytes nur noch 1 Byte braucht. Aber
> sieh sich mal einer hinterher das Listing an...

Wozu erst extra Variablen, nimm doch gleich die Pins.
Dann sieht das Listing auch vernünftig aus:
int main( void )
{
  for(;;){
    if( TASTE_ON == 0 )
  6c:   b0 9b           sbis    0x16, 0 ; 22
      LED = 0;
  6e:   a8 98           cbi     0x15, 0 ; 21
    if( TASTE_OFF == 0 )
  70:   b1 99           sbic    0x16, 1 ; 22
  72:   fc cf           rjmp    .-8             ; 0x6c <main>
      LED = 1;
  74:   a8 9a           sbi     0x15, 0 ; 21
  76:   fa cf           rjmp    .-12            ; 0x6c <main>


Und hier der Quelltext dazu:
#include <avr/io.h>


struct bits {
  uint8_t b0:1;
  uint8_t b1:1;
  uint8_t b2:1;
  uint8_t b3:1;
  uint8_t b4:1;
  uint8_t b5:1;
  uint8_t b6:1;
  uint8_t b7:1;
} __attribute__((__packed__));
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
#define SBIT(x,y)       SBIT_(x,y)


#define LED             SBIT( PORTC, PC0 )
#define TASTE_ON        SBIT( PINB,  PB0 )
#define TASTE_OFF       SBIT( PINB,  PB1 )


int main( void )
{
  for(;;){
    if( TASTE_ON == 0 )
      LED = 0;
    if( TASTE_OFF == 0 )
      LED = 1;
  }
}


Peter

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Wozu erst extra Variablen, nimm doch gleich die Pins.
Ich habe mir angewöhnt, für Prozessabläufe bewusst nicht die Pins 
(zumindest nicht die Eingangspins) zu verwenden, sondern wie bei SPSen 
üblich erst mal ein Eingangssbbild einzulesen, mit dem dann ein 
Ausgangsabbild zu berechnen und das dann auf die Ports abzubilden.

Und warum? Damit gibt es keine solchen Grenzfälle mehr, wo ein 
Taster/Schalter/Sensor im Programm mehrfach abgefragt wird, aber erst in 
der 2. Programmhälfte aktiv wird...

Aber für die Low-Level IO-Manipulation muß ich mir das mit den 
Bitfeldern offenbar noch mal genauer ansehen. Die Compiler scheinen 
besser geworden zu sein... ;-)

Autor: Tarkan D. (gruetzwurschd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum bekomme ich bei folgendem Code
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
#define SBIT(x,y)       SBIT_(x,y)

und
SBIT( PORTC , PC3) = 1;

folgende Fehlermeldung:

dereferencing pointer to incomplete type

ich bin irgendwie am verzweifeln!

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tarkan D. schrieb:
> Warum bekomme ich bei folgendem Code

Weil Du den wichtigen Teil weggelassen hast.

Um auf "struct bits" zu zeigen, muß der Compiler ja wissen, was das 
überhaupt ist.

Ich dachte, Du hast schonmal Bitfelder benutzt?


Peter

Autor: Tarkan D. (gruetzwurschd)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit Bitfeldern hatte ich im Prinzip nur folgende Spielereien 
veranstaltet:



union gruetze
{
   struct
   {
       unsigned char bit0 : 1;
       unsigned char bit1 : 1;
       unsigned char bit2 : 1;
       unsigned char bit3 : 1;
       unsigned char bit4 : 1;
       unsigned char bit5 : 1;
       unsigned char bit6 : 1;
       unsigned char bit7 : 1;
   };unsigned char gruetz_byte;       
};




und dann bitweise schreiebn und auslesen

naja wie auch immer

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tarkan D. schrieb:
> Mit Bitfeldern hatte ich im Prinzip nur folgende Spielereien
> veranstaltet:
>
>
>
> 
> 
> union gruetze
> {
>    struct
>    {
>        unsigned char bit0 : 1;
>        unsigned char bit1 : 1;
>        unsigned char bit2 : 1;
>        unsigned char bit3 : 1;
>        unsigned char bit4 : 1;
>        unsigned char bit5 : 1;
>        unsigned char bit6 : 1;
>        unsigned char bit7 : 1;
>    };unsigned char gruetz_byte;
> };
> 
> 
> 
> 
>
> und dann bitweise schreiebn und auslesen

Ja.
Und weiter?

Jetzt musst du nur noch den nächsten Schritt machen.
Du hast ein Register. Das wird dir vom Compiler wie eine Variable 
präsentiert. Nimmst du also die Adresse dieser Variablen her, dann 
kannst du dem Compiler durch Umcasten dieser Adresse in einen anderen 
Datentyp weismachen, dass an genau dieser Stelle im Speicher nicht 
einfach nur ein Byte sitzt, sondern dass sich dort an dieser Adresse im 
Speicher genau so ein Bitfeld befindet.

Und voila. Schon kannst du über ein Bitfeld auf die Einzelbits 
zugreifen.


Einfach nur 2 und 2 zusammenzählen und 2 Techniken miteinander 
kombinieren.

Autor: Peter S. (psavr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@peda
Und wieso verschachtelst Du das in zwei #defines?
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
#define SBIT(x,y)       SBIT_(x,y)

anstatt direkt:
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:
> @peda
> Und wieso verschachtelst Du das in zwei #defines?

Das (die genaue Funktionsweise von ##) ist eines der großen Mysterien 
des C-Präprozessor. Nimm einfach hin, dass wenn es richtig funktionieren 
soll, man das immer 2-stufig machen muss. Ansonsten werden Argumente an 
dieses Makro, welche seinerseits Makros sind, nicht richtig ausgewertet.

Autor: Peter S. (psavr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okey, dann nehme ich das einfach mals als "Mysterium" hin! ;o)

Ich hatte mich mich nämlich gefragt, ob ich da was offensichtliches bzw. 
triviales übersehe...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Quatsch, das ist kein Mystrerium.

Der Präprozessor expandiert einfach immer nur eine Macroebene pro 
Durchlauf:
LED = 0;
nach 1. Runde:
SBIT( PORTC, PC0 ) = 0;
nach 2. Runde:
SBIT_( _SFR_IO8(0x15), 0 ) = 0;
nach 3. Runde:
(*(volatile struct bits*)&((0x15) + __SFR_OFFSET)).b##0 = 0;
nach 4. Runde:
(*(volatile struct bits*)&((0x15) + 0x20)).b0 = 0;

Und schon wird das bit 0x35.b0 angesprochen.


Und damit wird auch klar, warum das 2. Macro.
Wenn man nämlich "b##PC0" zusammenkleben würde, kommt nicht "b0" raus, 
sondern "bPC0" und das ist kein Element von "struct bits".
Das Macro "PC0" muß erst noch zu "0" expandiert werden.


Peter

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

> Und damit wird auch klar, warum das 2. Macro.
> Wenn man nämlich "b##PC0" zusammenkleben würde, kommt nicht "b0" raus,
> sondern "bPC0" und das ist kein Element von "struct bits".
> Das Macro "PC0" muß erst noch zu "0" expandiert werden.

Ganz so einfach ist es nicht, denn dann dürfte

#define LED_BIT   PC0
#define LED             SBIT( PORTC, LED_BIT )

nicht compilieren :-)
Die Reihenfolgen in der Makros selbst bzw. Makroargumente expandiert 
werden ist in manchen Fällen auf den ersten Blick etwas dubios.

##, genauso wie #, verhält sich hier einfach anders. Beide expandieren 
ihre möglichen Makroargumente selbst nicht. Zumindest nicht so, wie es 
an anderen Stellen der Makrobearbeitung passiert.

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.