Problem med utdatat från funktion

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
ankan
Inlägg: 1091
Blev medlem: 12 november 2004, 01:50:35

Problem med utdatat från funktion

Inlägg 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?
ankan
Inlägg: 1091
Blev medlem: 12 november 2004, 01:50:35

Inlägg av ankan »

Det är de två första byten som skiljer sig åt.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg 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
  }
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg 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.
Millox
Inlägg: 559
Blev medlem: 10 december 2005, 22:10:43
Ort: Östhammar

Inlägg 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.
ankan
Inlägg: 1091
Blev medlem: 12 november 2004, 01:50:35

Inlägg 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?
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg 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.
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg 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.
ankan
Inlägg: 1091
Blev medlem: 12 november 2004, 01:50:35

Inlägg 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]);
    
}
ankan
Inlägg: 1091
Blev medlem: 12 november 2004, 01:50:35

Inlägg av ankan »

Jag kan inte heller göra så är:

Kod: Markera allt

ROM_id=ow_get_id();
... för då får jag Assigning to non-lvalue []

Kod: Markera allt

strcpy(ROM_id,ow_get_id());
... 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.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg 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[]
    ....
    }
  }
ankan
Inlägg: 1091
Blev medlem: 12 november 2004, 01:50:35

Inlägg 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?
Skriv svar