Tripp:
Grejen är att man kan göra "allt" oberoende på programmeringsspråk!
En µC blir inte annorlunda av att kompilern får källkod i form av BASIC eller C eller Pascal eller...
Skillnaden är strukturen i programmet och sättet att behandla variabler på.
Ett exempel:
Har ett antal projekt med olika parameter som styr en massa saker. Dessa variabler är av olika storleker (bytes/words/long osv.) och de sparas i EEPROM. Man kan ändra dessa variabler på olika sätt men senaste inställningen ska sparas för varje ändring.
Så långt är allt ganska normalt.
I C deklarerar jag:
Kod: Markera allt
typedef struct
{
WORD Club_Number;
BYTE Grinds_Max;
BYTE Carrier_Target;
BYTE Grinder_Target;
BYTE Rampspeed_Carrier_Offset;
BYTE Rampspeed_Carrier_Step;
BYTE Rampspeed_Grinder_Offset;
BYTE Rampspeed_Grinder_Step;
} T_CONFIG;
Detta deklarerar en variabel-typ (som heter "T_CONFIG") som består av samlingen av alla dessa variabler. detta är ett ganska begränsat exempel, jag har projekt som har avsevärd större och mer komplicerat.
För att faktisk deklarera ett kopia i minnet gör jag:
T_CONFIG Config;
Nu har jag reserverat plats i minnet till Config, för att "komma åt" dessa variabler skriver jag t.ex. X = Config.Rampspeed_Carrier_Offset.
OK, detta är bara ett avancerat att göra det samma som man kan i BASIC...
Men jag ska ju läsa från EEPROM när jag slår på skiten:
// EEPROM I/F
#define EE_SCK p6_4
#define EE_SCK_DD pd6_4
#define EE_SI p6_5
#define EE_SI_DD pd6_5
#define EE_SO p3_0
#define EE_SO_DD pd3_0
#define EE_NCS p3_1
#define EE_NCS_DD pd3_1
#include "\SofTune\Works\25lc160.h" // That's it, now it's possible to use the EEPROM
Sådär, nu har jag tagit min gamla EEPROM-rutin från Fujitsuprocessorn in i mitt Renesas M16C-projekt HELT UTAN ÄNDRING! (portabilitet!)
Men det gör knappast så mycket, jag ska ju fortfarande hämta data från EEPROM till Config-blocket eller hur? OK, jag har tagit en genväg:
#define Save_Config() (Write_EE_Buffer(Config_Start , (BYTE*)&Config , sizeof(T_CONFIG)))
#define Read_Config() (Read_EE_Buffer (Config_Start , (BYTE*)&Config , sizeof(T_CONFIG)))
När jag alltså skriver "Read_Config();" läsas de data som finns i EEPROM in i Config-blocket, ändrar jag ett värde och vill spara det är det bara att lägga in kommandot: "Save_Config();" på lämpligt ställe i programmet.
Men låt oss dissikrera det lite, själva funktionen utförs av den kommando jag har gjort i den fil som inkluderas:
Write_EE_Buffer(Config_Start, (BYTE*)&Config, sizeof(T_CONFIG));
Lite förklaring:
Config_Start har ett värde som anger på vilken startadress i EEPROM'en dessa värden har lagrats på, i detta fall 0h.
(BYTE*)&Config... den är lite tuffare men det är ett sätt att berätta att jag vill ha Config's adress i RAM men att jag vill använda den som en pekare till bytes. Det är så för att den rutin jag har gjort förväntar sig en adress som pekar på byte(s).
Sedan är det "sizeof(T_CONFIG)" som ger ett värde som anger hur många bytes en T_CONFIG-variabel tar i minnet.
Ändrar jag Config vid att ändra storleker på variabler (8 -> 16 bits t.ex.) kommer detta värde att "följa med" då kompilern "tillverkar" det när det kompileras.
Ett annat exempel:
Seriell överföring, protokoll. En datablock har tagits emot men VAD ska den göra? Jo, det finns en byte som anger detta! Här kallar vi den "Rx.Command" (jepp, du har gissat rätt, det är en 'struct')
Kod: Markera allt
enum {Command_Ping, Command_Set_Speed, Command_Read_Speed};
switch(Rx.Command)
{
case Command_Ping:
// Gör vad som ska göras här
break;
case Command_Set_Speed:
// Gör vad som ska göras här
break;
case Command_Read_Speed:
// Gör vad som ska göras här
break;
default: // Behöver inte vara med!
// Allt som inte passar in på några av de andra
}
Förklaring:
enum ger del tags som står i klammorna fortlöpande värden, första värde får 0, nästa får 1 osv. Man kan dock ange det värde som tag'en ska ha och sedan kör den vidare därifrån om man vill. Man kan alltså få 0, 1, 5, 7, 100, 101, 102, 103 osv om man vill.
Sedan switch.... kan bäst jämföras vid:
if(Rx.Command = Command_Ping)
// Gör vad som ska göras här
else if(Rx.Command = Command_Set_Speed)
// Gör vad som ska göras här
else if(Rx.Command = Command_Read_Speed)
// Gör vad som ska göras här
else
// Allt som inte passar in på några av de andra
endif
Visst, i BASIC har man "on X goto" (ibland) men vad om man bara vill använda kanske 3 av 100 värden? Då ska man i BASIC skriva upp alla 100 fast bara 3 av dom pekar på en egentlig rutin, resten pekar på "stega vidare".
Om jag då skulle få för mig att ändra enum:
enum {Command_Ping = 'A', Command_Set_Speed, Command_Read_Speed};
Vad händer då?
Ingenting, allt fungerar precis likadan efter kompilering fastän värden är ändrade!
Självklart definierar man kommunikationsvariabler i en egen fil, denna inkluderar man sedan i sitt PC-program (C++) och därmed kan kommunikationen inte gå fel om man lägger till eller ändrar värden, det är bara att kompilera igen i "båda ändar" och saken är biff och tro mig, jag har testat detta MYCKET.