Jesses följetång om AVR programmering i C...
Re: lite undringar om AVR progrannering i C
Hur sätter kompilatorn igentligen in koden om du gör två separata asm anrop på det där sättet ?
Om man har ett stycke inline-asm så ska det normalt inte påverkas alls av eventuell optimering av C-koden.
Och det "normala" är väl att man sätter in en hel sekvens asm utan separata anrop på det där sättet...
(Sen är det en helt annan sak att jag inte fattar det där med "två gånger", men det spelar mindre roll...)
Om man har ett stycke inline-asm så ska det normalt inte påverkas alls av eventuell optimering av C-koden.
Och det "normala" är väl att man sätter in en hel sekvens asm utan separata anrop på det där sättet...
(Sen är det en helt annan sak att jag inte fattar det där med "två gånger", men det spelar mindre roll...)
Re: lite undringar om AVR progrannering i C
Fundera över om inte någon variabel måste vara volatile.
Exempel:
v1 och v2 är inte volatile.
Den här koden kan optimeras till att v1 laddas till ett register innan loopen, och sedan görs testet hela tiden mot registret. Men om v1 ändras i någon annan funktion/interrupt så påverkar det ju inte värdet på registret.
Exempel:
Kod: Markera allt
while(v1 != v2)
{
...
kod som inte påverkar v1
...
}
Den här koden kan optimeras till att v1 laddas till ett register innan loopen, och sedan görs testet hela tiden mot registret. Men om v1 ändras i någon annan funktion/interrupt så påverkar det ju inte värdet på registret.
Re: lite undringar om AVR progrannering i C
Jo, så tänkte jag också men jag lyckades av nån anledning inte få den att fatta mer än en instruktion per anrop ... orkade inte utforska vidare just då utan löste det med två separata, viket blev OK; de sattes direkt efter varandra i koden. Det var alltså inte de raderna som inte fungerade utan dessa rader i C:Sodjan skrev:Och det "normala" är väl att man sätter in en hel sekvens asm utan separata anrop på det där sättet...
MCUCR = 0x80;
MCUCR = 0x80;
(två gånger ska det skrivas i MCUCR. Det togs kanske ur sitt sammanhang när jag bara klippte ut en bit av koden.)
bearing: aha, ja, så kan det vara... jag sätter bl.a. en flagga i en interruptrutin när det kommer in ett tecken på UART. Denna flagga läses sedan av i main()... ska testa att göra den till volatile och samtidigt kolla att jag inte har fler sådana fällor. (har inte kompilatorn här just nu så det får bli senare). Tack för tipset! (börjar förstå mer och mer nu varför volatile används ibland)


EDIT: en rättelse: ovanstående instruktioner handlar om att avaktivera jtag-interfacet, inte CPU-frekvensen som jag skrev innan. Men samma problem uppstår när jag ska ändra "clock-prescalern"...
pekare till arrayer i funktioner
pekare till arrayer i funktioner
Nu har jag fått det att fungera - utskrift från EEPROM till uart, men jag fattar ändå inte exakt vad jag gör! Hur man skriver för att skicka pekare är fortfarande lite av en chansning.
Koden:
Den här raden fungerar oavsett om jag skriver string med eller utan stjärna:
tecken = eeprom_read_byte(*string+i);
tecken = eeprom_read_byte(string+i);
Jag hade först med stjärnan, men fick en varning och testade att ta bort den. Jag trodde det skulle vara en stjärna där eftersom string är en pekare, men det var visst fel tänkt? Varningen jag fick var:
warning: passing argument 1 of 'eeprom_read_byte' makes pointer from integer without a cast
så jag misstänker att det är fel, även om det råkar fungera i just det här fallet ändå?
hmmm... (tänker efter...)
skriver jag bara string så får jag minnesadressen?
skriver jag *string så får jag värdet i SRAM på den adress pekaren string pekar på?
Så *string blir tokigt fel här, antar jag för jag vill bara skicka en adress som argument, inte ett datavärde.
Nu har jag fått det att fungera - utskrift från EEPROM till uart, men jag fattar ändå inte exakt vad jag gör! Hur man skriver för att skicka pekare är fortfarande lite av en chansning.
Koden:
Kod: Markera allt
uint8_t EEMEM welcome[]="Välkommen!"; // definierar sträng i EEPROM som slutar med '0'
// "welcome" är en pekare till första positionen
// strängen består av uint_8t istället för char eftersom ReadEEprom tar [i]unsigned[/i] char som argunent.
// skriv ut texten string[] EEPROM
// sista tecknet måste vara 0 ( \000)
void uaprint_EE(const uint8_t * string) {
/* argumentet string är en pekare till en adress innehållande
* uint8_t som inte får skrivas över.
* skriver man till *string så skrivar man på en plats i SRAM = fel! */
uint8_t i,tecken;
for (i=0;i<128;i++) {
tecken = eeprom_read_byte(string+i); // funktion i <avr/eeprom.h>
if (tecken==0) break;
uartSend(tecken);
}
}
int main (void){
uaprint_EE(welcome); // welcome är en pekare...
}
tecken = eeprom_read_byte(*string+i);
tecken = eeprom_read_byte(string+i);
Jag hade först med stjärnan, men fick en varning och testade att ta bort den. Jag trodde det skulle vara en stjärna där eftersom string är en pekare, men det var visst fel tänkt? Varningen jag fick var:
warning: passing argument 1 of 'eeprom_read_byte' makes pointer from integer without a cast
så jag misstänker att det är fel, även om det råkar fungera i just det här fallet ändå?
hmmm... (tänker efter...)
skriver jag bara string så får jag minnesadressen?
skriver jag *string så får jag värdet i SRAM på den adress pekaren string pekar på?
Så *string blir tokigt fel här, antar jag för jag vill bara skicka en adress som argument, inte ett datavärde.

Re: lite undringar om AVR progrannering i C
En "pekare" är ju i princip någonting som innehåller en adress till något annat.
I ditt fall är "welcome" igentligen inte en pekare, utan det är adressen till
själva variablen direkt, så att säga. Annars hade "welcome" inte pekat direkt
till texten, utan till en adress där det i sin tur låg en adress till texten...
Så att "welcome" är en pekare till första positionen" stämmer igentligen inte riktigt...
I ditt fall är "welcome" igentligen inte en pekare, utan det är adressen till
själva variablen direkt, så att säga. Annars hade "welcome" inte pekat direkt
till texten, utan till en adress där det i sin tur låg en adress till texten...
Så att "welcome" är en pekare till första positionen" stämmer igentligen inte riktigt...
Re: lite undringar om AVR progrannering i C
Jo, det blir en pekare, men det här är en av de punkter där språket med rätta har kriticerats för att vara ologiskt.
I språket 'd', efterföljaren till 'c', försöker man komma till rätta med sånt här, har jag för mig. Återstår att c om d blir populärt
I språket 'd', efterföljaren till 'c', försöker man komma till rätta med sånt här, har jag för mig. Återstår att c om d blir populärt

Re: lite undringar om AVR progrannering i C
Nja...
Om man i C deklarerar en variabel t.ex som :
int varA;
Så är ju varA inte en "pekare". Dock så innehåller naturligstvis symbolen
"varA" i alla fall en adress som "pekar" till platsen där det lagras en int.
Alltså varA => int. Men det är inte en pakare på det sätt som C definierar det.
Men om man istället säger :
int *VarA;
så är varA en pekare till en int. D.v.s att varA är en symbol i kompilatorn som
innehåller en adress som pekar till en plats i minnet där det ligger en adress till en int.
Alltså varA => adress => int.
I fallet med koden i tråden så har symbolen "welcom" redan adressen direkt till
den aktuella variablen (strängen), och alltså är "welcome" *INTE* en pekare.
Med din logik så skulle alla symboler som innehåller en adress till en variabel vara
"pekare", men så är det ju inte. Bara de symboler som innehåller en adress till
en adress till något är "pekare".
Om man i C deklarerar en variabel t.ex som :
int varA;
Så är ju varA inte en "pekare". Dock så innehåller naturligstvis symbolen
"varA" i alla fall en adress som "pekar" till platsen där det lagras en int.
Alltså varA => int. Men det är inte en pakare på det sätt som C definierar det.
Men om man istället säger :
int *VarA;
så är varA en pekare till en int. D.v.s att varA är en symbol i kompilatorn som
innehåller en adress som pekar till en plats i minnet där det ligger en adress till en int.
Alltså varA => adress => int.
I fallet med koden i tråden så har symbolen "welcom" redan adressen direkt till
den aktuella variablen (strängen), och alltså är "welcome" *INTE* en pekare.
Med din logik så skulle alla symboler som innehåller en adress till en variabel vara
"pekare", men så är det ju inte. Bara de symboler som innehåller en adress till
en adress till något är "pekare".
Re: lite undringar om AVR progrannering i C
nu är ju welcome[] en array, och så här står det i boken "Snygg grundläggande C++ med Dev-C++" av Fredrik Vallbo:
det betyder att
tecken = welcome[ i ];
är detsamma som
tecken = *(welcome + i);
jag skickar ju pekaren welcome som parameter i funktionen uaprint_EE, där den kallas string. Sedan läser jag tecken för tecken med
tecken = eeprom_read_byte(string+i);
så visst är welcome en pekare.
Men det gäller bara arrayer förstås, inte andra variabler.
--------spekulation:-------
(Kanske jag hade kunnat skriva tecken = eeprom_read_byte(string[ i ]); och det hade betytt samma sak?)
(EDIT: Nej, det går inte... funktionen eeprom_read_byte ska ju inte ha själva tecknet som argument (vilket hade lästs ur en odefinierad plats i SRAM) utan adressen så att den kan läsa eepromet... så det var fel,fel,fel!)
(där "variablenamn" är en pekare och "index" är en integer).sidan 67: skrev:Om vi deklarerar en array med
datatyp variabelnamn[antal fack];
så kommer den dels att reservera utrymme ... men kommer också att deklarera en pekare ungefär som om vi hade skrivit:
datatyp* variabelnamn;
och tilldela denna pekare minesadressen där första elementet ligger lagrat.
...
Faktum är att skrivsättet
variabelnamn [index]
bara är ett förkortat skrivsätt för
* (variabelnamn+index)
det betyder att
tecken = welcome[ i ];
är detsamma som
tecken = *(welcome + i);
jag skickar ju pekaren welcome som parameter i funktionen uaprint_EE, där den kallas string. Sedan läser jag tecken för tecken med
tecken = eeprom_read_byte(string+i);
så visst är welcome en pekare.
Men det gäller bara arrayer förstås, inte andra variabler.
--------spekulation:-------
(Kanske jag hade kunnat skriva tecken = eeprom_read_byte(string[ i ]); och det hade betytt samma sak?)
(EDIT: Nej, det går inte... funktionen eeprom_read_byte ska ju inte ha själva tecknet som argument (vilket hade lästs ur en odefinierad plats i SRAM) utan adressen så att den kan läsa eepromet... så det var fel,fel,fel!)
Re: lite undringar om AVR progrannering i C
Det är precis som jesse citerar ovan, och som sodjan påpekar är det inte logiskt.
eeprom_read_byte() deklareras så här i avr-libc <avr/eeprom.h>:
Det betyder att den skall ha en pekare som argument.
Man kan skriva på olika sätt:
Det är alltid svårt att hålla reda på vad som är pekare och det tar lång tid att träna in.
eeprom_read_byte() deklareras så här i avr-libc <avr/eeprom.h>:
Kod: Markera allt
static __ATTR_PURE__
__inline__ uint8_t eeprom_read_byte (const uint8_t *__p)
Man kan skriva på olika sätt:
Kod: Markera allt
tecken = eeprom_read_byte(string+i);
tecken = eeprom_read_byte(&string[i]);
tecken = eeprom_read_byte(&string[0] + i );
Re: lite undringar om AVR progrannering i C
Problemet är att om man deklarerar en sträng (kan kalla den "String") är den egentligen en array av char och när man anger den som argument gör kompilern om den till en pekare som pekar på första char i array'n.
Om man istället anger String[6] uppfattar kompilern inte det som en pekare till en sträng men som en pekare till en char så det finns en del "oskrivna regler" (som nog är skrivit ner någonstans) som är bra att känna till. Själv sker det att jag vill skriva till ett visst ställe i en sträng och då skriver jag "&String[3]" som mål.
Om man istället anger String[6] uppfattar kompilern inte det som en pekare till en sträng men som en pekare till en char så det finns en del "oskrivna regler" (som nog är skrivit ner någonstans) som är bra att känna till. Själv sker det att jag vill skriva till ett visst ställe i en sträng och då skriver jag "&String[3]" som mål.
Re: lite undringar om AVR progrannering i C
Vill bara säga det att ibland så kanske inte C-koden funkar som den skall bara för att man inte har slagit på kodoptimeringen.
Ett exempel är då man skall skriva till internt EEPROM. Då ska man enabla skrivningen genom att ettställa en bit i ett register och sen inom 4 cykler ska man ettställa en annan bit i samma register.
Om man inte optimerar koden så blir det för mycket instruktioner mellan dessa operationer och då funkar inte skrivning till EEPROMet.

Ett exempel är då man skall skriva till internt EEPROM. Då ska man enabla skrivningen genom att ettställa en bit i ett register och sen inom 4 cykler ska man ettställa en annan bit i samma register.
Om man inte optimerar koden så blir det för mycket instruktioner mellan dessa operationer och då funkar inte skrivning till EEPROMet.

Re: lite undringar om AVR progrannering i C
Och just sådana saker använder man ASM-direktiv till...
Re: lite undringar om AVR progrannering i C
Ja, då slipper man vara beroende av hur effektiv kod kompilatorn genererar.
Eftersom jag inte är så bra på assembler på AVR så kollade jag vad kompilatorn genererade för assemblerkod vid optimering. Sen klippte jag in de assembler raderna i C-koden.
Eftersom jag inte är så bra på assembler på AVR så kollade jag vad kompilatorn genererade för assemblerkod vid optimering. Sen klippte jag in de assembler raderna i C-koden.

Re: lite undringar om AVR progrannering i C
Till vilken nytta?Mr M skrev:Sen klippte jag in de assembler raderna i C-koden.