Bitmanipulationen bei AVR GCC

Im Unterforum Microcontroller - Beschreibung: Hardware - Software - Ideen - Projekte

Elektronik Forum Nicht eingeloggt       Einloggen       Registrieren




[Registrieren]      --     [FAQ]      --     [ Einen Link auf Ihrer Homepage zum Forum]      --     [ Themen kostenlos per RSS in ihre Homepage einbauen]      --     [Einloggen]

Suchen


Serverzeit: 24 11 2024  05:55:56      TV   VCR Aufnahme   TFT   CRT-Monitor   Netzteile   LED-FAQ   Osziloskop-Schirmbilder            


Elektronik- und Elektroforum Forum Index   >>   Microcontroller        Microcontroller : Hardware - Software - Ideen - Projekte


Autor
Bitmanipulationen bei AVR GCC

    







BID = 703477

wulf

Schreibmaschine



Beiträge: 2246
Wohnort: Bozen
 

  


Ich sitze gerade an meinem ersten ATmega8535 und lese gerade im AVR GCC Tutorial von mikrocontroller.net.

Und schon kommt die erste Frage:
Gibts denn keinen besseren (einfacheren) Weg einzelne Bits zu manipulieren als mit Bitmasken?

Ich stell mir das so ähnlich wie bei den PICs vor, a la:

PORTA.3 = 1;

Danke für die Hilfe.

Grüße
Simon



_________________
Simon
IW3BWH

BID = 703515

DonComi

Inventar



Beiträge: 8605
Wohnort: Amerika

 

  

Moin Simon,

Im Gegensatz zu dieser unsäglichen BASIC-Syntax (Port.Bit) sind Bitmasken viel intelligenter, lassen sich damit doch gleichzeitig auch mehrere Bits manipulieren.
Zudem erleichtert es z.B., bestimmte Bitpositionen in Treibern festzulegen, wie z.B.

#define LED 5 /* Led ist an Bit5 angeschlossen */
#define LEDPORT PORTD

/* LED anschalten */
LEDPORT |= 1<<LED;

/* LED ausschalten */
LEDPORT &= ~(1<<LED);

/* LED-Zustand umkehren */
LEDPORT ^= 1<<LED;


Allerdings ist diese Syntax (Port.Led) bei anderen Umgebungen durchaus Standard, da dort die Portverwaltung über Strukturen läuft. Und auf Elemente einer Struktur greift man nunmal mit dem .-Operator zu.

Das kann dann wirklich so aussehen:

PORT.Bit4 = 1;


Dennoch sind Bitmasken allgemein der bessere Weg, weil viel allgemeiner anwendbar.

_________________

BID = 703528

wulf

Schreibmaschine



Beiträge: 2246
Wohnort: Bozen

Auf den ersten Blick hats mir erstmal die Augen verdreht. Ich war bisher PIC IDE gewöhnt.
Aber wenn du sagst, dass Bitmasken hier üblich sind werd ich mich wohl daran gewöhnen müssen.

Vielen Dank schonmal

Grüße
Simon

_________________
Simon
IW3BWH

BID = 703539

DonComi

Inventar



Beiträge: 8605
Wohnort: Amerika

Hallo Simon,

Ja, es stimmt schon: das sieht sehr kryptisch aus .

Aber Bitmasken werden allgemein genutzt, um Bits gezielt zu manipulieren.
So werden z.B. Ganzzahlen benutzt, um unabhängige Flagbits zu speichern und die Auswertung dieser Bits geschieht mit Bitmasken.
Das kann so aussehen:

/* Wie soll die Datei geöffnet werden? */
#define READ 0
#define WRITE 1
#define APPEND 2
#define BINARY 3


FILE* mein_fopen(char const* filename, int mode)
{
 if( mode & (1<<READ) ) dothat;
 if( mode & (1<<WRITE)) dothis;
 if( mode & (1<<APPEND))...;
 if( mode & (1<<BINARY))...;
 .
 .
 .
}

int main(int argc, char** argv)
{
 .
 .
 .
 /* Binärdatei zum Lesen und Schreiben öffnen */
 FILE* meine_datei = mein_fopen("/home/david/datei", 1<<READ|1<<WRITE|1<<BINARY);
 .
 .
 .
}


OK, das Beispiel hinkt: meist schreibt man statt 1<<1 gleich 0x1. Prinzipiell ist es aber synonym zueinander.


Die Operationen dabei (|,&,^,<<) sind dabei Bitoperationen, die man auch anderweitig nutzt. Wenn dir das zu kryptisch ist, dann kannst du dir ja auch, analog zum AVR-Assembler-Dialekt, folgende Makros definieren:
#define sbi(port,bit) port |= (1<<bit)
#define cbi(port,bit) port &=~(1<<bit)



Wenn man in Treibern (sei es z.B. für ein Display) die IOs völlig frei belegen lassen will, dann kann man sogar so nette Dinge konstruieren wie:
/* Strobe-Leitung: */
#define STROBE PORTD, 5

.
.
.
/* im Treiber */
sbit(STROBE);

cbit(STROBE);

.
.
.


Spätestens dann sind Bitmasken essentiell

_________________

BID = 703580

wulf

Schreibmaschine



Beiträge: 2246
Wohnort: Bozen

Ich werds einfach mal mit den Bitmasken versuchen, und wenn ich zu viele "Fehler" reinhaue kann ich ja immer noch mit dem Makros versuchen.

Danke für den vielen Beispielcode. Werde das in Ruhe durcharbeiten.

Als Hintergrundinfo:
Das aktuelle Projekt mit dem ich in die AVR µC einsteigen will ist ein Sensorbus für eine Wetterstation basierend auf RS-485. Eine Interfaceplatine soll von RS-232 auf RS-485 wandeln. Vor allem gehts um die Steuerung von Read/Write auf dem RS-485 Bus da die RS-232 nur RxD und TxD zur Verfügung stellt.
Der Sensorbus wird dann an eine RS-232 eines Routerboards (Mikrotik) angeschlossen das Teil eines WLAN Netzes für Amateurfunk ist.
Wenn alles so funktioniert wie geplant wird jeder WLAN Umsetzer mit einer Wetterstation ausgestattet.
Abgefragt werden die Sensoren im Bus dann von einem fernen Server der die ganze Datenaufbereitung übernimmt und auf einer Website zur Verfügung stellt. Die Sensoren sollen aber auch leicht getestet und konfiguriert werden können, deshalb ein ASCII Protokoll das auch menschenlesbar ist.


Grüße
Simon

_________________
Simon
IW3BWH

BID = 703760

BjörnB

Stammposter

Beiträge: 242
Wohnort: Dortmund

Hallo Simon,

in der avr-libc gibts bereits ein Makro: #define _BV (bit) (1 << (bit))
Damit kann man das Bitshiften optisch unter _BV "verstecken" und z.B. TCCR2 = _BV(COM20)|_BV(CTC2)|_BV(CS20) statt TCCR2 = (1 << COM20)|(1 << CTC2)|(1 << CS20) schreiben, siehe http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_use_bv

Schöne Grüße,
Björn


BID = 703764

DonComi

Inventar



Beiträge: 8605
Wohnort: Amerika


Offtopic :

Hallo

Also, diese _BV-Dinger zerstören imho jeden schönen Code...
Dann lieber in Pseudo-ASM-Notation (sbit) oder aber dann makrolos.

Das hebt finde ich auch vielmehr den Charakter hervor: die IO-Ports sind ja im RAM gemappt (PORTD ist ein Symbol, was eigentlich ganz eklig aussieht...) und man manipuliert dabei eigentlich bloß Speicherstellen.

(Der GCC optimiert diese RAM-Zugriffe unterhalb einer bestimmten IO-Adresse hin zu den Opcodes für sbi und cbi.)


Schöne Grüße,
David


_________________

BID = 703956

wulf

Schreibmaschine



Beiträge: 2246
Wohnort: Bozen

Hallo,
da diese BV Dinges auch nichts anderes als die Bitmaske aufbaut werd ich eher die Bitmaske direkt aufbauen, sonst vergisst man irgendwann noch was dahinter steckt und findet Fehler nicht mehr.

_________________
Simon
IW3BWH

BID = 707453

gerhard54

Gelegenheitsposter



Beiträge: 76
Wohnort: Wien

Hallo,

ich möchte auch meinen Senf dazugeben ;-)....

Prinzipiell stimme ich allen zu, mit Bit-Masken ist es einfacher und übersichtlicher.

Was mich allerdings etwas stört, ist die Sache mit "1 << Bitx".
Aus der Programmierung für UNIX-Systeme bin ich gewohnt, daß Bits mit ihrem WERT und nicht ihrer POSITION kodiert werden. also nicht:

#define READ 0
#define WRITE 1
#define APPEND 2
#define BINARY 3
und
if( mode & (1<<READ) ) dothat;
if( mode & (1<<WRITE)) dothis;
if( mode & (1<<APPEND))...;
if( mode & (1<<BINARY))...;

sondern:
#define READ 1
#define WRITE 2
#define APPEND 4
#define BINARY 8
und
if( mode & READ ) dothat;
if( mode & WRITE) dothis;
if( mode & APPEND)...;
if( mode & BINARY)...;

Kennt jemand den Grund für das für den AVR nicht so gemacht wird?
Mir kommt die zweite Art einfacher und übersichtlicher vor...
Man könnte dan einfach schreiben:

if(PINA & PIN3)
....

LG
Gerhard



[ Diese Nachricht wurde geändert von: gerhard54 am 12 Aug 2010 21:11 ]

BID = 707455

DonComi

Inventar



Beiträge: 8605
Wohnort: Amerika

Hallo Gerhard,

Ja, du hast völlig Recht, nicht nur in Unix macht man diese Klimmzüge nicht.

Dies war eher ein allgemeines, eher unpassendes Beispiel für die Schiebeoperatoren.
Gerade in hardwarenahen Systemen bieten sich diese Operatoren aber an, um beispielsweise kleinere Bibliotheken etwas generischer zu programmieren, Beispiel LCDs:


#define LCD_BIT_E 6
#define LCD_BIT_RW 2
#define LCD_BIT_RS 0

int open_lcd(void)
{
 PORT |= 1<<LCD_BIT_E;
 .
 .
 .
}


Natürlich kann man auch statt 1<<LCD_BIT_E PORT |= 0x01; schreiben.
Speziell hier finde ich die Schiebeoperatoren wesentlich praktischer, ist aber alles reine Geschmackssache.



_________________

BID = 707462

gerhard54

Gelegenheitsposter



Beiträge: 76
Wohnort: Wien

Hallo Wulf,

ganz überzeugt hast Du mich nicht, ich finde

#define LCD_BIT_E 0100
#define LCD_BIT_RW 04
#define LCD_BIT_RS 01

int open_lcd(void)
{
PORT |= LCD_BIT_E;
.
}

einfach übersichtlicher und weniger anfällig für (Tip-)Fehler.
Natürlich hat der, der die Library an eine andere Hardware anpasst etwas mehr Arbeit,
Er muß die "Werte" neu berechnen.
Ich hab' sie daher immer oktal geschrieben, da geht das fast von alleine.

#define PIN0 01
#define PIN2 02
#define PIN3 08
#define PIN4 010
...

Aber das ist Geschmackssache und ich will ja keinen Glaubenskrieg entfachen!

Gerhard


BID = 707468

DonComi

Inventar



Beiträge: 8605
Wohnort: Amerika

Moin,

ich bin nicht wulf

Jemand, der sowas schon länger macht, der nutzt lieber direkt Masken ohne Schiebeoperation. Ich z.B. notiere sie direkt in hexadezimaler Form, dort sieht der geübte Blick schon, welche Bits gesetzt sind und welche nicht.

Viele fangen aber mit AVRs an und haben von Nichts eine Ahnung. Die schauen dann ins Datenblatt: "Ah, PortD, Pin 4, toll, und wo trage ich das ein?".


Wie gesagt, beide Ausdrücke sind vom Informationsgehalt praktisch gleichwertig.

Glaubenskrieg haben wir bald genug, da müssen wir hier nicht auch schon anfangen...

_________________

BID = 707475

clembra

Inventar



Beiträge: 5404
Wohnort: Weeze / Niederrhein
ICQ Status  

Ein Grund für diese Schreibweise dürfte auch sein, dass die Angaben in den AVR-Gerätedefinitionen bereits in der Positionsschreibweise vorgegeben sind - es gibt ja nicht nur die externen Ports. Dann hätte man die Wahl zwischen alle vorgefertigten Definitionen (bzw. jene, die man braucht) neu zu notieren, und zwar für jeden Gerätetyp, oder zwei verschiedene Systeme zu nutzen, und da wird man wohl selber durcheinander kommen. Dann lieber die unschönere Schreibweise, dafür aber schön gleichmäßig. Für den µC ist es so oder so egal, da kommt nur noch das Ergebnis an.

_________________
Reboot oder be root, das ist hier die Frage.

BID = 707477

DonComi

Inventar



Beiträge: 8605
Wohnort: Amerika

Ja, die avr-libc dürfte daran Schuld sein.

Zudem sind die Programmbeispiele in den jeweiligen Datenblättern konsequent mit reinen Schiebeoperatoren geschrieben.

Wie gesagt, es ist fast egal. Viel 'bösere' Fehler werden von Anfängern gemacht, die sich noch nicht sehr auskennen - da wird dann für die Bitposition ein zur Compile-time unbekannter Wert benutzt...

Zudem kann man bei Bismasken verdeutlichen, welchen Gültigkeitsbereich (Wortbreite) die Maske hat:

0x1000
0x0080
0x0002

Ist deutlich als 16bit-Maske erkennbar.

_________________

BID = 707502

wulf

Schreibmaschine



Beiträge: 2246
Wohnort: Bozen

Hallo,
jetzt geb ich auch mal wieder meinen Senf dazu.
Hab jetzt etwas rumprobiert und schreibe die Bitmasken jetzt auch direkt. Am liebsten in Binärer Notation, da erkennt dann jeder was gemeint ist. Leider unterstützt der Compiler das noch nicht so lange und könnte mit älteren Versionen Probleme geben.

Etwas was mir allgemein bei den AVR aufgefallen ist:
Für den Anfänger gibt es sehr viel weniger Fallstricke als z.B. bei den PIC.

Grüße
Simon

_________________
Simon
IW3BWH


Zurück zur Seite 0 im Unterforum          Vorheriges Thema Nächstes Thema 


Zum Ersatzteileshop


Bezeichnungen von Produkten, Abbildungen und Logos , die in diesem Forum oder im Shop verwendet werden, sind Eigentum des entsprechenden Herstellers oder Besitzers. Diese dienen lediglich zur Identifikation!
Impressum       Datenschutz       Copyright © Baldur Brock Fernsehtechnik und Versand Ersatzteile in Heilbronn Deutschland       

gerechnet auf die letzten 30 Tage haben wir 19 Beiträge im Durchschnitt pro Tag       heute wurden bisher 3 Beiträge verfasst
© x sparkkelsputz        Besucher : 182385882   Heute : 607    Gestern : 6874    Online : 647        24.11.2024    5:55
0 Besucher in den letzten 60 Sekunden         ---- logout ----viewtopic ---- logout ----
xcvb ycvb
0.0881261825562