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
... 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
intmain(void)
5
{
6
uint8_tzustand=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
elseif(!(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
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
intmain(void)
5
{
6
uint8_tzustand=AUS;
7
uint8_tzeit=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
elseif(!(PINC&(1<<PINC1)))
19
{
20
zustand=AN;
21
}
22
23
if(zustand==AN)
24
{
25
switch(zeit){
26
case0:PORTB^=(1<<PB5);break;
27
case1:PORTB^=(1<<PB4);break;
28
case2:PORTB^=(1<<PB3);break;
29
case3: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
elseif(!(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
elseif(Schritt==1)
27
PORTB&=~(1<<PB4);
28
elseif(Schritt==2)
29
PORTB&=~(1<<PB3);
30
elseif(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."
;)