Nabend, tja, jetzt ist es soweit und ich probiere ich mich an meinen ersten ernsthaften C-Projekt. Bis jetzt habe ich immer mit ASM gearbeitet und hatte nie Probleme. Im Code den ich hier Eingefügt habe werden über Portexpander (74HC595 für Out und 74HC165 für IN) 8 Kanäle zu je einem Byte für Eingang und Ausgang realisiert. Die Kanäle werden immer paarweise angesprochen (16Bit In/Out). Die Auswahl der Kanäle erfolgt über einen Hardware Decoder (74HC139) mit der Funktion PE_Select(). Gelesen wird mit PE_In() und geschrieben mit PE_Out(). Ich habe zum Test in main einfach Eingang auf Ausgang kopiert. Wenn ein Bit am Eingang gesetzt wird, wird dieses auch am Ausgang korrekt gesetzt. Aber im benachbarten Kanal wird es auch gesetzt und toggelt dort. (Die Bitnummer ist die gleiche.) Dieses Programm habe ich vorher in ASM realisiert und dort funktioniert alles so wie es soll. Ich habe so eine Ahnung das der Compiler die Variablen etwas am mixen ist? Das ganze läuft auf einen MEGA16 und programmieren tue ich unter AVR Studio mit WinAVR als C Compiler. Wenn jemand eine Ahnung/Idee hat wo mein Problem liegt wäre ich für einen Hinweis echt dankbar! mfg Lars Code ------------------------------------------------------------------------ #include <avr/io.h> #include <stdint.h> #include "eeprom_default.h" #define PE_Demux_A0 PD2 // Ausgang #define PE_Demux_A1 PD3 // Ausgang #define PE_Demux_A2 PD4 // Ausgang #define PE_CLK PD7 // Ausgang #define PE_Enable PD6 // Ausgang #define PE_SData_Out PD5 // Ausgang #define PE_Port PORTD #define PE_SData_In PINB4 // Eingang #define PE_Read_Write PB3 // Ausgang #define PE_Modul_Enable PB1 // Ausgang //Achtung - Signal ist invertiert #define PE_PortB PORTB //###################################################################### ######################### /* Funktionsdeklarationen */ void GPIO_INIT(void); void PE_Select(volatile uint8_t Port); void PE_Out(volatile uint8_t Byte); volatile uint8_t PE_In(void); //###################################################################### ######################### int main(void) { //start main GPIO_INIT(); while(1) { PE_Select(0); PE_Out(PE_In()); PE_Select(1); PE_Out(PE_In()); PE_Select(2); PE_Out(PE_In()); PE_Select(3); PE_Out(PE_In()); } } //end main //###################################################################### ######################### /* Initialisierung */ void GPIO_INIT(void) { // Adress Port für den Adressdemultiplexer konfigurieren. DDRD |= (1 << DDD2 | 1 << DDD3 | 1 << DDD4); // Portexpander Steuerports konfigurieren. DDRD |= (1 << DDD5 | 1 << DDD6 | 1 << DDD7); DDRB |= (1 << DDB1 | 1 << DDB3); PE_PortB |= (1<<PE_Modul_Enable); // IO Modul deaktivieren } //###################################################################### ######################### /* Portexpander Funktionen */ /* Diese Funktion setzt den gewünschten Portexpander. Die Aufrufvariable ist ein uint8_t mit den Bereich von 0-7 (andere Werte werden ignoriert). Pro IO-Modul werden 2 Portexpander Adr. benutzt. IO-Modul 0 = 0 & 1; IO-Modul 1 = 2 & 3; IO-Modul 2 = 4 & 5; IO-Modul 3 = 6 & 7; */ void PE_Select(volatile uint8_t Port) { switch(Port) { case 0: { PE_Port &= ~(1 << PE_Demux_A0 | 1 << PE_Demux_A1 | 1 << PE_Demux_A2); break; } case 1: { PE_Port |= (1 << PE_Demux_A0); PE_Port &= ~( 1 << PE_Demux_A1 | 1 << PE_Demux_A2); break; } case 2: { PE_Port |= (1 << PE_Demux_A1); PE_Port &= ~( 1 << PE_Demux_A0 | 1 << PE_Demux_A2); break; } case 3: { PE_Port |= (1 << PE_Demux_A0 | 1 << PE_Demux_A1); PE_Port &= ~(1 << PE_Demux_A2); break; } case 4: { PE_Port |= (1 << PE_Demux_A2); PE_Port &= ~( 1 << PE_Demux_A0 | 1 << PE_Demux_A1); break; } case 5: { PE_Port |= (1 << PE_Demux_A0 | 1 << PE_Demux_A2); PE_Port &= ~(1 << PE_Demux_A1); break; } case 6: { PE_Port |= (1 << PE_Demux_A1 | 1 << PE_Demux_A2); PE_Port &= ~(1 << PE_Demux_A0); break; } case 7: { PE_Port |= (1 << PE_Demux_A0 | 1 << PE_Demux_A1 | 1 << PE_Demux_A2); break; } } } // PE_Select /* Das Ausgabewort wird mit dem MSB zuerst ausgegeben. */ void PE_Out(volatile uint8_t Byte_Out) { volatile uint8_t i,temp = 0; PE_PortB &= ~(1<<PE_Read_Write); // Schreibmodus aktivieren PE_PortB &= ~(1<<PE_Modul_Enable); // IO Modul aktivieren for (i=0; i<=7; i++) { temp = Byte_Out & 0b10000000; if ( temp==0) PE_Port &= ~(1<< PE_SData_Out); else PE_Port |= (1<<PE_SData_Out); PE_Port |= (1<<PE_CLK); Byte_Out <<= 1; asm volatile ("nop"); PE_Port &= ~(1<<PE_CLK); } PE_Port |= (1<<PE_Enable); // Enable Impuls an PE_Port &= ~(1<< PE_SData_Out); // PE_SData_Out auf 0 setzten asm volatile ("nop"); PE_Port &= ~(1<<PE_Enable); // Enable Impuls aus PE_PortB |= (1<<PE_Modul_Enable); // IO Modul deaktivieren } volatile uint8_t PE_In(void) { volatile uint8_t i,Byte_In = 0; PE_PortB |= (1<<PE_Read_Write); // Lesemodus aktivieren PE_PortB &= ~(1<<PE_Modul_Enable); // IO Modul aktivieren PE_Port |= (1<<PE_Enable); // Enable Impuls an asm volatile ("nop"); PE_Port &= ~(1<<PE_Enable); // Enable Impuls aus for (i=0; i<=6; i++) { if (PINB & (1<<PE_SData_In)) { Byte_In = Byte_In | 0b00000001; } PE_Port |= (1<<PE_CLK); asm volatile ("nop"); PE_Port &= ~(1<<PE_CLK); Byte_In <<= 1; } if (PINB & (1<<PE_SData_In)) { Byte_In = Byte_In | 0b00000001; } PE_PortB |= (1<<PE_Modul_Enable); // IO Modul deaktivieren return Byte_In; }
> Ich habe so eine Ahnung das der Compiler die Variablen etwas > am mixen ist? Von einem kannst du mit 99.9% Sicherheit ausgehen. Es ist kein Compilerfehler, sondern ein Fehler des Prgrammierers. Für die beschriebene Funktionalität ist mir allerdings dein Programm viel zu komplex, sodass ich es nicht im Kopf durchgehen möchte. AVR-Studio hat aber einen guten Simulator (Debugger). Starte dein Programm unter Simulatorkontrolle und steppe es mal durch, dann siehst du wie die Ausgaben zustande kommen. (Genau das Gleiche müsste ich auch tun, um dir weiter helfen zu können. Nur hab ich den Nachteil, dass ich nicht in deinem Projekt drinnen bin und mich erst mal orientieren muss) Du hast viel zu viel Code vor dem ersten Testen geschrieben. Fang kleiner an, teste es, debugge es und mache es fehlerfrei und erst dann wird die nächste Funktionalität ergänzt. So weiss man immer in welchen 10 Code Zeilen (nämlich den zuletzt hinzugefügten) ein Problem steckt und muss nicht eine größere Menge Code analysieren um Probleme zu entdecken.
Tja, der krux ist ja, das die Funktionen einzeln funktionieren. Ich habe ja an der Hardware direkt geschrieben und getestet. Die PE_Out() Funktion funktioniert einwandfrei, wenn ich Ihr statische Werte übergebe oder Werte aus einer anderen Variable. Diese vorher beschriebenen Symptome treten sporadisch auf sobald die PE_In() Funktion ins Spiel kommt. Der Umfang / Leserlichkeit des Codes kommt daher das das ganze nur die zusammengestückelte Runpfprogrammierung ist. Am Anfang habe ich die PE_Out() Funktion geschrieben und getestet -> einwandfrei. Nur hatte ich anstatt der for noch eine while Schleife. Dann habe ich die PE_Select() Funktion zusammen gesetzt. Hardwaremäßig hat diese das auch getan was Sie sollte. Nur hat je nach übergeben Wert (0 bis 7) dieses Einfluß auf die Schleifendurchläufe in der PE_Out(). Zu sehen war das über den Schiebetakt des Schieberegisters mit den Oszi. ( zB. Wert 2 -> 8 - 2 = 6 Durchläufe anstatt 8). Nachdem die die while durch die for getauscht hatte war dieses Problem behoben. Aber wieso??? Natürlich liegen <99,xx% aller Fehler beim Programmierer. Aber dieser hier wird mir nicht wirklich klar! mfg Lars
Hat nix mit dem Problem zu tun, aber mit void PE_Select(volatile uint8_t Port) { PE_Port &= ~(1<<PE_Demux_A0 | 1<<PE_Demux_A1 | 1<<PE_Demux_A2);} if (port & 1<<0) PE_Port |= 1<<PE_Demux_A0; if (port & 1<<1) PE_Port |= 1<<PE_Demux_A1; if (port & 1<<2) PE_Port |= 1<<PE_Demux_A2; } wird das Programm schon mal einen halben Meter kürzer. Was die Funktion angeht: Bei Schaltungen ist ein Bild einer verbalen Beschreibung immer vorzuziehen. Lies: ich kapier's nicht, was du da wie verschaltet hast.
Bzw.: void PE_Select(uint8_t Port) { PE_Port &= ~(1<<PE_Demux_A0 | 1<<PE_Demux_A1 | 1<<PE_Demux_A2); if (Port & 1<<0) PE_Port |= 1<<PE_Demux_A0; if (Port & 1<<1) PE_Port |= 1<<PE_Demux_A1; if (Port & 1<<2) PE_Port |= 1<<PE_Demux_A2; } denn das "volatile" ist bei einem Parameter Unfug.
@ A.K. Dein Abkürzungsvoschlag sieht sehr vieleversprechend aus. Werde ich morgen mal probieren. Darauf wäre ich so schnell nicht gekommen. @ all Ich werde Morgen mal eine Zeichnung machen. Das Problem kenne ich, von anderen die Geistigen Ergüsse auf die schnelle zu verstehen ;). Meiner Meinung nach ist das was die Funktionen im einzelnen machen, gar nicht so wichtig, sondern das sie sich gegenseitig beeinflussen. Obwohl alle Variablen lokal in den Funktionen deklariert sind. (Und nur dort gültig sein sollten!?). Lars
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.