-
        

Ergebnis 1 bis 10 von 10

Thema: Bitweiser Zugriff uint16_t

  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    22.06.2009
    Beiträge
    1.265

    Bitweiser Zugriff uint16_t

    Anzeige

    Hey, da meine Platine zum testen noch nicht fertig ist würde mich kurz interessieren ob folgendes Konstrukt funktionieren würde. Ziel ist es herauszufinden welches Bit der Variable gesetzt ist.

    Code:
    uint16_t test = 0b0000000000000001;
    
    for(uint8_t i = 0; i<16;i++;)
    {
        if((test & (1<<i))==1)
       {
          //Schalte Segment an usw....
       }
    
    }

  2. #2
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.781
    Blog-Einträge
    8
    if((test & (1<<i))==1)

    Das funzt so nicht. Endweder auf größer null testen oder auf (1<<i)

    if((test & (1<<i)) > 0)
    if((test & (1<<i)) == (1<<i))

    Ein Semikolon zuviel?
    for(uint8_t i = 0; i<16;i++;)

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    22.06.2009
    Beiträge
    1.265
    Oh, danke. Jetzt wo ich noch mal drüber nachdenke ist es mir klar, dass das mit dem testen auf 1 nicht funktionieren kann.
    Das Semikolon ist in der Tat zu viel. Kleiner Tippfehler.

  4. #4
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.781
    Blog-Einträge
    8
    Wenn man davon ausgeht, dass (1<<i) immer ungleich false ist, kann man natürlich auch quick&dirty ein gesetztes Bit so prüfen:

    if(test & (1<<i))

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.551
    Zitat Zitat von radbruch
    ... quick&dirty ein gesetztes Bit so prüfen: if(test & (1<<i)) ...
    Quick´n dirty? Meine Bitprüfungen verschiedener Flags laufen z.B. so (das Beispiel mit uint16_t kann ich im Moment nicht finden):

    #define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
    ...
    if ( IsBitSet ( MNUflg, 5 ))
    ...

    und das läuft. Ne sinngemäße Abfrage auf IsBitClr habe ich mir natürlich auch definiert. Vielleicht darf ich aber über quick´n dirty in C als C-Noob kein absolutes Urteil abgeben.
    Ciao sagt der JoeamBerg

  6. #6
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    An "if (test & (1<<i))" ist absolut überhaupt nichts dirty.
    MfG
    Stefan

  7. #7
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Du könntest deinen armen µC auch etwas schonen, der shiftet ja sonst herum wie der Böse:
    Code:
    uint16_t test = 0b0000000000000001;
    
    for(uint16_t i = 1; i<=16;i<<= 1)
    {
        if(test & i)
       {
          //Schalte Segment an usw....
       }
    }
    (is aber auch noch nicht das effizienteste)
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  8. #8
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von PicNick Beitrag anzeigen
    (is aber auch noch nicht das effizienteste)
    Vor allem ist es falsch. Es testet ja nur die unteren 5 Bits.
    Code:
    for (uint16_t i = 1;  i; i <<= 1)
    Und falls im weiteren Code die Position als Bitnummer benötigt wird:
    Code:
    for (uint16_t i = 1, uint8_t pos = 0;  i; i <<= 1, pos++)
    MfG
    Stefan

  9. #9
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.781
    Blog-Einträge
    8
    Hallo

    Das "quick&dirty" bezog sich auf die Annahme, dass der Kompiler intern false als 0 speichert und deshalb jeder Wert größer 0 als true interpretiert wird. Ich wollte das nur mal wieder bewußt machen, denn "im Alltag" beachtet das eh niemand: while(1) sollte eigentlich while(true) lauten.

    #define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT)) > 0) // Fragt Bit = 1?

    So würde das Ergebniss true oder false sein.

    Das wollte ich mal genauer untersuchen, weil ich ja was lernen will. Mit C komme ich inwischen recht gut zurecht, aber mit Assembler kenne ich mich noch gar nicht aus. Dieses kleine Testprogramm wurde (ohne Optimierung!) mit 136 Bytes übersetzt:
    Code:
    #define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
    #define IsBitSet2(ADDR,BIT) (((ADDR) & (1<<BIT)) > 0)
    
    int main(void)
    {
    	int x, tmp;
    	
    	if(IsBitSet(x,0)) tmp=0x11; else tmp=0x22;
    	if(IsBitSet2(x,0)) tmp=0x33; else tmp=0x44;
    
    	while(1);
    	return(0);
    }
    IsBitSet() wird in zwei Varianten definiert, Variante eins prüft 1 oder 0, Variante zwei prüft true/false.

    Aus dem erzeugten Assemblerlisting habe ich die entscheidende Stelle rauskopiert und kommentiert (soweit mir das möglich ist):
    Code:
    .LM2:				// if((
    	ldd r24,Y+3		// x
    	ldd r25,Y+4		// x ist in Y+3 und Y+4 gespeichert
    	andi r24,lo8(1)		// & (1<<0))
    	andi r25,hi8(1)
    	tst r24			// prüft ob ein Bit in R24 gesetzt ist (Lowbyte von x!)
    	breq .L2		// springt nach L2 wenn R24 null ist
    		ldi r24,lo8(17)	// tmp=0x1111
    		ldi r25,hi8(17)
    		std Y+2,r25	// tmp ist in Y+1 und Y*2 gespeichert
    		std Y+1,r24
    		rjmp .L3
    	.L2:
    		ldi r24,lo8(34)	// tmp=0x2222
    		ldi r25,hi8(34)
    		std Y+2,r25
    		std Y+1,r24
    .L3:
    
    .LM3:
    	ldd r24,Y+3
    	ldd r25,Y+4
    	andi r24,lo8(1)
    	andi r25,hi8(1)
    	cp __zero_reg__,r24	// Vergleicht Lowbyte von x mit null
    	cpc __zero_reg__,r25	// dito Highbyte mit Carry! (beide Bytes werden ausgewertet)
    	brge .L4		// Sprung wenn beide Vergleiche null sind
    		ldi r24,lo8(51)
    		ldi r25,hi8(51)
    		std Y+2,r25
    		std Y+1,r24
    		rjmp .L5
    	.L4:
    		ldi r24,lo8(68)
    		ldi r25,hi8(68)
    		std Y+2,r25
    		std Y+1,r24
    
    .L5:				// while(1)
    	rjmp .L5
    Erstaunlicherweise ist die erste Variante kürzer, allerdings habe ich das Gefühl, mit tst r24 wird nur das Lowbyte geprüft. Beschreibung von breq:

    "Conditional relative branch. Tests the Zero Flag (Z) and branches relatively to PC if Z is set." Bedingter relativer Sprung, springt relativ zum Progammcounter, wenn ZeroFlag gesetzt ist. Das Z-Flag wird von tst gesetzt:

    Z: R7• R6 •R5• R4• R3 •R2• R1• R0
    Set if the result is $00; cleared otherwise.

    Das ist aber das Ergebniss vom Test mit R24, wo wird geprüft, ob R25 auch null ist? Sehr seltsam.

    btw. wird sowohl while(1) wie auch while(1==1) gleich übersetzt:
    .L5:
    rjmp .L5

    Gruß

    mic

    [Edit]
    tst scheint doch richtig zu funktionieren. Bei if(IsBitSet(x,0)) ergibt (1<<0) genau 1, das passt in das Lowbyte. Bei if(IsBitSet(x,15)) übersetzt der Kompiler so:
    Code:
      29               	.LM2:
      30 000c 8B81      		ldd r24,Y+3
      31 000e 9C81      		ldd r25,Y+4
      32 0010 9923      		tst r25
      33 0012 04F4      		brge .L2
      34 0014 81E1      		ldi r24,lo8(17)
      35 0016 90E0      		ldi r25,hi8(17)
      36 0018 9A83      		std Y+2,r25
      37 001a 8983      		std Y+1,r24
      38 001c 00C0      		rjmp .L3
      39               	.L2:
      40 001e 82E2      		ldi r24,lo8(34)
      41 0020 90E0      		ldi r25,hi8(34)
      42 0022 9A83      		std Y+2,r25
      43 0024 8983      		std Y+1,r24
      44               	.L3:
      45               	.LM3:
      46 0026 8B81      		ldd r24,Y+3
      47 0028 9C81      		ldd r25,Y+4
      48 002a 8070      		andi r24,lo8(-32768)
      49 002c 9078      		andi r25,hi8(-32768)
      50 002e 1816      		cp __zero_reg__,r24
      51 0030 1906      		cpc __zero_reg__,r25
      52 0032 04F4      		brge .L4
      53 0034 83E3      		ldi r24,lo8(51)
      54 0036 90E0      		ldi r25,hi8(51)
      55 0038 9A83      		std Y+2,r25
      56 003a 8983      		std Y+1,r24
      57 003c 00C0      		rjmp .L5
      58               	.L4:
      59 003e 84E4      		ldi r24,lo8(68)
      60 0040 90E0      		ldi r25,hi8(68)
      61 0042 9A83      		std Y+2,r25
      62 0044 8983      		std Y+1,r24
      63               	.L5:
      64 0046 00C0      		rjmp .L5
    Genial ;)

    [EDIT2]
    Erstaunlich was der Kompiler alles beachtet:
    Code:
    #define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
    
    int main(void)
    {
    	int x, tmp;
    	
    	if(IsBitSet(x,0)) tmp=11; else tmp=22;
    	if(IsBitSet(x,15)) tmp=33; else tmp=44;
    
    	while(1);
    	return(0);
    }
    Code:
    .LM2:
    	ldd r24,Y+3
    	ldd r25,Y+4
    	andi r24,lo8(1)
    	andi r25,hi8(1)
    	tst r24
    	breq .L2
    		ldi r24,lo8(11)
    		ldi r25,hi8(11)
    		std Y+2,r25
    		std Y+1,r24
    		rjmp .L3
    	.L2:
    		ldi r24,lo8(22)
    		ldi r25,hi8(22)
    		std Y+2,r25
    		std Y+1,r24
    	.L3:
    .LM3:
    	ldd r24,Y+3
    	ldd r25,Y+4
    	tst r25
    	brge .L4
    		ldi r24,lo8(33)
    		ldi r25,hi8(33)
    		std Y+2,r25
    		std Y+1,r24
    		rjmp .L5
    	.L4:
    		ldi r24,lo8(44)
    		ldi r25,hi8(44)
    		std Y+2,r25
    		std Y+1,r24
    .L5:
    	rjmp .L5
    Geändert von radbruch (20.07.2011 um 13:20 Uhr)

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  10. #10
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von radbruch
    Das "quick&dirty" bezog sich auf die Annahme, dass der Kompiler intern false als 0 speichert und deshalb jeder Wert größer 0 als true interpretiert wird.
    1) Man braucht da nichts "anzunehmen". Das ist vom Standard alles klipp und klar geregelt.
    2) Nicht jeder Wert größer Null ist true, sondern jeder Wert ungleich Null.
    Nochmal: da ist rein gar nichts "quick&dirty".

    Zitat Zitat von radbruch
    Variante zwei prüft true/false.
    Nein. (siehe oben)
    MfG
    Stefan

Ähnliche Themen

  1. HTTP Zugriff
    Von BuckWheat im Forum Microcontroller allgemeine Fragen/Andere Microcontroller
    Antworten: 10
    Letzter Beitrag: 30.06.2009, 08:53
  2. Warum uint16_t statt unsigned int?
    Von ricola im Forum C - Programmierung (GCC u.a.)
    Antworten: 6
    Letzter Beitrag: 05.07.2007, 18:38
  3. Zugriff auf Ports
    Von HeinzBecker im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 03.07.2007, 17:07
  4. Com Port Zugriff mit C++
    Von hacker im Forum Software, Algorithmen und KI
    Antworten: 3
    Letzter Beitrag: 13.05.2006, 12:30
  5. zugriff auf port 7-16
    Von gast im Forum Robby CCRP5
    Antworten: 4
    Letzter Beitrag: 12.03.2004, 20:56

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •