Jesses följetång om AVR programmering i C...

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR progrannering i C...

Inlägg av jesse »

Jag undrade just varför jag ibland fick en varning , ibland tre och iblans upp till 6 varningar. Hade antagligen ändrat i main.h som innehåller globala variabler och som anropas av alla källfiler.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Re: Jesses följetång om AVR programmering i C...

Inlägg av speakman »

> som innehåller globala variabler

Hur menar du nu? En .h-fil ska på sin höjd innehålla "extern"-deklarationer till globala variabler. Variablerna själva ska ligga i en av .c-filerna. Förslagsvis main.c om du har en sån.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR programmering i C...

Inlägg av jesse »

jo ,det är extern-deklarationerna.... men just för att dom finns där måste den anropas av de andra filerna.
bos
Inlägg: 2314
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Re: Jesses följetång om AVR programmering i C...

Inlägg av bos »

Vad är det som måste "anropas" av andra filer?
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR programmering i C...

Inlägg av jesse »

ehhh... varför blev detta så viktigt? :roll:

... för att de globala variablerna används i de andra c-filerna, och då måste alltså main.h anropas av dessa (eller deras respektive h-filer) ... inkluderas kanske det heter.
bos
Inlägg: 2314
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Re: Jesses följetång om AVR programmering i C...

Inlägg av bos »

Därför att semantik ÄR viktigt inom programmering.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR programmering i C...

Inlägg av jesse »

Jahapp... då är jag tillbaks igen med en liten fundering...

jag har en funktion som skickar ett 8-bitars unsigned int (uint8_t) på SPI-bussen:

Kod: Markera allt

void SPI_TransmitByte(uint8_t databyte);
och skall skicka en 24 bitars adress lagrad i en uint32_t variabel.

Jag skickar:

Kod: Markera allt

	SPI_TransmitByte(adress>>16);             // AA byte 2
	SPI_TransmitByte((adress>>8)&0xFF);   // AA byte 1
	SPI_TransmitByte(adress&0xFF);            // AA byte 0
Men det verkar som om det 32-bitars heltalet omvandlas till 8 bitars utan att jag behöver göra typomvandling, och det oavsett storlek på talet. Alltså borde jag kunna skippa &0xFF helt och ändå få ut rätt bitar:

Kod: Markera allt

	SPI_TransmitByte(adress>>16);    // AA byte 2
	SPI_TransmitByte((adress>>8));   // AA byte 1
	SPI_TransmitByte(adress);             // AA byte 0
Det ser ju till och med mer läsligt ut än det förra exemplet. Har nu lånat "Brian W Kernighans bok "Programmeringsspråket C" så det var ju lätt att konstatera att det inte blir några programfel att göra så. Den tar helt enkelt de lägsta 8 bitarna och spolar resten. Utan någon varning eller så. (Hade aldrig fungerat i Java. Hur det är med C++ vet jag inte?)
Användarvisningsbild
Icecap
Inlägg: 26658
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Jesses följetång om AVR programmering i C...

Inlägg av Icecap »

Tyvärr är detta beteende kompilerberoende varför det bör undvikas.

Och det kan enkelt fixas på annat sätt:

Kod: Markera allt

union
  {
  unit32_t LWord;
  unit8_t Byte[1]; // Ska egentligen vara [4] men duger fint såhär...
  } Address;
Adressen används så att 32-bit värdet heter "Address.LWord" och 8-bit värden heter "Address.Byte[x]" där x är 0, 1, 2 eller 3. Detta betyder att det att sända 24 bit adress plötsligt ser ut såhär:
SPI_TransmitByte(Address.Byte[2]); // AA byte 2
SPI_TransmitByte(Address.Byte[1]); // AA byte 1
SPI_TransmitByte(Address.Byte[0]); // AA byte 0

Och detta är kompileroberoende, dock är det endian-beroende.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Re: Jesses följetång om AVR programmering i C...

Inlägg av speakman »

Enda sättet att vara säker på hur värdet skickas över är att göra som du gjort, men ta med type casting:

Kod: Markera allt

   SPI_TransmitByte((uint8_t)((adress>>16) & 0xFF));   // AA byte 2
   SPI_TransmitByte((uint8_t)((adress>>8) & 0xFF));    // AA byte 1
   SPI_TransmitByte((uint8_t)(adress & 0xFF));         // AA byte 0
Det är märkligt att inte kompilatorn klagar annars. Det är väldigt lite den brukar ta för givet.

EDIT: Jag provade ditt "extremexempel" i gcc, och den varnade ingenting. Inte ens med -pedantic påslaget. Jag hade dock ändå valt att göra som koden ovan.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR programmering i C...

Inlägg av jesse »

Endianberoende.... är ju ungefär lika jobbigt som kompilatorberoende, om det nu varierar.

Frågan är vad olika kompilatorer skulle kunna hitta på i mitt exempel, förutom att trunkera, dvs bara skala bort de bitar som blir över.? Felkod eller varning kan ju vara ett alternativ kanske.

Men så här då:

Kod: Markera allt

	
	SPI_TransmitByte( (uint8_t) ( adress >> 8); // AA byte 1
eller
	SPI_TransmitByte( (uint8_t) (( adress >> 8) & 0xFF); // AA byte 1
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Re: Jesses följetång om AVR programmering i C...

Inlägg av speakman »

Lite för lite parenteser, men med den senare så har du iallafall typat stenhårt. Den hade jag kört på.

Vad gäller endianess så spelar det ju ingen roll om man bara lagrar i minnet. Men ska man ut på bussar och skyffla mellan olika system så måste ju protokollet du använder eller skriver specificera byte order. Network byte order är ju inte så dumt så behöver man inte komma ihåg vad som använder vad. Standarder ftw. :)
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR programmering i C...

Inlägg av jesse »

Network byte order hehe , om det ändå hade varit så enkelt... jag har en krets som lagrar data i 12-bitars heltal. När jag ska läsa dem så tror du bitarna kommer i ordning 11 till 0 eller 0 till 11 ? Moooaaahahahaha... nejdå inte alls. Det skulle ju vara alldeles för simpelt:

Datan kommer förts i 8 bitar från "värde1" : bit 7 till 0.
Sedan kommer bit 3-0 i "värde2" följt av de högsta fyra bitarna i "värde1": 11 till 8.
nästa byte innehåller till sist de sista bitarna i "värde2": bit 7-0.
Sedan upprepas mönstret med "värde3" bit 7 till 0 osv....
:doh:

Dom har säkert patent på det där. Undrar vad det kallas?
what endian? mixed endian? intelligent endian? :mrgreen:

Well well.... nu till nästa roliga AVR-GCC fundering:

Jag har en massa loopar här och där som brukar se ut ungefär som:

Kod: Markera allt

for ( uint8_t  i=0;  i<antal;  i++ ) ...
Detta blir i kompilatorn i slutet av loopen:

Kod: Markera allt

 622:	1f 5f       	subi	r17, 0xFF	; 255
 624:	80 91 01 01 	lds	r24, 0x0101
 628:	18 17       	cp	r17, r24
 62a:	80 f3       	brcs	.-12    
givetvis måste jag testa om jag kan spara in en rad och tjäna 1 clockcykel per varv och en byte i programminnet, så det blev:

Kod: Markera allt

for ( uint8_t  i=antal;  i<255;  i-- ) ...
och, ja, det fungerar:

Kod: Markera allt

 2d0:	81 50       	subi	r24, 0x01
 2d2:	d8 f7       	brcc	.-10 
jag tjänade två bytes per loop - och en av looparna ingick i en inline funktion och sparade över 12 bytes kod bara när jag ändade på ett ställe. Och så gick loopen på 6 cykler istället för 8. :P

Men det är ju lite skumt att räkna ner ett otecknat , otäckent, otäckt...heltal (äsch, vad heter unsigned integer på svenska?) och sedan jämföra om det är mindre än 255.. kompilatorn skulle ju kunna få krupp :| Man kan ju använda signed integer och skriva i<0, men då är problemet:
1) om koden blir lika effektiv? och
2) jag begränsas till 128 varv.

jag kanske börjar bli lite för petig när det gäller att spara tid och minne... snart kanske GCC kraschar :?
SvenW
Inlägg: 1156
Blev medlem: 24 april 2007, 16:23:10
Ort: Göteborg

Re: Jesses följetång om AVR programmering i C...

Inlägg av SvenW »

Premature optimization is the root of all evil -- DonaldKnuth
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR programmering i C...

Inlägg av jesse »

************* NYTT ÄMNE *************
Jag skulle vilja göra en struct som ser ut så här:

Kod: Markera allt

struct dataformat {
      int32_t summa;
      uint16_t antal;
      uint8_t status;
      uint8_t crc;
} data;
sedan vill jag skicka denna byte för byte på SPI bussen, typ:

Kod: Markera allt

for (i = 0 ; i < antalBytesInStruct; i++) {
      SPI_SendByte(data[i]);
}
Men hur adresserar jag enskilda bytes i en struct?
Går det att definiera en pekare för det? Eller går det att mixtra så att man skapar en uint8_t array[8] som ligger på samma adress som structen "data" och därmed kunna läsa enskilda bytes?
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Jesses följetång om AVR programmering i C...

Inlägg av jesse »

Verkar ha hittat lösningen själv, även om jag inte är 100% säker på att den gör exakt det jag vill...

Denna pekare går tydligen att deklarera utan problem, och kan användas i en loop:

Kod: Markera allt

uint8_t *bytepekare = (uint8_t*) & data;
SPI_SendByte( *bytepekare + i);
Den bör ju nu räkna upp byte för byte... *bytepekare blir i allafall en uint8_t...
...om den nu pekar rätt bara ... :roll:
Skriv svar