Hallo zusammen, ich == GCC-Anfänger :-)) ich habe ein Byte FLAGS. Dort speichere ich allerhand Zustände. Nun möchte ich einige Bits sezten und einige löschen. Im GCC tutorial und in den entsprechenden Verweisen zur Bitmanipulation werden immer mal ein oder meherere Bit gesetzt und mal welche gelöscht. Habe ich auch verstanden. Bits setzen: #define BIT2 (2) . #define BIT5 (5) . . . FLAGS |= (1<<BIT5)|(BIT2) Bits löschen: FLAGS &= ~((1<<BIT5)|(1<<BIT2)) Soweit klar, muss man nur wissen und verstanden haben... Wenn ich jetzt BIT5 und BIT1 setzen will UND BIT2 und BIT3 löschen, (die restlichen sollen bleiben, wie sie sind) was mach ich denn dann?? FLAGS |= (1<<BIT5) | (1<<BIT1) FLAGS &= ~((1<<BIT3) |(1<<BIT2)) würde gehen. Das geht doch sicher auch irgentwie in einer Zeile, oder? dankeschön AxelR.
FLAGS = (FLAGS|(1<<BIT5) | (1<<BIT1))&(~((1<<BIT3) |(1<<BIT2)));
So sollte das funktionieren: FLAGS = (FLAGS | ((1<<BIT5) | (1<<BIT1)) & ~((1<<BIT3) |(1<<BIT2)) (Einfach klammern, wie in der Mathematik...) Ich finde das allerdings deutlich weniger übersichtlich als die "ausführliche" Variante. Im compilierten Code ergeben sich damit sicher auch keine Vorteile.
Das ging schnell!! g Ich probier mal, ob es mehr Code wird. Die Übersichtlichkeit leidet wirklich - muss man zugeben. Vielen Dank! AxelR.
#define GPRMC (4) #define GPGGA (5) case ('A'): // The GPGGA sentence ID contains "A" //getrennte Umschaltung der Stati GPS_STATUS &= ~(1<<GPRMC); d0: 80 91 0a 02 lds r24, 0x020A d4: 8f 7e andi r24, 0xEF ; 239 d6: 80 93 0a 02 sts 0x020A, r24 GPS_STATUS |= (1<<GPGGA); da: 80 91 0a 02 lds r24, 0x020A de: 80 62 ori r24, 0x20 ; 32 e0: 80 93 0a 02 sts 0x020A, r24 // oder als Einzeiler GPS_STATUS = (GPS_STATUS|(1<<GPGGA) )&(~(1<<GPRMC)); e4: 80 91 0a 02 lds r24, 0x020A e8: 80 62 ori r24, 0x20 ; 32 ea: 8f 7e andi r24, 0xEF ; 239 ec: 80 93 0a 02 sts 0x020A, r24 return; f0: 08 95 ret } return; GPS_STATUS musste ich als 'volatile' deklarieren, sonst hat der Compiler schlicht weg garnichts gemacht. Das lerne ich noch... Da ich eh nur zwei Datensatztypen (GGA+RMC) habe, könnte man auch mit "^=" arbeiten. Fazit: Der Einzeiler ist (unwesentlich) kürzer, vielen Dank nochmals. AxelR.
unschwer zu erkennen: ich kämpfe mit meinem GPS-Empfänger :-)) http://www.mikrocontroller.net/forum/read-2-217483.html#306655 http://www.mikrocontroller.net/forum/read-1-371391.html#371391 AxelR.
> GPS_STATUS musste ich als 'volatile' deklarieren, sonst hat der > Compiler schlicht weg garnichts gemacht. Dann hast du das Ergebnis wohl nicht weiter benutzt.
Wenn es um das gleichzeitig setzen und löschen geht, könntest Du ja auch mit einer Hilfsvariable arbeiten und zunächst da alles machen und dann zurückschreiben.
1 | temp = flag; |
2 | temp |= (1<<BIT5) | (1<<BIT1) |
3 | temp &= ~((1<<BIT3) |(1<<BIT2)) |
4 | flag = temp; |
@Werner naja, soo gleichzeitig muss es nicht... trotzdem Danke! @Jörg Ja, ich hatte die Variable noch nicht "in Verwendung". Das stimmt wohl - so weit war ich da noch nicht. In der Hauptschleife frage ich nach, ob beide GPS-Datensätze vorliegen, um diese dann verarbeiten zu können. Da es nur zwei sind ($GGA und $RMC), waren da noch Bits in der Variable "GPS_STAUS" frei. Es gibt im Programm zwar eine Variable namens "sentence_type". Aber die wollte ich sparen und statt dessen BIT 5 und 6 oderso von "GPS_STAUS" mit heranziehen. Ich werde mir mal die Bitfields (hiess doch so?) ansehen. Damit gehts vielleicht einfacher. Men "IF" Konstrukt in der Main sieht toll aus! Passt (fast) garnicht in eine Zeile if (((GPS_STATUS & (1<<RMC_OK)) == (1<<RMC_OK)) && ((GPS_STATUS & (1<<GGA_OK))== (1<<GGA_OK))) Wenn da jemand eine Idee hat... Sollte aber so den Regeln entsprechen. rmc_ok und gga_ok sind per define festgelegt #define GGA_OK (2) #define RMC_OK (3) Bin noch am lernen. sprintf für Debugausgaben ist ja wohl der Hammer! Da platzt mein kleiner Mega48 ja sofort aus allen Nähten :-(( schmoll Dabei wollte ich unterwegs nur Grad, Minuten und sekunden (Länge/Breite) in eine ganzzahl wandeln und mit der von Zuhause vergleichen. Das kann ich mir wohl in "C" und mit dem Mega48 abschminken - schade... Viele Grüße, schönen Dank AxelR.
Das geht kompakter: if (((GPS_STATUS & (1<<RMC_OK)) == (1<<RMC_OK)) && ((GPS_STATUS & (1<<GGA_OK))== (1<<GGA_OK))) kann auch als if ((GPS_STATUS & (1<<RMC_OK)) && (GPS_STATUS & (1<<GGA_OK))) geschrieben werden. Da in beiden Teilausdrücken GPS_STATUS mit nur einem Bit verANDet wird, genügt es, auf != 0 abzufragen. Das macht das doch schon ein bisschen lesbarer, oder?
> Ja, ich hatte die Variable noch nicht "in Verwendung". Dann ist der Compiler wirklich eifrig im Wegoptimieren. volatile kann dagegen helfen, man sollte nur dran denken, es wieder rauszuwerfen, wenn der Code fertig ist. > Ich werde mir mal die Bitfields (hiess doch so?) ansehen. Damit > gehts vielleicht einfacher. Ja, für derartige Flags nehme ich gern mal bit fields. > Bin noch am lernen. sprintf für Debugausgaben ist ja wohl der > Hammer! Da platzt mein kleiner Mega48 ja sofort aus allen Nähten > :-(( Debuggen sollte man auch nicht auf einem ATmega48. Fürs Debuggen kann man nie genug Ressourcen frei haben. Nimm einen ATmega168, der ist pin- und funktionskompatibel bei deutlich mehr Speicher. printf() ist halt vom Prinzip her riesig, da die Entscheidung, was von den Möglichkeiten wirklich benötigt wird, erst zur Laufzeit feststeht. > Dabei wollte ich unterwegs nur Grad, Minuten und sekunden > (Länge/Breite) in eine ganzzahl wandeln und mit der von Zuhause > vergleichen. Das kann ich mir wohl in "C" und mit dem Mega48 > abschminken - schade... Oder halt mit itoa() arbeiten, da hast du eben nur keine netten Dinge wir Vornullen etc.
Wenn es reicht, auf !=0 abzufragen, dann könnte man ja auch eine weitere Definition einführen, wo beide (RMC_OK und GGA_OK) enthalten sind. Dann allerdings nicht mehr auf !=0 abfragen, sondern auf die Summe beider. #define GSP_OK (12) //BIT2 und BIT3 zusammen if ((GPS_STATUS & GPS_OK) == GPS_OK) müsste ja gehen, oder? Naja - macht jedenfall Spaß. Obwohl ich besser und schneller kleine Leiterplatten entwerfen kann. Vlt.kann ich da ja mal jemanden helfen - würde mich freuen! man kann eben nicht alles können :-)) Ich habe im Makefile jetzt erstmal die minimalistische Printf Variante eingestellt. Das brachte nochmal 1K einsparung. Ich könnte die Daten aber auch auf PORTB ohne Printf ausgeben... Jetzt werd ich erstmal einen Mega168(wiedermal nur im MLF) "anfassbar" machen. Habe i.M. keinen anderen zur Hand. VlG AxelR.
Hi, du koenntest auch die Output Funktionen von Peter Danneger aus der Codesammlumng nehmen. Der Code von PeDa ist fuer C51, aber ich hatte sie damals auf GCC portiert. Der Code braucht 900 Byte fuer String, hex, Dezi, Float usw. Gruß, Dirk
..Output Funktionen..Codesammlumng..Peter Danneger finde ich nicht! ich habe nach "C51", "Output", "PeDa", "float", "printf" usw. in der Codesammlung gesucht :-(( määäh
> Das geht kompakter: > > if (((GPS_STATUS & (1<<RMC_OK)) == (1<<RMC_OK)) && ((GPS_STATUS & > (1<<GGA_OK))== (1<<GGA_OK))) > > kann auch als > > if ((GPS_STATUS & (1<<RMC_OK)) && (GPS_STATUS & (1<<GGA_OK))) Oder noch ne Variante: Wenn man Schreibarbeit sparen möchte, kann man sich oft mit einem Makro helfen (auch wenn ich nicht so ein Fan von Makros bin, na ja von C++ halt 'verdorben' ) #define BIT_SET( Where, What ) ( Where & (1<<What) == (1<<What) ) Dann schreibst du if( BIT_SET( GPS_STATUS, RMC_OK ) && BIT_SET( GPS_STATUS, GCA_OK ) ) Wobei ich sagen muss, dass ich solche && oder || verknüpfte logische Ausdrücke überhaupt gerne auf 2 Zeilen aufteile.
@Dominik gefunden und kopiert - Danke! Probier ich heute abend aus. @Karl-Heinz Makros? intesessant... und hier mal einleuchtend (habe da aber auch schon ganz übelst komplizierte Sachen gesehen) Man kann doch nicht einfach so eine neue Zeile anfangen? Nun, offensichtich doch - Mega168 im MLF nach elm-chang (kopfüber mit doppeltape auf lochraster) adaptiert (schwitz) gg Schönen Gruß AxelR.
Warum so umständlich? #define BIT_SET( Where, What ) ( Where & (1<<What) == (1<<What) ) Den Vergleich kann man sich hierbei schenken #define BIT_SET( Where, What ) ( Where & (1<<What)) da nur ein Bit abgefragt wird. Ein blöder Compiler macht daraus womöglich einen richtigen Vergleich, statt einfach auf 0 bzw. Nichtnull zu testen. Ich würde allerdings bei der Namenswahl auch noch etwas länger nachdenken, es geht ja nicht darum, ein Bit zu setzen, sondern um zu testen, ob es gesetzt ist. Das nur am Vertauschen von "bit" und "set" festzumachen ...
BIT_IS_SET klingt gut. C macht Spass (FatsAVR war aber einfacher [auweia- bin schon weg]) - ich muss aber weiterabreiten, bis denne AxelR.
> Warum so umständlich? :-) Weil es immer wieder Programmierer gibt, die sich in den Fuss schiessen. Im Ernst. Ich hab vor Jahren den Vergleich mal weggelassen. Prompt hat ein Kollege das hier gebaut (sinngemaess): int NrBitsSet = BIT_SET( PORTA, 2 ) + BIT_SET( PORTA, 3 ) + BIT_SET( PORTA, 4 ); if( NrBitsSet > 1 ) // wenn mindestens 2 von 3 gesetzt sind > BIT_IS_SET klingt gut Meist zieht man das IS vor: IS_BIT_SET Alle Dinge die mit 'IS' beginnen sind 'Prädikate' (liefern also eine Ja/Nein Aussage). Ist aber nur so eine Konvention. > C++ ist sogar noch viel cooler. Da steh ich voll drauf :-)
> Man kann doch nicht einfach so eine neue Zeile anfangen? > Nun, offensichtich doch - Klar kann man. Wenn dein Compiler deinen Source Code in die Finger kriegt (nach dem Präprozessor), dann ist das erste was er macht: Er ersetzt den sog. 'Whitespace' durch genau ein Leerzeichen. Whitespace sind Sequenzen, die nur aus Leerzeichen, Tabulatoren, Zeilentrenner bestehen. Oh. Vorher werden, glaub ich, noch Kommentare durch ein Leerzeichen ersetzt. d.h. Dein Compiler macht aus dem hier int i; int j; for( i = 0; i < 8; ++i ) j = 5; das hier: int i; int j; for( i = 0; i < 8; ++i ) j = 5; Gibt auch keinen Grund das nicht zu tun. Der Compiler wird durch die C Grammatik udnd die ';' geleitet und nicht durch die Zeilentrenner. Fortran ist da noch konsequenter: Alle Leerzeichen (natuerlich nicht in Strings) werden entfernt bevor die Anweisung übersetzt wird. d.h. man kann in Fortran auch so schreiben: I N T E G E R * 4 ALPHA R E A L * 8 BETA BETA = A L P H A * 2 man kann aber auch so schreiben :-) INTEGER*4ALPHA REAL*8BETA BETA=ALPHA*2
> das hier: > > int i; int j; for( i = 0; i < 8; ++i ) j = 5; Na ja. Er macht es nicht wirklich. Aber er tut so als ob.
Dazu fällt mir nur noch ein: Real programmers can program FORTRAN in any language. :-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.