Sida 1 av 3
Användning av struct
Postat: 28 mars 2007, 14:16:54
av ankan
Definierar en struct enligt följande:
Kod: Markera allt
typedef struct {
byte SenderID[8];
byte ReciverID[8];
byte Datatype;
byte Data[16];
byte Length;
} RF_Data_Struct;
RF_Data_Struct RX_Data;
Sedan tilldelar jag den värden med denna interrupt varje gång det finns datat på RX-porten.
Kod: Markera allt
if (PIR1.RCIF) {
TMR0=0;
inner_state=RECIVING;
if (!RX_Data.Length) {
OPTION_REG = 0x07;
INTCON.TMR0IF=0;
INTCON.TMR0IE=1;
}
if (RX_Data.Length<9)
RX_Data.SenderID[RX_Data.Length]=Usart_Read();
else {
if (RX_Data.Length>8 && RX_Data.Length<17)
RX_Data.ReciverID[RX_Data.Length]=Usart_Read();
else {
if (RX_Data.Length==17)
RX_Data.Datatype=Usart_Read();
else {
if (RX_Data.Length>17 && RX_Data.Length<26)
RX_Data.Data[RX_Data.Length]=Usart_Read();
}
}
}
RX_Data.Length++;
}
När jag sedan ska skriva ut innehållet så stämmer byten i RX_Data.SenderID men inte i RX_Data.ReciverID som hamnar i nästa 8 byte där datat ska finnas.
Provat att lägga allt i en array i stället och då kom all data på rätt plats så det måste vara uppdelningen i interruptet eller något med upplägget av structen.
Några tips?
Postat: 28 mars 2007, 14:31:50
av Icecap
Kod: Markera allt
typedef struct
{
byte SenderID[8];
byte ReciverID[8];
byte Datatype;
byte Data[16];
byte Length;
} T_RF_Data_Struct;
union
{
T_RF_Data_Struct Data;
byte Buffer[1];
} Rx_Data;
if(PIR1.RCIF)
{
TMR0=0;
inner_state = RECIVING;
if(!RX_Data.Data.Length)
{
OPTION_REG = 0x07;
INTCON.TMR0IF=0;
INTCON.TMR0IE=1;
}
if(Rx_Data.Data.Length < (sizeof(T_RF_Data_Struct) - sizeof(Rx_Data.Data.Length))
{
Rx_Data.Buffer[RX_Data.Length] = Usart_Read();
RX_Data.Length++;
}
}
På detta sätt fylls data in i strukturen ganska som de ska, sedan kan du komma åt dom såhär:
Rx_Data.Data.SenderID[]
Rx_Data.Data.RecieverID[]
osv....
Postat: 28 mars 2007, 14:38:52
av ankan
Vad är det som är felet med att använda en struct som jag hade gjort?
Vad är det man gör när man kör union?
Ser ut som att man lossas om att structen är en array när man stoppar in datat och sedan när man ska läsa ut data så har varje del fått sitt eget namn skulle man kunna säga.
Tar "structen/arrayen" RX_Data någon mer plats och hur mycket i så fall när man gör så där?
Postat: 28 mars 2007, 14:46:15
av Icecap
Vad du gör fel är att du indexerar 0-7 i SenderID och det är helt OK.
Därefter indexerar du 8-16 i RecieverID och det är ju helt fel eller hur? Du måste ju dra av storleken av SenderID i indexeringen och det är samma fel som finns genomgående.
'union' anger att de 2 variabler ligger "över varandra", alltså är Buffer[0-7] den samma adress som SenderID[0-7], Buffer[8-15] det samma som RecieverID[0-7] osv.
Edit: Förtydligande:
Med 'union' anger man att alla grundelementen börjar på samma adress. Om man skrivar:
Kod: Markera allt
typedef unsigned char byte;
typedef unsigned int word;
typedef unsigned long dword;
union
{
byte[1] Byte;
word[1] Word;
dword Long;
} The_One;
då kommer den största variablen att bestämma den totala storleken på 'The_One' och de övriga variabler kan sedan indexeras inom detta område och plocka ut/ändra bytes eller words efter önska. Kan vara extremt praktisk om man behöver att flippa bitar, kolla specialgrejer eller spara värden som t.ex. bytes när det i själva verket är en float eller liknande.
Postat: 28 mars 2007, 15:00:57
av ankan
Då tar jag alltså upp dubbelt så mycket minne, eller?
Postat: 28 mars 2007, 15:18:01
av Millox
Nope. Den upptar bara så mycket plats som det största elementet. Du kan se det som att man kan titta på en variabel bit för bit. För vanliga datorer:
union {
int integer;
char[4] character;
} un;
Där kan du tilldela enkelt unionen genom att använda un.integer = 1234; men du kan också sätta varje individuell char genom un.character[x] = 255;
När du läser tillbaka återspeglas värdet i den andra variabeln. Mycket praktiskt ibland.
Dock har du gjort lite bus i din kod ändå, som jag dock inte har nån susning om om det funkar för just den kompilatorn, men i ansi-C kommer det bli dål.
Nämligen den här raden:
RX_Data.SenderID[RX_Data.Length]=Usart_Read();
Problemet är att du bara kan tilldela grundläggande variabler, dvs upp till din registerstorlek (osäker om det funkar med 16 bitar, eller bara

. Kompilatorn kanske fixar dehär felen, men man kan inte vara säker på att det funkar överallt och om man går vidare och kodar för vanliga datorer så kommer man absolut att stöta på patrull. Gör såhär istället:
Usart_Read(buf); // Om det är du som gjort funktionen, ändra till dethär
bcopy(RX_Data.SenderID,buf,sizeof(RX_Data.SenderID);
Med reservation för att det kanske funkar på specialkompliatorer.
Postat: 28 mars 2007, 15:19:55
av Icecap
???? Har du inte förstått något av vad jag skrev?
OK, jag ger ett annan exempel:
Kod: Markera allt
typedef struct
{
byte SenderID[8];
byte ReciverID[8];
byte Datatype;
byte Data[16];
byte Length;
} T_RF_Data_Struct; // Totalt 34 bytes
union
{
T_RF_Data_Struct Data;
byte Buffer[34];
} Alla_Bytes_I_Samma_Klump;
Nu är det 2 stycken minnesarea som är definierat som
1: Alla_Bytes_I_Samma_Klump.Data; (som är en T_RF_Data_Struct på 34 bytes)
2: Alla_Bytes_I_Samma_Klump.Buffer[34];
Dessa två minnesarea BÖRJAR PÅ SAMMA ADRESS och är därför med samma innehåll och FYLLER SOM DEN STÖRSTA av de två.
Alltså är minnesåtgången den samma, det är ju samma bytes det gäller.
Du kan även göra en fuling och enbart indexera i SenderID, resultatet blir det samma då den variabel ligger först i blocken och blocken per definition är en sammanhängande minnesblock. Detta betyder att SenderID[8] är samma byte som RecieverID[0] osv.
Postat: 28 mars 2007, 15:28:45
av ankan
Det där var bra förklarat. Det var just det där om att det är samma minnesarea som man definierar med två olika "namn". Den ena accessas som en array och den andra som en struct. Antar att ordningen i uppbyggnaden av structen är väldigt viktig.
Tack för hjälpen!
Postat: 28 mars 2007, 16:07:39
av Icecap
Jag hade själv "en del förståelsesproblem" med union i början men när man sedan har fattat grejen kan det vara en stor hjälp.
Det finns en del sätt att fuska på men dom sparar vi till senare.
Såklart är uppbyggnade av struct'en viktig, om man definierar den som man använder den, byte för byte blir livet mycket lättare.
Jag har en del projekt som "pratar med varandra" via serieport (PC<->enhet) och då gör jag en gemensam .H-fil där jag har alla kommunikationsdefinitioner i inklusive typedef's som anger kommunikationsblock.
Ändrar jag då ett ställe är det bara att kompilera om alla ingående delar i projekten och då fungerar det!
Jag har som definition att med datorer ska en viss variabel/definition enbart anges 1 gg och allt annat ska referera till detta ställe.
Postat: 28 mars 2007, 17:19:25
av JJ
Och glöm inte 'volatile' på det som accessas från både interrupt och main! (Eller från flera interrupt.)
Postat: 29 mars 2007, 17:42:46
av $tiff
Jag tackar för denna ingående förklaring, Icecap (och Millox). Även om jag är passiv deltagare i diskussionen så blev begreppet Union mycket klarare nu

Postat: 29 mars 2007, 17:43:56
av Icecap
Bra! Man ska lära sig lite varje dag, om man inte känner för det är det lika bra att reservera en ett-rummare utan brevinkast!
Postat: 29 mars 2007, 18:09:45
av sodjan
> ...så blev begreppet Union mycket klarare nu...
He he, ni har kört för lite Fortran och Cobol !!

Postat: 27 december 2008, 15:25:42
av thepirateboy
Bra exempel! Kan man initiera vissa element i structen i samband med att man deklarerar den och hur gör man isåfall?
Postat: 27 december 2008, 16:49:15
av Icecap
Det beror faktisk på kompilern.
Generellt är svaret "nej" men vissa kompilers är så att de kan göra det tack vara en kod som körs innan main.
Jag har löst det på det sätt att jag deklarerar en typedef med den önskade struktur, här kallat T_TEST:
typedef struct
{
char Char_1;
char Char_2;
int Int_1;
} T_TEST;
Först deklarerar man dom i RAM:
T_TEST Testvar;
Sedan är det standardinställningen:
const T_TEST Default = {0, 0, 2};
Sedan kopierar man från Default till Testvar på lämpligt sätt, memcpy(&Testvar, &Default, sizeof(Testvar)); kan vara ett av dessa.
Medger kompilern att man kan definiera och initiera RAM-delen utförs dessa steg automatisk innan main aktiveras men jag gillar att ha koll på vad som händer så jag föredrar att göra det själv.