AVR+C - Hur gör ni proffs för att sätta/läsa bitar

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Greensilver
Inlägg: 1305
Blev medlem: 21 januari 2005, 21:24:57
Ort: Sverige
Kontakt:

AVR+C - Hur gör ni proffs för att sätta/läsa bitar

Inlägg av Greensilver »

För snart ett år sedan surfade jag ju in här på forumet och började läsa om mikrokontrollers, sen så köpte jag ju mig ett STK500 och några kontrollers från SWC. Med Schnegelwerfer, M. Pihl, Icecap, Evert2, Cyr med fleras fina hjälp har jag nu lärt mig blinka både lysdioder och billampor som en tok! Vägen är dock fortfarande väldigt lång tills dess att jag kan göra mitt eget billarm (det var ju det som fick hit mig från början och nu är jag fast :) ).

Till saken; jag har nu gått från assembler, som jag började med för att lära mig hårdvaran, till C (Programmers Notepad). Nu undrar jag lite hur man "ska" göra för att sätta/polla bitar från exempelvis en port. Nedan visar jag hur jag gör. Hur gör ni som kan? Finns det en snyggare lösning som är mer lättförståelig?

För att sätta bit 0 (jag vill inte påverka någon annan bit):
PORTB=PORTB|0x01

För att sätta bit 1:
PORTB=PORTB|0x02

För att sätta bit 2:
PORTB=PORTB|0x04

osv. osv.

För att polla exempelvis bit 3:
(kan tillägga att denna funktion tog mig typ tre-fyra timmar att klura ut och få att fungera på rätt sätt. :D

Kod: Markera allt

if ((PINB&0x08)==0)
    	{
    		return 0x01;
    	}
    	else 
    	{
    	 	 return 0x00;
    	}
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

I princip är det så man gör...

Sätta en bit:

byte|=0x10;

Nolla en bit:

byte&=(~0x10);

Kolla om den är ett:

if(byte&0x10)

Kolla om den är noll:

if(!(byte&0x10))

Sen kan man låta kompilatorn räkna ut bitmasken, så istället för att skriva t.ex. 0x10 kan man skriva (1<<4), där 4 är bitpositionen man vill åt...

Och slutligen, om man vill stila till det extra mycket kan man skriva ett macro:

#define BIT_TEST(x,b) ((x)&(1<<(b)))

Som används:

if(BIT_TEST(byte,4))

Möjligheterna är obegränsade :)
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

cyr har bra beskrivning men jag använder aldrig "1<<x" versionen då shiftningen utförs i programmet och det tar tid. Såklart finns det program där men måste plocka ut en variabel bit och där är det sätt såklart det rätta.

Jag har ofta kört

Kod: Markera allt

return(!((PINB & 0x08) && 1));

i stället för

 if ((PINB&0x08)==0)
       {
          return 0x01;
       }
       else
       {
            return 0x00;
       }
om jag behöver sånt. Man kan även köra

Kod: Markera allt

Result = PINB & 0x08 ? 0: 1;
Användarvisningsbild
axelsonic
EF Sponsor
Inlägg: 709
Blev medlem: 8 juni 2003, 20:56:03
Ort: Stockholm

Inlägg av axelsonic »

Ursäkta om jag lånar tråden litet.
Men, ni som uppenbarligen verkar ena hejjare på programmering för AVR. Finns det någon C tutorial för det, eller är det något som man kanske skulle kunna få någon att skriva ? =) .
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Icecap: Varför väljer du att göra en funktion som returnera 1 eller 0, istället för att endast med if-raden returnera false (0) eller true (!=0)?
Finns det någon användning för det, eller var det bara en förenkling av Greensilvers kod?

Mvh
speakman
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

>> axelsonic

Det var en bra fråga. Med google hittade jag bara en tysk, den här. Den verkar iofs väldigt bra, men det är ju inte alla som behärskar tyska. :shock:

Ladda ner WinAVR (eller GCC om du är en pingvin). Där finns en "big" manual med som C-referens. Den hjälper om man har lite kunskaper från början, men alla har väl fötts med C-kunskaper i bakhuvudet? :roll:

Kolla på avrfreaks.com, där hittar du säkert något intressant.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Att göra en procedur för så enkel funktion betyder oftast att man spiller en hel del processortid: Först peta in parametra i stacken, sen ett kall till proceduren som petar svaret på stacken, därefter ett retur och sen ska resultaten pillas ur stacken......

Eller man kan göra den som INLINE vilket lägger in den direkt utan en massa kall osv.

Så ja, man kan kall den för förenkling, man kan mycket väl göra det som en procedure men det är inte lönt för så lite så att säga.
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Icecap skrev:cyr har bra beskrivning men jag använder aldrig "1<<x" versionen då shiftningen utförs i programmet och det tar tid. Såklart finns det program där men måste plocka ut en variabel bit och där är det sätt såklart det rätta.
Om du har en kompilator som inte beräknar konstanta uttryck vid kompileringen så ska du skrota den omgående.

Om x inte är konstant är det en annan sak, men metoden fungerar ju även då (fast med overhead vid runtime).

Litet exempel:

Kod: Markera allt

y = 1<<10;
Blir (med OR32 GCC):

Kod: Markera allt

l.addi          r3,r0,1024       # move immediate
Användarvisningsbild
axelsonic
EF Sponsor
Inlägg: 709
Blev medlem: 8 juni 2003, 20:56:03
Ort: Stockholm

Inlägg av axelsonic »

$tiff : Något av en liten pingvinär jag allt =) . Men jag använder Codevisions AVR-kompilator.

C++ har jag kodat litet i, så jag är inte helt ovan i språket. Dock så har jag aldrig kodat mot AVR eller någon annan mikroprofessor förut, så på det området är jag helt ny.

Den tyska sidan har jag hittat förrut, men min tyska är sämre än min franska och spanska. Så på den går jag bet.
Användarvisningsbild
Greensilver
Inlägg: 1305
Blev medlem: 21 januari 2005, 21:24:57
Ort: Sverige
Kontakt:

Inlägg av Greensilver »

Tackar så mycket för svaren! :D

Följdfråga:
En INLINE säger väl bara åt assemblern att skapa lite maskinkod på rätt ställe - så programmet blir större men inga anrop görs ...

... men hur är det med ett macro?
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

MACRO är oftast till för att man kan släppa skriva så mycket.

Men macro hör väl inte till C? Jag har aldrig sett det i alla fall.

Men i assembler kan det vara mycket användbart, det är inte sällan att man behöver göra "samma" funktion med olika registre/minnesceller och man kan till o med ge funktionerna vettiga namn.
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Macron i C görs genom #define

De klistras helt enkelt in i koden innan själva kompileringen, och beroende lite på hur avancerad kompilatorn (eller preprocessorn) är så kan man skriva rätt avancerade uttryck som utvärderas vid kompileringen.

Ett enkelt sådan macro kan vara:

#define MAC(sum,x,c) (sum) += (x) * (c)

Eller ett mer användbart:

#define IOWRITE32(addr,val) *((volatile unsigned long *)addr) = (val)

I många fall kan man uppnå precis samma resultat med macron som med inlines...
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

cyr: Jovisst är det rätt men i detta fall var det frågan om en ANDning och jag har märkt att vissa processorer inte gör saken helt optimerat, en del processorer som har "shiftning x steg" inbyggd utför den shiftning men det beror ju helt på preprocessorn vad resultatet blir. Och som du säger: om kompilern inte kan fatta att göra en "riktig" konstant av ett konstant uttryck kan det vara dax att hitta en annan.

Men att ha tillgång till att shifta kan vara grymt effektivt:

Kod: Markera allt

int X, Y; // Variabler, X är inkommande värde, Y är en arbetsvariabel
Y = X; // behöver ingen kommentar
X <<= 2; // X = 4*X(org)
X += Y;  // X = 5*X(org)
X <<= 1; // X = 10* X(org)
På detta viset kan man multiplicera med 10 SNABBT, på processorer med multiplokation kan det vara snabbare med sånt men en PIC16 kan läsa in ett numerisk värde från t-bord/seriell port och använda värdet enkelt o snabbt..
Användarvisningsbild
Greensilver
Inlägg: 1305
Blev medlem: 21 januari 2005, 21:24:57
Ort: Sverige
Kontakt:

Inlägg av Greensilver »

Nu har jag gjort nedanstående för att enkelt kunna sätta och cleara bitar - men det vill inte riktigt fungera. SET_BIT verkar göra vad den skall men CLR_BIT verkar rensa alla bitar.

Någon som ser vad som är fel med CLR_BIT? :oops:

#define SET_BIT(x,b) ((x)|=(1<<(b)))
#define CLR_BIT(x,b) ((x)&=(0<<(b)))
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Du måste skifta en etta och sedan invertera, annars får du bara "x&0" (= 0).

#define CLR_BIT(x,b) ((x)&=~(1<<(b)))

Borde funka...
Skriv svar