Forum: Mikrocontroller und Digitale Elektronik Einzelne Bits mit WinAvr


von Matze T. (gruetzwurschd)


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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Geist (Gast)


Lesenswert?

Such mal nach "struct" gehört und "bitfield".

von Frederik K. (n0ll4k)


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

von Matze T. (gruetzwurschd)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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:
1
  uint8_t schalter, taster, licht;
2
3
  schalter = PORTB&(1<<PORTB1);
4
  taster   = PORTC&(1<<PORTC2);
5
6
  if (schalter) licht = 1;
7
  if (taster)   licht = 0;
8
   :
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...

von z.b. so (Gast)


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

von Matze T. (gruetzwurschd)


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.

von Peter D. (peda)


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.:
1
#define LED_ROT  SBIT( PORTB, PB1 )
2
#define TASTE_OK SBIT( PINC,  PC5 )
3
4
void test(void)
5
{
6
  LED_ROT = TASTE_OK;
7
}

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

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



Peter

von Matze T. (gruetzwurschd)


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

von Peter D. (peda)


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:
1
int main( void )
2
{
3
  for(;;){
4
    if( TASTE_ON == 0 )
5
  6c:   b0 9b           sbis    0x16, 0 ; 22
6
      LED = 0;
7
  6e:   a8 98           cbi     0x15, 0 ; 21
8
    if( TASTE_OFF == 0 )
9
  70:   b1 99           sbic    0x16, 1 ; 22
10
  72:   fc cf           rjmp    .-8             ; 0x6c <main>
11
      LED = 1;
12
  74:   a8 9a           sbi     0x15, 0 ; 21
13
  76:   fa cf           rjmp    .-12            ; 0x6c <main>


Und hier der Quelltext dazu:
1
#include <avr/io.h>
2
3
4
struct bits {
5
  uint8_t b0:1;
6
  uint8_t b1:1;
7
  uint8_t b2:1;
8
  uint8_t b3:1;
9
  uint8_t b4:1;
10
  uint8_t b5:1;
11
  uint8_t b6:1;
12
  uint8_t b7:1;
13
} __attribute__((__packed__));
14
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
15
#define SBIT(x,y)       SBIT_(x,y)
16
17
18
#define LED             SBIT( PORTC, PC0 )
19
#define TASTE_ON        SBIT( PINB,  PB0 )
20
#define TASTE_OFF       SBIT( PINB,  PB1 )
21
22
23
int main( void )
24
{
25
  for(;;){
26
    if( TASTE_ON == 0 )
27
      LED = 0;
28
    if( TASTE_OFF == 0 )
29
      LED = 1;
30
  }
31
}


Peter

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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

von Matze T. (gruetzwurschd)


Lesenswert?

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

und
1
SBIT( PORTC , PC3) = 1;

folgende Fehlermeldung:

dereferencing pointer to incomplete type

ich bin irgendwie am verzweifeln!

von Peter D. (peda)


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

von Matze T. (gruetzwurschd)


Lesenswert?

Mit Bitfeldern hatte ich im Prinzip nur folgende Spielereien 
veranstaltet:

1
union gruetze
2
{
3
   struct
4
   {
5
       unsigned char bit0 : 1;
6
       unsigned char bit1 : 1;
7
       unsigned char bit2 : 1;
8
       unsigned char bit3 : 1;
9
       unsigned char bit4 : 1;
10
       unsigned char bit5 : 1;
11
       unsigned char bit6 : 1;
12
       unsigned char bit7 : 1;
13
   };unsigned char gruetz_byte;       
14
};

und dann bitweise schreiebn und auslesen

naja wie auch immer

von Karl H. (kbuchegg)


Lesenswert?

Tarkan D. schrieb:
> Mit Bitfeldern hatte ich im Prinzip nur folgende Spielereien
> veranstaltet:
>
>
>
1
> 
2
> 
3
> union gruetze
4
> {
5
>    struct
6
>    {
7
>        unsigned char bit0 : 1;
8
>        unsigned char bit1 : 1;
9
>        unsigned char bit2 : 1;
10
>        unsigned char bit3 : 1;
11
>        unsigned char bit4 : 1;
12
>        unsigned char bit5 : 1;
13
>        unsigned char bit6 : 1;
14
>        unsigned char bit7 : 1;
15
>    };unsigned char gruetz_byte;
16
> };
17
> 
18
> 
19
> 
20
>
>
> 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.

von Peter S. (psavr)


Lesenswert?

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

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

von Karl H. (kbuchegg)


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.

von Peter S. (psavr)


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

von Peter D. (peda)


Lesenswert?

Quatsch, das ist kein Mystrerium.

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

von Karl H. (kbuchegg)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.