Moin ich befasse mich sein ca 2 Wochen mit Microcontroller und habe mir nach Anleitung hir im Board den ATmega8 zugelegt. Nach den ersten start Schwirigkeiten habe ich es geschafft den kleinen zu Programmieren... Jetzt habe ich folgendes Problem: Ich habe 4 Ports (PORTB2 - PORTB5) als Ausgänge und 2 Ports (PORTC0 und PORTC1) als Eingänge festgelegt. An den Ausgänge habe ich 4 LEDs angeschlossen die nacheinander (wenn PORC0 Taster gedrückt wird) Blinken. Jetzt Wolte ich mit einem 2. Taster (PORTC1) die LEDs wieder ausschalten. Das Problem ist wenn ich mit Taster0 die LEDs einschalte fallen die in eine While(2) und da krige ich sie auch nicht mehr raus. Ich hab schon alles was mir so eingefallen ist ausprobiert. Hier ist mein Code. Würde mich über Tipps freuen. LG Shabi #define F_CPU 4000000UL #include <avr/io.h> #include <util/delay.h> #include <stdio.h> #include <inttypes.h> int main(void) { DDRB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); DDRC = (0<<PC0) | (0<<PC1); while(1) { if (!(PINC & (1<<PINC0))) { while(2) { PORTB^=(1<<PB5); _delay_ms(200); PORTB^=(1<<PB4); _delay_ms(200); PORTB^=(1<<PB3); _delay_ms(200); PORTB^=(1<<PB2); _delay_ms(200); } } else if (!(PINC & (1<<PINC1))) { PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); } } }
Ich servier dir keine Lösung, sonst lernst du nichts, aber ich führ dich mal auf den Weg: Wieso "while(2)" .. weil das nach "while(1)" kommt? .. mach dich mal schlau was in den Klammern der while-Schleife steht. Nein, es ist keine laufende Nummer! Tipp: Schau mal 2 Zeilen weiter oben... Weiterhin, wie kannst du erreichen, dass das Programm sich merkt das du einen Taster gedrückt hast, obwohl du ihn schon wieder losgelassen hast (das hast du bereits einmal implizit realisiert). Wenn du das hast, weisst du auch wie du dein Problem löst. Das die untere Abfrage niemals mehr erreicht wird im aktuellen Code sobald die Blinkschleife läuft, hast du korrekt erkannt. Gruß, Christian
Wenn Du folgendes schreibst:
1 | while(1) |
2 | {
|
3 | if (!(PINC & (1<<PINC0))) |
4 | {
|
5 | PORTB^=(1<<PB5); |
6 | _delay_ms(200); |
7 | PORTB^=(1<<PB4); |
8 | _delay_ms(200); |
9 | PORTB^=(1<<PB3); |
10 | _delay_ms(200); |
11 | PORTB^=(1<<PB2); |
12 | _delay_ms(200); |
13 | }
|
14 | }
|
15 | else if (!(PINC & (1<<PINC1))) |
16 | {
|
17 | PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); |
18 | }
|
... dann blinken die LEDs, solange Du Taster 1 drückst. Sobald Du Taster 2 drückst, leuchten alle LEDs (oder gehen halt alle aus, je nach Beschaltung gegen GND/Vcc). Lass also das while(2) einfach weg. Du wirst dann merken, dass die Reaktion auf Deinen Taster 1 u.U. ziemlich lahm ist. Das liegt daran, dass Du Deinen Taster1 im Worstcase nur alle 800ms abfragst. Du solltest Dich also im nächsten Schritt mit Timern beschäftigen, damit Du die Delays da wegbekommst. Viel Spaß noch, Frank
while(2) { ... } bedeutet, dass alles was in "..." steht für immer und ewig ohne Ende ausgeführt wird. Tipp: lerne erstmal c programmieren --> da gibt es auch super Literatur zu :-)
Das ging ja schnell. Christian Erker: Danke für die Tipps mal schauen ob ich das hinbekomme. Und Frank M. : genau das habe ich auch schon ausprobiert. Du hast recht wenn ich nach der if abfrage die While schleife raus lasse blinken die LEDs nur so lange wie ich den Taster0 gedrückt halte. Und wenn ich Taster1 drücke gehen die LEDs aus. LG Shabi
Shabi N. schrieb: > Und Frank M. : > genau das habe ich auch schon ausprobiert. Du hast recht wenn ich nach > der if abfrage die While schleife raus lasse blinken die LEDs nur so > lange wie ich den Taster0 gedrückt halte. Und wenn ich Taster1 drücke > gehen die LEDs aus. Vielleicht möchtest Du das ja anders: Taster1 kurz drücken und wieder loslassen: LEDs blinken dauerhaft Taster2 kurz drücken und wieder loslassen: LEDs gehen aus und bleiben aus. Dann wäre die 1. Lösung die folgende:
1 | #define AUS 0
|
2 | #define AN 1
|
3 | |
4 | int main(void) |
5 | {
|
6 | uint8_t zustand = AUS; |
7 | |
8 | DDRB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); |
9 | DDRC = (0<<PC0) | (0<<PC1); |
10 | |
11 | while(1) |
12 | {
|
13 | if (!(PINC & (1<<PINC0))) |
14 | {
|
15 | zustand = AUS; |
16 | }
|
17 | else if (!(PINC & (1<<PINC1))) |
18 | {
|
19 | zustand = AN; |
20 | }
|
21 | |
22 | if (zustand == AN) |
23 | {
|
24 | PORTB^=(1<<PB5); |
25 | _delay_ms(200); |
26 | PORTB^=(1<<PB4); |
27 | _delay_ms(200); |
28 | PORTB^=(1<<PB3); |
29 | _delay_ms(200); |
30 | PORTB^=(1<<PB2); |
31 | _delay_ms(200); |
32 | }
|
33 | else
|
34 | {
|
35 | PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); |
36 | }
|
37 | }
|
38 | }
|
Trotzdem wirst Du damit das Problem nicht los, dass Du die Taster eventuell bis zu knapp 1 Sekunde lang drücken muss, bis Dein Programm reagiert. Du könntest die Abfrage natürlich öfter machen... aber richtig lösen kannst Du das nur mit einem Timer.
Genau das wollte ich damit erreichen. würdest du mir nur noch folgende 3 Zeilen erklären was da genau passiert? #define AUS 0 <<<---- #define AN 1 <<<---- int main(void) { uint8_t zustand = AUS; <<<---- den rest habe ich verstanden und du hast wieder recht. Wenn ich jetzt die LEDs ein schalte gehat ds recht schnell nur wenn ich sie wieder ausschalten will muss ich warten bis die LEDs ein mal durchgelaufen sind. Aber das stört mich erst mal nicht bin ja noch ganz am Anfang. LG Shabi
Shabi N. schrieb: > Genau das wollte ich damit erreichen. Na prima. Ging aus Deinem Eröffnungsposting aber nicht direkt hervor :-) > würdest du mir nur noch folgende 3 Zeilen erklären was da genau > passiert? > > #define AUS 0 <<<---- > #define AN 1 <<<---- Mit Preprocessor-Befehlen wie #define kannst Du Texte definieren, die im Quelltext - bevor der eigentliche Compiler gestartet wird, ausgetauscht werden. Dadurch wird Dein Quelltext lesbarer. Der Preprocessor ersetzt einfach alles, wo AUS steht, durch 0 und alles, wo AN steht, durch 1 - einfach deshalb, weil ich es durch die #defines so eingestellt habe. Ich hätte auch schreiben können: zustand = 1; bzw. zustand = 0; bzw. if (zustand == 1) { ... } Aber weisst Du nach ein paar Monaten noch, was die magischen Werte 1 und 0 eigentlich bedeuten? Ich rate Dir zum Lesen ein C-Buch, damit Du solche Grundlagen lernst und auch anwendest. Viel Spaß dabei, Frank
Super danke vielmals das hat sich auf jeden fall gelohnt und wieder was dazu gelernt. LG Shabi
Shabi N. schrieb: > Super danke vielmals das hat sich auf jeden fall gelohnt und wieder was > dazu gelernt. Du wirst lachen: Ich habe mit der C-Programmiererei Mitte der 1980er unter Unix angefangen, das ist jetzt 28 Jahre her. Und ich lerne heute noch dazu... Stell Dich also schon mal darauf ein... ;-)
Wenn gleich die Lösung schon ganz OK ist, hat sie noch ein Problem, dass nur allzugern ignoriert wird. Deine Taster werden nur einmal pro LED-Durchlauf abgefragt. Drückst du nur kurz mittendrin, reagiert dein Programm nicht. Und deine LED-Spielchen werden sicherlich sehr schnell viel länger werden. Darum sollte man frühzeitig das richtige Konzept erlernen, das da lautet Multitasking. Klingt kompliziert, ist es aber nicht.
1 | #define AUS 0
|
2 | #define AN 1
|
3 | |
4 | int main(void) |
5 | {
|
6 | uint8_t zustand = AUS; |
7 | uint8_t zeit =0; |
8 | |
9 | DDRB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); |
10 | DDRC = (0<<PC0) | (0<<PC1); |
11 | |
12 | while(1) |
13 | {
|
14 | if (!(PINC & (1<<PINC0))) |
15 | {
|
16 | zustand = AUS; |
17 | }
|
18 | else if (!(PINC & (1<<PINC1))) |
19 | {
|
20 | zustand = AN; |
21 | }
|
22 | |
23 | if (zustand == AN) |
24 | {
|
25 | switch (zeit) { |
26 | case 0: PORTB^=(1<<PB5); break; |
27 | case 1: PORTB^=(1<<PB4); break; |
28 | case 2: PORTB^=(1<<PB3); break; |
29 | case 3: PORTB^=(1<<PB2); break; |
30 | }
|
31 | zeit++; |
32 | if (zeit >= 4) zeit=0; |
33 | }
|
34 | else
|
35 | {
|
36 | PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); |
37 | zeit =0; |
38 | }
|
39 | |
40 | _delay_ms(200); |
41 | }
|
42 | }
|
Jetzt werden deine Tasten alle 200ms geprüft, EGAL wie lange deine LED-Kette blinkert!
> while(1) > { > if (!(PINC & (1<<PINC0))) > { > zustand = AUS; > } > else if (!(PINC & (1<<PINC1))) > { > zustand = AN; > } > > if (zustand == AN) > { > PORTB^=(1<<PB5); > _delay_ms(200); > PORTB^=(1<<PB4); > _delay_ms(200); > PORTB^=(1<<PB3); > _delay_ms(200); > PORTB^=(1<<PB2); > _delay_ms(200); > } > else > { > PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); > } > } Das ist eine Möglichkeit. Es gibt aber noch andere EINFACHE Möglichkeiten, mit der du den Nachteil der seltenen Tastenabfrage noch weiter drücken kannst: Bau dir zum Beispiel einen 'Schrittzähler' ein. Der Schrittzähler sagt dir, welche LED zu leuchten hat.
1 | ...
|
2 | |
3 | Schritt = 0; |
4 | |
5 | while(1) |
6 | {
|
7 | if (!(PINC & (1<<PINC0))) |
8 | {
|
9 | zustand = AUS; |
10 | }
|
11 | else if (!(PINC & (1<<PINC1))) |
12 | {
|
13 | zustand = AN; |
14 | }
|
15 | |
16 | if (zustand == AN) |
17 | {
|
18 | Schritt++; |
19 | if (Schritt == 4) |
20 | Schritt = 0; |
21 | |
22 | PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); |
23 | |
24 | if (Schritt == 0) |
25 | PORTB &= ~(1<<PB5); |
26 | else if (Schritt == 1) |
27 | PORTB &= ~(1<<PB4); |
28 | else if (Schritt == 2) |
29 | PORTB &= ~(1<<PB3); |
30 | else if (Schritt == 3) |
31 | PORTB &= ~(1<<PB2); |
32 | |
33 | _delay_ms(200); |
34 | }
|
35 | else
|
36 | {
|
37 | PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2); |
38 | }
|
39 | }
|
Vorteil: jetzt wird die Tastenabfrage nach JEDEM Lampenwechsel gemacht. Die Verzögerungszeit nach der spätestens auf einen Tastendruck reagiert wird, ist von 4*200ms (800ms) auf 200ms gesunken. 2 Zehntelsekunden ist zwar noch nicht "sofort", aber immerhin schon nahe drann, so dass die meisten Benutzer damit kein Problem haben.
@Falk :-) @Shabi Wenn die 200ms immer noch zu lang sind: Nun, kein Mensch sagt, dass man 200ms am Stück warten muss. Wartet man 10 mal 20ms, dann hat man in Summe auch 200ms gewartet. Dann darf man halt nicht bei jedem Schritt in die nächste Schaltstufe gehen, sondern nur bei jedem 10.ten. Im Endeffekt kommt das aufs gleiche raus. Mit einem kleinen Unterschied: Die Tastenabfrage findet dann alls 20ms statt. Und 2 Tausendstel Sekunden sind für einen Menschen viel zu kurz um das als Verzögerung wahr zu nehmen. Also: Was sollst du mitnehmen? Es gibt Variablen. In Variablen kann man sich Werte speichern. Diese Werte können zb auch Beschreibungen (in Form von Zahlen) sein, die einen Zustand beschreiben. Jede Zahl steht für einen Zustand, zb Lampe 1 ein, Motor 1 dreht, Rollo oben, etc. Bei dir dann zum Beispiel eben auch: Lauflicht läuft oder Lauflicht läuft nicht. Eine andere Variable beschreibt an welcher Stelle die Lauflichtsequenz gerade ist. Es ist meistens eine ganz gute Strategie, wenn man 'Auslöser' (Tastendruck) von der tatsächlichen Aktion (bei dir Lauflicht) mit solchen Zustandsvariablen trennt. Der Auslöser vermerkt in der Variablen lediglich, ob die Aktion auszuführen ist oder nicht (oder auch wie sie auszuführen ist). Davon getrennt ist der Teil im Programm, der anhand der Zustandsvariablen die entsprechende Aktion dann auch tatsächlich ausführt. Und wenn die Aktion insgesammt zu lange dauert, dann unterteilt man sie in einzelne Phasen, wieder gekoppelt mit einer weiteren Variablen, die beschreibt, in welcher Phase sich die 'Aktion' gerade befindet. Das ganze ist eingebettet in die eine 'große' Hauptschleife while( 1 ) { ... } die dein Programm immer hat. Die ist aber auch die einzige Endlosschleife! Andere Schleifen in dieser Form sind nicht zulässig, denn jede Logik lässt sich immer irgendwie in eine ähnliche Struktur bringen. Du musst weg vom Denken: Ich mach jetzt in einer Schleife dieses und jenes. Deine Denkweise (in der µC Programmierung) muss in die Richtung gehen: Ich habe da einen Zeitpunkt nach dem anderen - mit jedem Durchlauf durch die große while Schleife ist etwas Zeit vergangen - was gibt es genau jetzt, nachdem ein bischen Zeit vergangen ist, zu tun. Also weg vom Denken in Schleifen, hin zum Denken in Ereignissen, die in bestimmten Zeitabständen auszuwerten sind.
Danke Leute für die vielen Tipps. Ich merke das ich noch nicht Microcontrollermäßig denke und mir warscheinlich alles viel komplizierter vorstelle als es wirklich ist. Wenn ich mir die Quellcodes jetzt anschaue, leuchtet auch vieles ein. Werde mir das ganze noch mehrmals genauer anschauen und analysieren bis es komplett sitzt. SUUUUPPER Danke nochmals an alle. So macht das Thema richtig spaß. LG Shabi
Shabi N. schrieb: > warscheinlich alles viel komplizierter vorstelle als es wirklich ist. Das tun die meisten. Sie sind vom Fernsehen/Film 'verdorben' worden. "Computer, die Schilde rekonfigurieren" funktioniert nun mal nur auf der Enterprise. Und auf die Eingabe "Suche alle Personen, die in Beziehung zur Toten stehen und ein Motiv haben" kriegst du von einem heutigen Computer höchtens ein lakonisches "Syntax Error". Computer sind einerseits (im elektronischen Aufbau) viel komplexer als viele Menschen glauben, können dafür von sich aus (auf Logikebene) viel weniger als die meisten Menschen glauben. Will man einen Computer programmieren, muss man einfach (im Gegensatz zu: kompliziert) denken! Ganz banale Vorgehensmuster, wie wir sie jeden Tag problemlos benutzen. Oder bleibst du beim Herd stehen, bis die Suppe fertig gekocht ist? Ich wette, du tust das nicht. Du schaltest ein und siehst nur ab und zu beim Herd vorbei, ob die Suppe schon kocht. Und in der Zwischenzeit machst du was anderes.
Falk Brunner schrieb: > if (zeit >= 4) zeit=0; Karl Heinz Buchegger schrieb: > if (Schritt == 4) > Schritt = 0; Hier sieht man den Unterschied zwischen dem Angsthasen, der seinem Programm nicht traut und dem, der sich sicher ist, dass die Schrittvariable niemals größer als 4 werden kann :-) Nichts für ungut, ich selber programmiere eher genauso "defensiv" wie Falk - im Zweifel lieber mit ">=" als mit "==". Kostet den µC dasselbe an Arbeit. Gruß, Frank
Frank M. schrieb: > Hier sieht man den Unterschied zwischen dem Angsthasen, der seinem > Programm nicht traut und dem, der sich sicher ist, dass die > Schrittvariable niemals größer als 4 werden kann :-) Dazu mal ein Zitat von Bertrand Russell: "Das ist der ganze Jammer: Die Dummen sind so sicher und die Gescheiten so voller Zweifel." ;)
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.