Hallo, versuche mich gerade auf einem kleinen Testboard, worauf ein ATmega16 steckt. Habe am PortB 4LEDs (PB0 bis PB3) und 4 Taster (PB4 bis PB7). Funktioniert soweit auch, dass ich mit den Tastern etwas an den LEDs herumspielen kann. Nun wollte ich eine kleine Schleife bauen, wo mir LED1 aufleuchtet, und dann die logische 1 rüber zur LED4 wandert (Lauflicht). Dies funktionierte ebenfalls noch. Diese Funktion wurde dann erweitert, dass ich die Anzahl der Wiederholungen einstellen kann. Und hier beginnt das Problem: Er macht zwar den Durchlauf so oft wie ich ihm sage, aber beim letzten Durchlauf leuchtet LED1, dann 2, dann 3, und die 4. kommt nicht. Kann mir einer helfen? Hier der Programmauszug: unsigned wert = 1; // Startwert -> LED1! unsigned schleife = 0; // Startwert für Schleife (f. Wiederholungen benötigt) unsigned wiederholungen = 5; // Anzahl der Wiederholungen int zaehl() { _delay_ms(20); // Zeitverzögerung PORTB = wert; // Aktuellen Wert an Port B ausgeben wert = wert << 1; // "wert" um 1 verschieben if bit_is_set (PORTB,LED4) // Ende für Zähler ist LED4 { // Wenn Ende erreicht: wert = 1; // Zähler zurücksetzen schleife++; // Schleife um 1 erhöhen if (schleife < wiederholungen) // Schleife mit Anzahl d. Wiederholungen vergleichen zaehl(); // Schleife kleiner als Wied. -> gehe zu zahel else // Ansonsten: { schleife = 0; // Schleife zurücksetzen main(); // Fertig: Zurück zum Hauptprogramm } } else // Wenn Ende noch nicht erreicht: zaehl(); // Beginne von vorne }
Du hast da einige rekursive Aufrufe in Deiner Funktion drinnen. Rekursionen sind zwar nicht unbedingt falsch, ich bin mir aber sicher, dass du damit noch nicht zurecht kommst. (Rekursion: Wenn eine Funktion sich selbhst entweder direkt oder indirekt aufruft. In Deinem Fall ist dies die Funktion 'Zaehl' die selbst wieder die Funktion 'Zaehl' aufruft, welche ihrerseits die Funktion 'Zaehl' aufruft, usw.) Warum verwendest Du nicht ganz einfach Zaehl-Schleifen: int i; for( i = 0; i < Anzahl; i++ ) { /* mach irgendwas */ } Das ist eine Schleife, die genau 'Anzahl'-mal ausgefuehrt wird. Mit dem was du da geschrieben hast (ich habs zwar nicht analysiert, bin mir aber ziemlich sicher), hast du dich selbst ins Bein geschossen. Viel zu kompliziert.
Du rufst main() aus Deiner Funktion auf? Das ist kein "zurück zum Hauptprogramm, sondern main() wird aus Deiner Funktion heraus aufgerufen! Das ist ein rekursiver Aufruf von main(). Genauso mit zaehl(): Weisst Du, was Du mit rekursiven Aufrufen machst? Jeder Aufruf von zaehl() oder main() braucht Platz auf dem Stack - irgendwann läuft der über und Dein Programm hängt. Eine Funktion sollte sich NIEMALS selber aufrufen - solange Du nicht genau weisst, was Du damit machst. int zaehl(uint8_t wiederholungen) { uint8_t schleife = 0; uint8_t wert = 1; while (schleife < wiederholungen){ PORTB = wert; wert = wert << 1; if bit_is_set (PORTB,LED4){ wert = 1; schleife++; } _delay_ms(20); } PORTB = 0; // ganz am Schluss: alle LEDs aus } void main(void){ zaehl(5); while(1); } Gruß, Stefan
Ich hab noch mal etwas genauer durch den Code geschaut. Man, du hast dich da aber ordentlich verfranst. Ein Buch ueber Grundlagen der C-Programmierung waere da mal angebracht. Grundsaetzlich: Teile dir die Arbeit auf. Das was du vorhast, ist zunaechst mal viel zu schwierig. Also muss man sich mal was einfacheres suchen. Eine einzelne Lauflichtkette, zb. void EinDurchlauf() { int i; int Ausgabe = 1; for( i = 0; i < 4; ++i ) { PORTB = Ausgabe; Ausgabe = Ausgabe << 1; _delay_ms(20); } } Diese Funktion sollte eigentlich selbsterklaerend sein. Eine 1 wird an Port B an 4 Pins durchgeschoben. Klar? Wenn ja. Dann machen wir daraus Deine 'kompliziertere' Aufgabenstellung: Eine Funktion, die unter Zuhilfenahme obiger Funktion, das ganze Geschiebe eine bestimmte Anzahl mal macht: void Wiederhole( int WieOft ) { int i; for( i = 0; i < WieOft; i++ ) EinDurchlauf(); } und aufgerufen wird das ganze dann: int main() { int Anzahl; /* hier kommt der Teil, der feststellt wieoft das Lauflicht laufen soll. Dieser Teil soll eine Zahl in Anzahl hinterlassen */ .... /* Da wir jetzt wissen, wieviele Durchlauefe notwendig sind, rufen wir ganz einfach Wiederhole mit dieser Anzahl auf */ Wiederhole( Anzahl ); /* und den Mikro Schlafen schicken (Eine Endlosschleife in der er nichts tut */ while( 1 ) { } } Alternativ koennte man die Programmstruktur auch umstricken, so dass der µC immer wieder (Hinweis: das wird eine Schleife) feststellt ob eine Taste gedrückt wurde und wenn ja diese Taste in eine Zahl verwandelt und Wiederhole mit dieser Zahl aufruft: int main() { int Anzahl; while( 1 ) { /* mache immer wieder */ /* Tasten abfragen: Wenn keine Taste gedrueckt ist, soll Anzahl den Wert 0, haben, ansonsten steht die gewuenschte Anzahl an Wiederholgungen in Anzahl */ .... /* Die Aktion jetzt ausfuehren */ if( Anzahl > 0 ) Wiederhole( Anzahl ); } } In Deinem Code 'springst' Du zuviel herum. Zumindest denkst du das, in Wirklichkeit passiert da ganz was anderes. Wie gesagt: Grundlagenliteratur ueber Programmieren in C kaufen und lesen.
oh Mann ... da haben wir ja wieder klassisch doppelt gemoppelt ... Gruß Stefan
Vielen Dank mal für die Antworten. Fange leider neu mit C an und daher noch diese Fehler. Aber nun weis ich wenigstens worauf ich achten sollte, bzw. was nicht gemacht werden darf. Die Lösung mit der for-Schleife ist mir irgendwie gar nicht in den Sinn gekommen, obwohl ich diese auch schon ab und zu verwendet hab. Mit dieser klappt es jetzt aber problemlos. Code sieht so aus: int wert; // Variable für Ausgabe int schleife; // Variable für Schleife unsigned wiederholungen = 5; // Anzahl der Wiederholungen int zaehl() { for (schleife = 0; schleife < wiederholungen; schleife++) { for ( wert = 1; wert < 16; wert = wert << 1) { PORTB = wert; // Aktuellen Wert ausgeben _delay_ms(20); // Zeitverzögerung } } } Nur dieses "wert < 16" stört mich hier noch... Wie kann ich da die Variable LED4 mit herein bringen? Es ist die letzte LED die noch leuchten soll, LED4 ist an PB3, PB4 ist bereits ein Taster. Habe schon etwas herumprobiert, aber da ging dann überhaupt nichts mehr, nur wenn ich wert kleiner 16 reinschreibe. Werde jetzt noch Stefans Variante mal ausprobieren, da das mit der Übergabe einer Zahl für die Anzahl der Wiederholungen ja auch nicht schlecht währe... Vielen Dank schonmal :-) Schön das man hier Hilfe bekommt!
> Schön das man hier Hilfe bekommt! Schön, dass es hier noch Leute gibt, die selber lernen wollen und nicht nur cut & paste machen! Zeig mal, wie LED4 definiert ist. > Habe schon etwas herumprobiert, aber da ging dann überhaupt nichts > mehr, nur wenn ich wert kleiner 16 reinschreibe. Was hast Du da genau gemacht? Sinnvoll sind ja nur die Werte 2, 4, 8, 16, 32, 64 128. Aber Zwischenwerte sollten vom Prinzip auch funktionieren. Schreib die Variablen-Deklarationen besser in die Funktion mit rein, das hat den Vorteil, dass Speicherplatz gespart wird (gut, bei Deinem Programm wohl noch nicht das Hauptproblem). Gruß, Stefan
Okay. Hier der Auszug mit den Defines: // ### Die Defines ### #define TST1 PB4 #define TST2 PB5 #define TST3 PB6 #define TST4 PB7 #define LED1 PB0 #define LED2 PB1 #define LED3 PB2 #define LED4 PB3 >> Habe schon etwas herumprobiert, aber da ging dann überhaupt nichts >> mehr, nur wenn ich wert kleiner 16 reinschreibe. >Was hast Du da genau gemacht? Sinnvoll sind ja nur die Werte 2, 4, 8, >16, 32, 64 128. Aber Zwischenwerte sollten vom Prinzip auch >funktionieren. Naja, anstatt eines Wertes habe ich die Variable LED4 benutzt. Habs versucht mit LED4 == 1, wo ja überprüft wird ob LED4 (PB3) auf logisch 1 ist. >Schreib die Variablen-Deklarationen besser in die Funktion mit rein, >das hat den Vorteil, dass Speicherplatz gespart wird (gut, bei Deinem >Programm wohl noch nicht das Hauptproblem). Werde ich machen, danke für den Hinweis :-)
Du benutzt gcc, ja? LED4 ist keine Variable. Die Zeile #define LED4 PB3 macht nur einen Textersatz. LED4 wird also (aus Sicht des Compilers) in Deinem Quelltext durch PB3 ersetzt. PB3 findet sich in den I/O-Definitionen Deines ATmega: /* PORTB */ #define PB7 7 #define PB6 6 #define PB5 5 #define PB4 4 #define PB3 3 #define PB2 2 #define PB1 1 #define PB0 0 Das heisst: wieder wird der Text PB3 ersetzt - und zwar durch 3. Statt if(LED4 == 1) sieht der Compiler also if(3 == 1) und das wird natürlich nie richtig/WAHR/ausgeführt oder was auch immer. Gruß, Stefan
Achja, natürlich. Danke für die Erklärung, echt super :-) Ja, benutze GCC (WinAVR). Mein Problem währe dann wohl gelöst.
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.