Hallo zusammen! Ich habe mal eine Frage bzgl. des CodeVision Compilers: Ich habe in meinen bisherigen Programmen die Verwendung von structs immer vermieden, da ich in einer Vorlesung mal gesagt bekommen habe, dass structs im Bereich Mikrocontrollerprogrammierung mit äußerster Vorsicht zu genießen sind. Ich habe mein aktuelles Projekt aber doch auf die Verwendung von Strukturen umgestellt, da ich finde, dass das die Wartung des SourceCodes wesentlich vereinfacht. Ich habe allerdings den Eindruck, dass der CodeVision Compiler Strukturen nicht wirklich zu 100% unterstützt. Ich will das an einem Beispiel verdeutlichen, wie ich mit Strukturen umgehe: void main(void) { struct beispiel test1; struct beispiel* pTest1; } In einer Headerdatei habe ich den Datentyp beispiel folgendermaßen definiert: struct beispiel { unsigned char variable1; unsigned char variable2; }; Die erste Funktion im Hauptprogramm ist dann eine Initialisierungsfunktion, in der ich den Strukturvariablen Defaultwerte zuweise. An diese und an alle weiteren Funktionen übergebe ich jeweils immer nur den Zeiger pTest1, z.B.: void init(pTest1) { pTest1->variable1 = 34; pTest1->variable2 = 56; } Wenn ich mein Projekt mit AVRStudio debugge, steht in den Strukturvariablen teilweise nur Müll drin, obwohl es das nicht sollte. Habt ihr vielleicht ähnliche Erfahrungen mit CodeVision gemacht; oder mache ich mit der Handhabung von Strukturen noch einen Fehler? Vielen Dank schonmal für eure Hilfe! Gruß Thomas
Initalisierst Du denn den Pointer pTest1 auch irgendwo? Wenn Du das nicht tust, dann geht jeder Zugriff darauf in die Hose.
Jawohl und zwar direkt nach der Definition des Zeigers: pTest1 = &test1; Sobald ich den Zeiger an eine Funktion übergebe und in dieser Funktion mit dieser Struktur arbeite, oder auf deren Daten zugreife stimmt nichts mehr.
Zeig mal Dein vollstaendiges (moeglichst kleines) Testprogramm. Die Wahrscheinlichkeit dass der Fehler bei Dir liegt und nicht beim Compiler ist groesser als 99%.
Das ganze Programm kann und darf ich nicht posten (über 20 000 Zeilen Code); aber ich kann es exemplarisch mal aufzeigen: struct timeDate{ BYTE measureStartDate[6]; BYTE measureStopDate[6]; BYTE actualDate[6]; }; void liesUhrzeit(struct timeDate* pZeitstempel) { // Lies Informationen von I2C-RTC pZeitstempel->actualDate[0] = read_info(); pZeitstempel->actualDate[1] = read_info(); pZeitstempel->actualDate[2] = read_info(); pZeitstempel->actualDate[3] = read_info(); pZeitstempel->actualDate[4] = read_info(); pZeitstempel->actualDate[5] = read_info(); } //Globale Variablen: struct timeDate zeitstempel; // Hauptprogramm: void main() { liesUhrzeit(&zeitstempel); } Ich hoffe mal, dass dieser prinzipielle Ausschnitt die Problemstellung verdeutlicht. Was ich mir noch überlegt habe: Ist es vielleicht besser (oder sogar notwendig) die Struktur in der Funktion liesUhrzeit wieder ans Hauptprogramm zurückzugeben, also in etwa so: struct timeDate* liesUhrzeit(struct timeDate* pZeitstempel) { // Lies Informationen von I2C-RTC pZeitstempel->actualDate[0] = read_info(); pZeitstempel->actualDate[1] = read_info(); pZeitstempel->actualDate[2] = read_info(); pZeitstempel->actualDate[3] = read_info(); pZeitstempel->actualDate[4] = read_info(); pZeitstempel->actualDate[5] = read_info(); return pZeitstempel; } Sorry für das lange Posting ;-)
also das mit dem zurückgeben brauchst du eigentlich nicht, das wird nur bei einigen funktioneen so gemacht, weil man die dann schachteln kann: gibUhrzeitAus(liesUhrzeit(&zeit)); ich werde mal meine CV version suchen, mal sehen woran es leigt.
Das Codefragment sieht in Ordnung aus. Die Rückgabe des Pointer in liesUhrzeit ist unnötig, da eben nur der Pointer an die Funktion übergeben wird und keine Kopie der Struktur; das ist auch gut so ("call-by-reference"). Würde die Struktur als Kopie ("call-by-value") an die Funktion übergeben, dann würde sie dafür auf den Stack gelegt, der entsprechend groß dimensioniert sein müsste. Und sie müsste nach Aufruf der Funktion auch wieder zurückkopiert werden, was auch nur Rechenzeit verbraucht. Nein, dein Beispiel hier ist soweit korrekt. Da wird Dir irgendetwas anderes Deine Strukturen zerstören.
kann es sein, dass du an den stack-grenzen gelangst? beobachte mal den SP, wenn du an die stelle kommst, an der es nicht mehr geht.
Kann es sein das der Compiler Zeiger vom Typ "far" und "near" unterstuetzt? Olaf
nein macht der nicht, ich tippe stark darauf, dass da was mit der read_info nicht stimmt. also folgendes geht (mega16 mit standard-einstellungen): <pre> struct st { int a; short b; }; struct st test; void foo(struct st* p) { p->a = -1; p->b = 10; } void main(void) { foo(&test); } </pre>
@hans dieter SP verhält sich "normal". Überlaufen tut er jedenfalls nicht, dann müsste er ja in die Nähe des Wertes 0xFFFF kommen und an den Stellen, an denen es nicht mehr geht, hat er den Wert 0x0EC3. CodeVision meldet das meines Wissens nach auch, wenn der Data Stack zu klein ist. @Olaf Diese beiden Begriffe habe ich im Kontext von CodeVision noch nie gehört. Ich weiß, dass es zu Problemen kommen kann, wenn ich Variablen im Flash ablege und mithilfe eines Zeigers, der im SRAM liegt darauf zugreifen will; aber solche Definitionen treten bei mir nirgendwo auf. Es ist z.B. auch merkwürdig, dass AVRStudio den Strukturdatentyp nicht richtig erkennt. In meinem obigen Beispiel habe ich ja einen Datentyp struct timeDate. Will ich mir die Struktur zeitstempel in AVRStudio anschauen ist sie auf einmal vom Typ struct file und natürlich stimmen die darin enthaltenen Elemente auch nicht. Das muss aber ein Fehler bei AVRStudio sein (würde ich zumindest mal vermuten). Mal generell eine Frage: Könnt ihr mir vielleicht ein paar Tipps geben, die es bei der Verwendung von Strukturen zu beachten gilt?
Kann es sein, das die structur in verschiedenen modulen deklariert und implementiert ist, dann kann es ggf am aligment liegen wenn das in verschiedenen modulen unterschiedlich definiert ist? aligment -> ausrichtung an Grenzen kann z.B. dann beim siezof auf unterschiedliche Ergebnisse kommen. Nur so eine Spekulation von mir...
Der Datentyp der Struktur ist in einem Headerfile deklariert. Diese Headerdatei wird in meinen verschiedenen C-Files eingefügt. In dieser Datei habe ich über die Präprozessoranweisung: #ifndef DEFINITION_H #define DEFINITION_H struct timeDate{ ... } #endif
Das mit near und far kenne ich vom R8C/M16C, deshalb die Frage. Hast du nur deinen Struct im header-File oder auch die Variablendeklaration selber? Wenn du die naemlich in jedem C-Source neu deklarierst dann hast du verschiedene Variablen wenn du sie nicht als in allen Files bis auf eins als extern deklarierst. Ich mache das immer so: -------------------------- #ifdef MAIN #define EXT #else #define EXT extern #endif typedef struct CIDSP { unsigned char MID; /* 8 Bit */ unsigned short OID; /* 16 Bit */ unsigned char PNM[6]; /* 48 Bit */ unsigned char PRV; /* 8 Bit */ unsigned long PSN; /* 32 Bit */ unsigned char MDT; /* 8 Bit */ unsigned char CRC; /* 7 Bit */ } CIDS; EXT CIDS CID; ----------------- Und nur im Hauptprogramm gibt es dann ein: #define MAIN Olaf
Hallo zusammen! Ich habe die Lösung des Problems gefunden. Rufus hatte mit seiner ersten Vermutung gar nicht so unrecht. Die Beispielstruktur, die ich oben aufgezeigt habe ist in Wahrheit doch etwas komplexer aufgebaut. Es handelt sich dabei um eine Status-struct, in der alle möglichen Information zu Messwerten gespeichert werden, u.a. auch Datum/Uhrzeit, Seriennummer usw. Ich habe also zwei Strukturen definiert: struct timeDate{ ... }; struct serialNumber{ ... }; Und nun die "Oberstruktur": struct status{ unsigned char number; struct serialNumber* serial; struct timeDate* datestamp; } Und genau hier liegt der Fehler. Ich habe nämlich nur eine Variable vom Typ status instanziiert, nicht jedoch die beiden Strukturen number und datestamp. Dies waren also Zeiger die ins Leere zeigten. Statt der Zeigerdeklarierung habe ich jetzt einfach geschrieben: struct status{ unsigned char number; struct serialNumber serial; struct timeDate datestamp; } Vielen Dank nochmal für eure Hilfestellungen ! Gruß Thomas
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.