Vad innebär "for (i=0x80;i>0;i/=2)" (C-program

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
PHermansson
EF Sponsor
Inlägg: 4340
Blev medlem: 22 december 2004, 00:46:38
Ort: Särestad Grästorp
Kontakt:

Vad innebär "for (i=0x80;i>0;i/=2)" (C-program

Inlägg av PHermansson »

Har börjat fundera på att koppla en SHT11 (fuktighetsmätare) till en PIC18F4450. Har kollat lite på den exempelkod som finns (http://www.sensirion.com/en/02_sensors/ ... _sht11.htm).
Har dock kört fast tämligen omgående :)
Vad har 'i/=2' för funktion?

Kod: Markera allt

for (i=0x80;i>0;i/=2)      //shift bit for masking
{ if (i & value) DATA=1;   //masking value with i , write to SENSI-BUS
  else DATA=0;
  SCK=1;                   //clk for SENSI-BUS
  _nop_();_nop_();_nop_(); //pulswith approx. 5 us
  SCK=0;
}
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Inlägg av thepirateboy »

Det blir väl samma sak som att skifta värdet för "i" ett steg till höger, 0x80, 0x40, 0x20 osv.
Användarvisningsbild
oJsan
EF Sponsor
Inlägg: 1541
Blev medlem: 11 november 2005, 21:36:51
Ort: Umeå
Kontakt:

Inlägg av oJsan »

variabeln i delas med två varje varv som for-loopen körs.

Kod: Markera allt

i+=1; <=> i = i + 1;
i/=2; <=> i = i / 2; 
Har du tur så översätter kompilatorn det hela till en "högerskift". :)

Edit: Piraten hann före...
Användarvisningsbild
oJsan
EF Sponsor
Inlägg: 1541
Blev medlem: 11 november 2005, 21:36:51
Ort: Umeå
Kontakt:

Inlägg av oJsan »

Hmm... lite optimering som borde fungera:

Kod: Markera allt

for (i=0x80;i>0;i/=2)      //shift bit for masking
{ 
  DATA=(i & value); //write to SENSI-BUS
  SCK=1;                   //clk for SENSI-BUS
  _nop_();_nop_();_nop_(); //pulswith approx. 5 us
  SCK=0;
}
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

"i/=2;" kan också göras mer begripligt med "i >>= 1;"
Ger antagligen ingen skillnad i den kompilerade koden. Skulle den det så blir det åt det bättre. ;)
Användarvisningsbild
AndLi
Inlägg: 18327
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Inlägg av AndLi »

oJsan skrev:Hmm... lite optimering som borde fungera:

Kod: Markera allt

for (i=0x80;i>0;i/=2)      //shift bit for masking
{ 
  DATA=(i & value); //write to SENSI-BUS
  SCK=1;                   //clk for SENSI-BUS
  _nop_();_nop_();_nop_(); //pulswith approx. 5 us
  SCK=0;
}
Det blir ju en rätt stor skillnad...
I orginalkoden blir ju DATA alltid 1 (om bitten är satt i value), men i den optimerade koden kommer DATA vara beroende av värdet av i, DATA kommer istället för att bli 1 bli 0x80,0x40,0x20 osv...

så frågan är ju hur DATA är definierat,
Användarvisningsbild
PHermansson
EF Sponsor
Inlägg: 4340
Blev medlem: 22 december 2004, 00:46:38
Ort: Särestad Grästorp
Kontakt:

Inlägg av PHermansson »

Tack för snabba svar! Då har man lärt sig något nytt idag med :)
DATA är definierad som en I/O-pinne som är kopplad till SHT11'an, så den optimeringen fungerar nog inte så bra. Det är ett I2C-liknande interface som används, SCK är klockan och DATA är just data.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Om den ändras till:
DATA=((i & value) == 1);
så borde det bli som oJsan tänkte...
Användarvisningsbild
GrodanB
Inlägg: 245
Blev medlem: 11 februari 2006, 16:46:25
Ort: Göteborg
Kontakt:

Inlägg av GrodanB »

Sen vill jag mena att man litar aldrig på en kompilator att den skall göra nått smart. Vet man att det snabbaste sättet är en shift, ANVÄNDER man en shift!

Alltså skall man använda shift och inte division i denna kod.

Kompilatorernas "smarthet" beror inte bara på tillverkaren utan också på hur du har satt upp kompileringsflaggorna...

Sen är jag lite skeptisk till spekamans förslag till förbättring... den beror på hur kompilatorn tolkar det hela...

Genom att göra en boolsk bitoperand och sedan en logisk så blir ju bara DATA = 1 i några fall... dvs. då resultatet av den boolska operanden blir 1 och endast då. Så jag vill säga att den skall i så fall vara:

Kod: Markera allt

DATA=((i & value) != 0); 
Eller har jag fel??? Inte otroligt i så fall... :)
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Din variant är givetvis att föredra. Så hade jag helst också gjort, var nog lite för snabb med mitt inlägg bara. :)
Användarvisningsbild
oJsan
EF Sponsor
Inlägg: 1541
Blev medlem: 11 november 2005, 21:36:51
Ort: Umeå
Kontakt:

Inlägg av oJsan »

Om DATA är deklarerad som boolean (vilket var ett dumt antagande av mig) så fungerar både min och speakmans förslag (och GrodanB's).
En boolsk variabel blir SANN om ett tal skiljt ifrån 0 tilldelas den (någon som vet en annan definition som används i någon kompilator?).
bool b = (unsigned short)123; kommer alltså bli SANN.

Men GrodanB har ju rätt, hans omskrivning fungerar oavsett vad DATA är deklarerad som. Speakmans skulle fungera om man skriver såhär:

Kod: Markera allt

DATA=((bool)(i & value) == 1); 
:jimmyhacker:
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

bool är ingen datatyp i C, samt !0 == 1 så min hade fungerat oavsett.
Men av logiska själ skulle jag föredra grodans variant.
Användarvisningsbild
GrodanB
Inlägg: 245
Blev medlem: 11 februari 2006, 16:46:25
Ort: Göteborg
Kontakt:

Inlägg av GrodanB »

!FALSE är lika med 1 men utdatat från (i & value) operanden är inte 0 eller 1 utan 0 eller nått annat.

Det finns de som använder ~ istället för ! i if satser men det är livsfarligt...

Så eran kod fungerar bara om man använder dv.s

Kod: Markera allt

DATA=((i && value) == 1); 
För då kommer utdatat från parantesen vara definierat som 0 eller 1...

Men tanken är ju att maska bitar ur value så det är ju inte rätt.

För att kunna göra som ni föreslår får man shifta ner den utmaskade biten för att sedan sätta den till data.

Personligen hade jag nog gjort så... Dvs. shifta och sen maska med 1 och tilldela DATA resulatet... Fast jag skulle ha kollat vilket som blir minst assembler instruktioner först.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Samma tankevurpa igen. Hade det funkat, hade även oJsans version funkat.
Ett helt annat alternativ är:
DATA = i & value ? 1 : 0;
Om man vill vara på den säkra sidan. :P
Användarvisningsbild
GrodanB
Inlägg: 245
Blev medlem: 11 februari 2006, 16:46:25
Ort: Göteborg
Kontakt:

Inlägg av GrodanB »

Men det är ingen optimering... vill minnas att det inte ens är C :) (C++ notation av en ifsats om jag inte minns fel.)

Kod: Markera allt

DATA = i & value ? 1 : 0; 
Är exakt samma som

Kod: Markera allt

if (i & value ){
  DATA = 1;
} else {
  DATA = 0;
}
(Kunde man inte indentera med TAB i CODE block? Använde SPACE)

Det är som att optimera genom att inte använd fetstil... Eller långa varibelnamn... :) Få kompilatorer genererar olika kod för detta.
Senast redigerad av GrodanB 22 november 2007, 16:20:51, redigerad totalt 1 gång.
Skriv svar