Sida 1 av 1
Problem med utdatat från funktion
Postat: 20 mars 2007, 17:44:06
av ankan
Vad kan vara fel?
Funktioner
Kod: Markera allt
unsigned short * ow_get_id() {
signed short i;
unsigned short ROM_id[4];
Ow_Reset(OW_PORT,OW_PIN); // RESET
Ow_Write(OW_PORT,OW_PIN,0x33); // READ_ROM
for (i=0;i<=3;i++)
ROM_id[i] = Ow_Read(OW_PORT,OW_PIN); // Spara ROM nummer
return ROM_id;
}
void Usart_Write_Data(unsigned short *text, unsigned short length) {
unsigned short i;
for (i=0;i<length;i++)
Usart_Write(text[i]);
}
Problemet
Kod: Markera allt
strcpy(ROM_id,ow_get_id());
Usart_Write_Data(ROM_id,4); //Skriver ut fel data
Usart_Write(ROM_id[0]); // Samma data fast byte för byte
Usart_Write(ROM_id[1]);
Usart_Write(ROM_id[2]);
Usart_Write(ROM_id[3]);
Usart_Write_Data(ow_get_id(),4); // Skriver ut samma fel datat som ovan
Usart_Write(ow_get_id()[0]); // Skriver ut rätt byte för byte
Usart_Write(ow_get_id()[1]);
Usart_Write(ow_get_id()[2]);
Usart_Write(ow_get_id()[3]);
Varför fungerar det inte?
Postat: 20 mars 2007, 17:56:55
av ankan
Det är de två första byten som skiljer sig åt.
Postat: 20 mars 2007, 19:19:59
av Icecap
När du anger variabler som interna i en funktion kan kompilern återanvända dom till andra funktioner. Flytta alltså deklarationen "unsigned short ROM_id[4];" till det allmäna (globa) deklarationsområde.
Ett alternativ är att ange adressen på variablen som datan ska sparas i:
Kod: Markera allt
void ow_get_id(char * Buffer)
{
Ow_Reset(OW_PORT,OW_PIN); // RESET
Ow_Write(OW_PORT,OW_PIN,0x33); // READ_ROM
for (i=0;i<=3;i++)
*(Buffer + i) = Ow_Read(OW_PORT,OW_PIN); // Spara ROM nummer
}
Postat: 20 mars 2007, 19:48:14
av vfr
Eller för att bara uttrycka det lite annorlunda. Din lokala variabel "i" i funktionen finns helt enkelt inte när du är utanför funktionen. Den är odefinierad. Det är därför fullständigt ogiltigt att returnera en pekare till den ut ur funktionen.
På en större processor, säg PC t.ex, så lagras normalt lokala variabler på stacken. I dessa små mikrokontrollers utan riktig stack så mappas det, precis som Icecap säger, ofta till en fast minnesadress och denna kan delas mellan flera olika lokala variabler i olika funktioner. Eftersom funktionerna inte kan exekvera samtidigt så fungerar detta. Dock blir inte funktionen reentrant.
Postat: 20 mars 2007, 20:35:34
av Millox
du kan även deklarera med
unsigned short *ow_get_id(unsigned short *buf);
och skriva till buf och sen returnera den. Då kan du använda funktionen direkt i ett annat anrop utan att behöva köra den först på en rad och sen nästa på nästa. Men det är bara skillnad i hur man tycker om att skriva syntax. Nån programmatisk skillnad blir det inte.
Postat: 20 mars 2007, 22:59:11
av ankan
Det är alltså sättet jag använder
i som är fel?
Skulle ju kunna lägga den globalt men jag vill gärna kunna återanvända funktionen smidigt utan att behöva lagra globala variabler.
Ska man försöka i största mån försöka dra ner på antalet lokala variabler i funktioner?
Funderar på om man kanske skulle kunna göra så här:
Kod: Markera allt
unsigned short * ow_get_id() {
Ow_Reset(OW_PORT,OW_PIN); // RESET
Ow_Write(OW_PORT,OW_PIN,0x33); // READ_ROM
return Ow_Read(OW_PORT,OW_PIN) & Ow_Read(OW_PORT,OW_PIN) & Ow_Read(OW_PORT,OW_PIN) & Ow_Read(OW_PORT,OW_PIN);
}
.... eller är det en dum idee?
Postat: 21 mars 2007, 08:05:18
av Icecap
Nej! Det är sättet du använder "ROM_id[];" på som är dumt!
"ROM_id[]" upphör existera när programmet lämnar rutinen men jag fick just en idé: deklarera ROM_id[] som static (static unsigned short ROM_id[4]

, då reserveras dess data även när rutinen lämnas.
Postat: 21 mars 2007, 09:23:53
av vfr
Ahh. Det var jag som skrev fel variabelnamn. Det skulle naturligtvis vara "ROM_id" och inte "i" i mitt inlägg.
Det går att lösa med "static" också men jag tycker inte det är en speciellt snygg lösning. Icecaps första förslag är det som jag tycker är mest korrekt. Då blir funktionen dessutom reentrant automatiskt.
Postat: 21 mars 2007, 09:26:54
av ankan
Static hjälper inte.
Jag får följande utdata av
Usart_Write_Data(ow_get_id(),8 )
0x08 0x01 0x64 0x7D 0x00 0x00 0x00 0x1D
... och följande av: Usart_Write(ow_get_id()[0]);
Usart_Write(ow_get_id()[1]);
Usart_Write(ow_get_id()[2]); osv ...
0x28 0xFD 0x64 0x7D 0x00 0x00 0x00 0x1D
Vilket stämmer med vad DS9097U säger.
ow_get_id() ser ut så här:
Kod: Markera allt
unsigned short * ow_get_id() {
signed short i;
static unsigned short id[8]; // Static gör ingen skillnad
Ow_Reset(OW_PORT,OW_PIN); // RESET
Ow_Write(OW_PORT,OW_PIN,0x33); // READ_ROM
for (i=0;i<=7;i++)
id[i] = Ow_Read(OW_PORT,OW_PIN); // Spara ROM nummer
return id;
}
Det som skiljer sättet att skriva ut det hela är ju bara att den ena skickar arrayen till usart_write_data som då ser ut så här:
Kod: Markera allt
void Usart_Write_Data(unsigned short *text, unsigned short length) {
unsigned short i;
for (i=0;i<length;i++)
Usart_Write(text[i]);
}
Postat: 21 mars 2007, 09:59:47
av ankan
Jag kan inte heller göra så är:
... för då får jag
Assigning to non-lvalue []
... fungerar inte heller eftersom några av byten i ID-strängen är 0x00 vilket tolkas som strängslut. Så hur ska man hantera denna sträng?
Provade att spara direkt till den globala variabeln i funktionen men det lirade inte heller.
Förslaget om att skicka pekaren och sedan spara på den andressen fungerade om funktionen låg i samma fil. Funktionenhittades inte av någon anledning annars.
Postat: 21 mars 2007, 12:02:19
av Icecap
Kod: Markera allt
typedef unsigned char byte;
byte Id[8];
void Ow_Get_Id(byte * Buffer)
{
byte i;
Ow_Reset(OW_PORT,OW_PIN); // RESET
Ow_Write(OW_PORT,OW_PIN,0x33); // READ_ROM
for(i = 0;i < 8;i++) *(Buffer + i) = Ow_Read(OW_PORT,OW_PIN); // Spara ROM nummer
}
main
{
while(1)
{
Ow_Get_Id(&Id); // Read the rom-number and save it in Id[]
....
}
}
Postat: 21 mars 2007, 14:05:28
av ankan
Jag verkar äntligen fått snurr på det hela rätt.
lockade ut port och pin så man måste ange det när funktionen anropas. Detta för att 1-wire funktionerna ska kunna användas utan speciell header fil som ska ändras.
Nu kan jag äntligen börja med Timer1 och sleep-funktionen. Måste man ha en extern kristall för att klocka Timer1 i sleep-mode eller kan man köra på den ena interna som ligger på 32khz någonting?