Hallo liebe Forenuser,
ich bin seit längerer Zeit ein begeisterter Mitleser dieses Forums, da
ich denke, dass ihr hier die richtigen Ansprechpartner seid, werde ich
euch ein paar Fragen zu meinem Projekt stellen...
Zum Projekt selbst:
Ein Bekannter von mir möchte eine Leuchtreklame für eine
Kunstausstellung bauen. Dabei wird mit einer 12 V-Lampe ein Plakat mit
unterschiedlichen Zeitintervallen angeleuchtet. Einfach gesagt eine
Lampe, die mit unterschiedlichen Intervallen leuchtet/blinkt.
Da ich mich schon seit einiger Zeit für Elektronik und Mikrocontroller
interessiere, habe ich mir dafür eine Steuerung überlegt und möchte sie
demnach meinem Bekannten schenken und mit einem ATmega8 steuern.
Das Ganze soll über ein Bedienpanel steuerbar sein. Heißt also, dass er
mehrere unterschiedliche "Blinkrhythmen" auswählen kann, die diese Lampe
dann anschließend ausgeben soll.
Dafür habe ich ein Pult mit 5 Schaltern gebaut.
Der erste Taster ("MANUAL") soll das manuelle Senden von Lichtimpulsen
ausgeben. Heißt, solange auf den Schalter gedrückt wird, wird das Licht
angelassen. Sobald er losgelassen wird, erlischt es.
Hinter dem zweiten Taster verbirgt sich ein fest programmierter
Rhythmus, der ein bestimmtes Blinkmuster endlos ausgeben soll.
Ebenso der dritte Signaltaster, der wieder ein anderes fest
programmiertes Muster endlos "blinken" lassen soll.
Taster-4 ist der "CLEAR"-Schalter, der die Ausgabe der Endlosrhythmen
löscht, sodass das Licht nach dem Betätigen erlischt.
Taster-5 ist die Speichertaste "STORE", mit der der Bekannte ein
beliebiges Blinkmuster speichern kann, welches er durch die MANUAL-Taste
vorgibt.
--> Zum speichern eines individuellen "Blinkmusters" wird zunächst die
STORE-Taste gedrückt gehalten, während mit der MANUAL-Taste das
beliebige Muster "eingespielt" wird.
Nachdem dann der STORE-Taster nach dem Eingeben des Musters losgelassen
wird, soll das eingespielte Blinkmuster über diesen Taster durch
einfachen Druck abrufbar sein, bis die Versorgungsspannung (ebenso 12 V)
zur Steuerung (uC) unterbrochen wird.
Vor jedem Wechsel der Blinkmuster muss die CLEAR-Taste betätigt werden.
Ich hoffe, ich konnte den Sachverhalt so gut wie möglich beschreiben.
Nun zum elektronischen Aufbau.
Das Ganze soll wie beschrieben über einen ATmega8 gesteuert werden.
An PORTC sollen die 4 Taster "MANUAL", "MUSTER-1", "MUSTER-2" und
"STORE" angeschlossen werden, an PORTD ein Relais bzw. Transistor als
Ausgabe zur 12V-Lampe, sowie der Schalter "CLEAR", am INT0
(Interrupteingang).
Die einzelnen Taster sind folgendermaßen an PORTC (und INT0-Eingang von
PORTD) über einen Spannungsteiler angeschlossen:
12V
o
|
|
_|_
| |
| | 1kOhm
| |
| |
|___|
| Taster
| /
o-------/ -------Controller-INPUT (ca. 5V)
|
|
_|_
| |
| | 680Ohm
| |
| |
|___|
|
|
GND
(Schaltbild vom kompletten Aufbau folgt)
Frage-1) Ist das Anschließen des Schalters so korrekt, damit man mit 12V
auf die 5V am Eingang eines Controllerpins kommt?
Soweit zum Hardwareaufbau.
Nun zum Quellcode (siehe Anhang)
Dann begann ich vor einer Woche mit dem Programmieren der Software für
den Mikrocontroller.
Zur Entprellung habe ich dankend den Entprell-Code von Peter Dannegger
übernommen, welcher für mich gut leserlich ist und den gewünschten
Effekt erzeugen sollte.
Die fest einprogrammierten Signale (Funktion signal()) sind
selbsterklärend, sie beinhalten das gewünschte Muster welches über den
Ausgangspin ausgegeben werden soll.
Sobald die CLEAR-Taste gedrückt wird, wird die InterruptRoutine
aufgerufen, welche das Licht erlöschen lässt.
Dann die STORE-Taste (das schwierigste an der Sache).
Dabei frage ich zunächst ab, ob die Taste alleine oder in Verbindung mit
der MANUAL-Taste gedrückt wird.
Ist ersteres der Fall, wird die vorher eingegebene Blinksequenz endlos
ausgegeben.
Soll jedoch erst ein manuelles Muster eingespielt werden, so dachte ich
mir, über einen Timer die Zeit des Gedrückthaltens des MANUAL-Tasters zu
messen (Zählen der Timerüberläufe), diese (entspricht der Dauer des
Gedrückthaltens des MANUAL-Tasters) in eine Array zu speichern und die
neuen Signale engegenzunehmen und ebenso in ein Array zu speichern, usw.
Ich hoffe, das war ebenso verständlich :)
Dabei haben sich auch einige Fragen aufgetan.
Frage-2) Sind meine Timer richtig initialisiert, damit dieser "läuft"?
Frage-3) Ist mein Interrupteingang (im Anfang der main()) richtig
initialisiert, damit dieser funktioniert?
Frage-4) Habe ich bei der Speichertaste (STORE) einen Denkfehler, um die
eingegebenen Rhythmen zu speichern und so wieder wiederzugeben?
Frage-5) Wird die von mir definierte delay_sec()-Funktion vom Compiler
wegoptimiert? Ich bräuchte nämlich eine Funktion, die besser in Sekunden
als in Millisekunden zählt...
Ich würde mich riesig darüber freuen, wenn ihr eueren geschulten Blick
auf meinen Quellcode werfen könntet um mir zu sagen, wo meine Fehler
liegen. Außerdem hoffe ich, den Code ausreichend kommentiert zu haben,
damit er halbwegs verständlich ist.
Soweit erstmal, der Schaltplan folgt wiegesagt, da ich gerade noch am
fleißigen Zeichnen bin :-)
Vielen Dank für euere Hilfe!!!
Gruß
Sascha
Sascha schrieb:> Frage-1) Ist das Anschließen des Schalters so korrekt, damit man mit 12V> auf die 5V am Eingang eines Controllerpins kommt?
Ja schon.
Die Frage ist aber, warum treibst du einen derartigen Aufwand?
+----------------> µC-Portpin
|
\
\
|
--+----- GND
Fertig ist die Schose.
Im Programm den Pin als Input definieren, den Pullup Widerstand
einschalten und die Sache ist gegessen. Die 12V interessieren keinen.
Und sei mir nicht böse, aber das ist erstes oder zweites Kapitel in
jedem Tutorial: welche Möglichkeiten hab ich, einen Taster
anzuschliessen.
(Den Rest muss ich mir jetzt erst mal genauer durchlesen)
Mir ist eines nicht klar.
Du hast einen Timer im Programm.
Das ist gut. Das ist sogar sehr gut.
Nur - warum benutzt du ihn nicht?
(ausser diesem läppischen Blinken einer LED)
Du kannst deine komplette Zeitsteuerung, inklusive dem Abfahren eines
Blinkmusters und Tastenentprellen, mit diesem Timer locker erledigen.
Statt dessen wimmelt es da wieder mal von komplizierten Konstrukten, die
sich um delays drehen.
Delay ist der falsche Weg für ernsthafte Programme! Delay ist eine
Krücke, weil man Anfängern mal was in die Hand geben muss, mit dem sie
klar kommen. Aber Delay führt zu Programmen, die grauslich zu warten
sind und die vor allen Dingen in der Bedienung immer besch.... sind,
weil der µC die halbe Zeit vertrödelt anstatt etwas sinnvolles zu tun.
>Ja schon.>Die Frage ist aber, warum treibst du einen derartigen Aufwand?
Ok, vielen Dank!
Da hast du Recht, das ist natürlich nicht sinnvoll und im Tutorial habe
ich es anscheinend überlesen.
>(Den Rest muss ich mir jetzt erst mal genauer durchlesen)
Danke dir schon mal! :)
>Delay ist der falsche Weg für ernsthafte Programme! Delay ist eine Krücke, >weil
man Anfängern mal was in die Hand geben muss, mit dem sie klar kommen. >Aber Delay
führt zu Programmen, die grauslich zu warten sind und die vor >allen Dingen in der
Bedienung immer besch.... sind, weil der µC die halbe >Zeit vertrödelt anstatt
etwas sinnvolles zu tun.
Ok, verstehe ich. Aber ist der Mehraufwand nicht größer, z.B. den Timer
auf eine "handliche" Zeiteinheit herunterzubrechen, bei einem solchen
Programm?
Z.B. hat in meinem Falle der controller nichts zutun, in der Zeit, in
der er eine Signalabfolge "blinken lässt". Außer auf ein CLEAR-Signal
warten. Und dafür ist der Interrupt zuständig.
Ich werde es aber ändern, wenn ich weiß, dass sonst alles im Code
stimmt! :)
Jedenfalls danke für den Tipp...
Sascha schrieb:>>Delay ist der falsche Weg für ernsthafte Programme! Delay ist eine Krücke, >weil> man Anfängern mal was in die Hand geben muss, mit dem sie klar kommen. >Aber
Delay
> führt zu Programmen, die grauslich zu warten sind und die vor >allen Dingen in
der
> Bedienung immer besch.... sind, weil der µC die halbe >Zeit vertrödelt anstatt> etwas sinnvolles zu tun.>> Ok, verstehe ich. Aber ist der Mehraufwand nicht größer, z.B. den Timer> auf eine "handliche" Zeiteinheit herunterzubrechen, bei einem solchen> Programm?
Das sind 2 Zuweisungen an das Timerregister (die du sowieso schon hast)
und eine Zählvariable.
> Z.B. hat in meinem Falle der controller nichts zutun, in der Zeit, in> der er eine Signalabfolge "blinken lässt". Außer auf ein CLEAR-Signal> warten. Und dafür ist der Interrupt zuständig.
Tasten über Interrupts. OK, dann ist alles klar.
>> Ich werde es aber ändern, wenn ich weiß, dass sonst alles im Code> stimmt! :)
Das Problem ist, dass der ganze Codeaufbau nicht stimmt.
Ich kann gar nicht glauben, dass du schon länger hier mitliest. So
ungefähr alle 2 Monate schreib ich riesige Abhandlungen darüber, wie man
Zeitsteuerungen mit dem µC 'nach den Regeln der Kunst' aufbaut, so dass
der µC zu jedem Zeitpunkt auf Tastendrücke reagiert und nebenher auch
noch andere Dinge abarbeiten kann.
>so dass der µC zu jedem Zeitpunkt auf Tastendrücke reagiert und nebenher >auch
noch andere Dinge abarbeiten kann.
Ich vermute, du meinst das Thema Betriebssystem/Scheduling auf einem
Mikrocontroller?!
Ok, aber ist es für mich als Anfänger nicht ein vielleicht nicht
eleganter aber trotzdem funkionierender Ansatz?
Sascha schrieb:> Ich vermute, du meinst das Thema Betriebssystem/Scheduling auf einem> Mikrocontroller?!
Dazu braucht man kein Betriebssystem. Das ist viel einfacher, als Du es
Dir vorstellst. Lies Dir mal den folgenden Artikel durch. Der beschreibt
im Prinzip sogar genau Dein Szenario (Taste abfragen und Lampe blinken
lassen): http://www.mikrocontroller.net/articles/Multitasking
Ok, das stimmt, der Inhalt des Artikels ist sinnvoll und professionell.
Leider übersteigt das Ganze jetzt meine Umsetzungsfähigkeit aufgrund der
recht geringen Erfahrungen mit Mikrocontrollern.
Könntet ihr mir bei der Umsetzung helfen oder mir wenigstens sagen, wie
mein "böses" Programm zum Leben erweckt?
Danke und Gruß
Hi,
nun habe ich es anhand des Multitasking-Artikels soweit mein Verständnis
es brachte abgeändert, siehe Anhang.
Leider weiß ich nicht, wie ich die led_blinken()-Funktion dazu bringe,
die gewünschten Aktionen wie CLEAR und Signal-Ausgabe geschweige denn
vom "STORE"-Taster abzuarbeiten.
Genauso wenig verstehe ich, wie die Funktion mit dem zaehler einen
Blinkintervall steuern kann.
Danke!
zumal es ja nicht nur ein Blinken sein wird sondern z.B. ein anderes
Muster wie "Lang (5 sec.) an, Lang an, kurz an (2 sec.), AUS (10 sec.).
Das kann ich mit "blinken" nicht erschlagen.
Es wird Dir hier sicher gerne geholfen. Machen musst Du es aber selber.
Als erstes musst Du erkennen, welche Zustände Dein Programm einnehmen
kann:
- STATE_MANUAL: Lampe leuchtet nur, solange Taste MANUAL gedrückt ist
- STATE_PROGRAM_1: Lampe leuchtet nach festem Programm
- STATE_PROGRAM_2: Lampe leuchtet nach festem Programm
- STATE_CUSTOM_PLAY: Lampe leuchtet nach selbst eingespeichertem
Programm
- STATE_CUSTOM_CAPTURE: Es wird gerade ein Programm einprogrammiert
Da Du fünf Tasten hast, würde ich die auch genau so nennen. Wenn man ein
der Tasten drückt, wird in den entsprechenden Zustand gewechselt.
Du brauchst also zuerst eine Varibale, die den aktuellen Zustand
speichert:
1
staticuint8_tstate=MANUEL;
Außerdem eine Funktion, die die Tasten auswertet und Zustände wechselt:
1
voidkey_task(void)
2
{
3
if(key_pressed(KEY_MANUAL){
4
if(state!=STATE_CUSTOM_CAPTURE){
5
state=STATE_MANUAL;
6
}
7
if(key_pressed(KEY_PROGRAM_1)){
8
state=STATE_BUTTON_1;
9
}
10
// ...
11
}
Dann eine Funktion für jeden Zustand. Die wird regelmäßig aufgerufen,
solange sich das Programm in dem Zustand befindet. Keine dieser
Funktionen blockiert das Programm, sondern sie kehrt sofort zurück:
1
voidmanual_task(void)
2
{
3
if(key_pressed(KEY_MANUAL){
4
light_on();
5
}else{
6
light_off();
7
}
8
}
9
10
voidprogram_1_task(void)
11
{
12
if(counter<10){
13
light_on();
14
}elseif(counter<200){
15
light_off();
16
counter=0;
17
}
18
}
Die Hauptschleife sieht dann so aus:
1
while(1){
2
key_task();
3
switch(state){
4
caseSTATE_MANUAL:
5
manual_task();
6
break;
7
casePROGRAM_1_TASK:
8
program_1_task();
9
break;
10
// ...
11
}
12
}
Vielleicht hilft Dir das, eine Vorstellung für ein sinnvolles
Grundgerüst zu bekommen. Umsetzten musst Du es aber wie gesagt selber.
> > Frage-1) Ist das Anschließen des Schalters so korrekt,> > damit man mit 12V auf die 5V am Eingang eines Controllerpins kommt?> Ja schon.
was für ein Unsinn.
Dem Eingang fehlt bei geöffnetem Schalter der definierte Pgel durch
einen PullDown.
Die Schaltung ist also falsch.
Deine Schaltung (Taster gen Masse) ist in Ordnung weil man den internen
PullUp des Eingangs verwenden kann.
Hi,
im Anhang nun die abgeänderte Version.
Ich habe Probleme beim Schreiben der STORE (capture) Funktion...wie kann
ich am besten die Zeit des Gedrückthaltens und des Loslassens zählen?
Brauche ich dafür zwei Timer, der eine, der bei steigender und der
andere der bei Fallender Flanke des Tasters losläuft?
Könntet ihr einen Blick auf meinen code werfen?
Danke!
Sascha schrieb:> Ich habe Probleme beim Schreiben der STORE (capture) Funktion...wie kann> ich am besten die Zeit des Gedrückthaltens und des Loslassens zählen?> Brauche ich dafür zwei Timer, der eine, der bei steigender und der> andere der bei Fallender Flanke des Tasters losläuft?
Du brauchst nur einen Timer, der regelmäßig einen Zähler (counter)
erhöht. Sagen wir mal, alle 100 ms. Das ist die Zeitbasis in Deinem
Programm.
Jetzt brauchst Du eine geeignete Form, wie Du das selbstgewählte
Programm abspeichern kannst. Eine Möglichkeit wäre folgendes:
Du legst Dir ein Array an, in dem die Zeitpunkte stehen, an denen die
Lampe umgeschaltet werden soll. Zu Beginn ist die Lampe immer aus.
Außerdem musst Du die Länge des Programms wissen, also wie viele
Datenpunkte gespeichert sind, sowie die aktuelle Position, die gerade
angezeigt wird.
Beispiel:
custom_program[0] = 5; // 500 ms aus
custom_program[1] = 20; // 1500 ms an
custom_program[2] = 30; // 1000 ms aus
custom_program[3] = 35; // 500 ms an
custom_program_len = 4; // Es sind 4 Zeitpunkte gespeichert
custom_program_pos = 2; // Wird sind gerade an Stelle 2 im Programm,
// also in der 1000 ms langen Aus-Phase
Du brauchst jetzt noch zwei Tasks:
custom_play_task():
- Vergleicht die Systemzeit (counter) mit dem aktuellen Array-Wert. Wenn
der counter größer ist, wird die Lampe umgeschaltet und das Programm
geht einen Schritt weiter.
- Falls die aktuelle Stelle im Programm der Programmlänge entspricht,
wird wieder von Anfang an begonnen.
custom_capture_task():
- Merkt sich, ob die Taste MANUAL zuletzt gedrückt war oder nicht.
- Wenn der counter ungleich dem aktuellen Arraywert ist und sich die
Taste geändert hat, wird der counter-Wert in das Array geschrieben und
die Programmlänge um eins erhöht.
- Der Task darf nicht über die Arraygrenze hinaus schreiben.
- Wenn die Aufzeichnung fertig ist, musst Du ggf. noch darauf achten,
dass eine gerade Anzahl an Einträgen vorliegt, damit das Programm immer
gleich läuft und nicht abwechselnd invertiert und nicht invertiert ist.
Das wäre eine Idee. Du kannst in dem Array statt der Gesamtzeit auch nur
die Zeit zwischen dem Umschalten speichern. Dann müssen die Funktionen
ein bisschen anders aussehen.
Hallo,
Danke erstmal für deine tolle Hilfe!
Nun habe ich meinen Code entsprechend aktualisiert.
Hinzugefügt wurde:
- inc_counter() -> glob. Zählvariable "timer_counter"
- init_timer()
- capture_1_play_task()
- capture_1_task()
- light_toggle()
- globale Array.
Leider habe ich noch die Frage:
- Was kommt in den if/else-Zweig in der Funktion capture_1_task(), die
das freie Muster aufzeichnen soll?
Ist der Code soweit ok? (siehe Anhang)
Vielen Dank und Gruß
Du brauchst noch eigene Definitionen für die Zustände. Es gibt nämlich
keinen Zustand CLEAR. Das ist nur ein einmaliges Ereignis beim Drücken
der Taste. Dafür fehlt der Zustand PLAY, also das Wiedergeben des
aufgenommenen Signals.
Ich würde übrigens für jeden dieser Zustände eine Taste benutzen. Das
macht die Bedienung und das Programm verständlicher und Du brauchst
keine Tastenentprellung. Also statt der CLEAR-Taste eine PLAY-Taste.
Aber auch dann definiere bitte eigene Namen für die Zustände und recycle
nicht die Tastendefinitionen.
1
uint8_ttimer_counter=0;
Hier fehlt ein volatile, wenn der counter von einem Interrupt und vom
Hauptprogramm genutzt werden soll. Außerdem alle Variablen static
machen, die Du nicht auch noch in anderen C-Dateien brauchst.
1
// glob. Array zur Speicherung der Aufzeichnungswerte:
Zur Initialisierung aller Element mit Null reicht ein {0}. Im Prinzip
brauchst Du an der Stelle nicht mal das, weil globale Variablen (aber
nicht lokale in Funktionen!) automatisch mit Null initialisiert werden.
Aber schreib es ruhig zur Verdeutlichung hin.
1
voidlight_toggle(void)
2
{
3
if(PORTD&(1<<PD0))
4
{
5
PORTD&=~(1<<PD0);
6
}
7
else
8
{
9
PORTD|=(1<<PD0);
10
}
11
}
Geht mit XOR einfacher:
1
voidlight_toggle(void)
2
{
3
PORTD^=(1<<PD0);
4
}
Dann der Task:
1
voidsign_1_task(void)
2
{
3
staticuint16_tcounter=0;
4
if(counter<10)
5
{
6
light_on();
7
}
8
elseif(counter<200)
9
{
10
light_off();
11
counter=0;
12
}
13
}
Du inkrementierst counter nie. Aber selbst wenn, würde es viel zu
schnell gehen, da die Funktion ja sehr oft aufgerufen wird. Statt
counter musst Du timer_counter nehmen. Dito für sign_2_task.
1
voidcapture_1_task(void)
2
{
3
inc_counter();
4
if(state==1)
5
{
6
//??
7
}
8
}
Hier wirds jetzt sinnlos. Wozu willst Du state abfragen? Den weißt Du
schon, da capture_1_task nur im Zustand STATE_CAPTURE_1 aufgerufen wird.
Du musst abfragen, ob die Taste gedrückt ist oder nicht. Und dann das
machen, was ich im Beitrag vorher geschrieben hab.
Dann kommt inc_counter: Diese Funktion wurde bisher nicht definiert. Der
Compiler kennt sie also nicht und sollte auch eine Warnung ausgeben. Du
müsstest also entweder die Definition von inc_counter weiter nach oben
holen, oder zuerst einen Prototyp deklarieren. Gut, schauen wir erst
mal, was inc_counter() machen würde:
Als erstes fällt mir der Syntaxfehler auf: Es fehlt eine schließende
Klammer nach dem if. Das heißt, Du hast den Code bisher nicht mal
kompiliert?! So entwickelt man keine Software. Du musst den Code
kompilieren und ausprobieren! Wenn Du die fertige Leuchtreklame nicht
hast, dann nimm stattdessen eine LED. Aber trocken das komplette
Programm entwickeln, auf die fertige Hardware flashen und es läuft wird
nicht passieren.
Eigentlich machts jetzt kaum noch Sinn, das weiter zu kommentieren, wenn
Du es nicht mal ausprobiert hast. :( Aber gut, noch ein paar Hinweise:
Der Timer wird nur ein einziges Mal initialisiert, nämlich zu Beginn des
Programms. In einer Funktion "inc_counter" hat es überhaupt nichts
verloren. Den Rest ersetzt Du durch den Overflow-Interrupt des Timers.
Oder mach meinetwegen einen timer_task() draus, den Du in der
Hauptschleife aufrufst, wenn Dir Interrupts suspekt sind. Aber die
"richtige" Version ist, den Overflow-Interrupt dafür zu nehmen. Schau
mal ins Tutorial, ist wirklich nicht kompliziert.
1
voidcapture_1_play_task(void)
2
{
3
for(inti=0;i<9;i++)
4
{
5
if(timer_counter>recorded_captures[i])
6
{
7
light_toggle();
8
recorded_capture_pos++;
9
}
10
11
if(timer_counter==recorded_captures[i])
12
{
13
break;
14
}
15
}
16
}
Wozu denn eine Schleife? Habe ich oben etwas von einer Schleife
geschrieben? Nein. Du vergleichst timer_counter mit dem aktuellen
Array-Wert. Der aktuelle Array-Wert ist:
1
recorded_captures[recorded_capture_pos]
Dann der zweite Schritt: Wenn das Programm einmal durchgelaufen ist,
soll es doch wieder von vorne beginnen, oder nicht? Du musst also
recorded_capture_pos auch mal wieder auf 0 zurücksezten. Sonst läuft es
nur genau einmal durch.
1
voidkey_task(void)
2
{
3
if(key_pressed(KEY_MANUAL))
4
{
5
if(state!=STATE_CUSTOM_CAPTURE)
6
{
7
state=KEY_MANUAL;
8
}
9
else
10
{
11
state=KEY_CCAP_1;
12
}
13
}
14
15
if(key_pressed(KEY_SIGN_1))
16
{
17
state=KEY_SIGN_1;
18
}
19
if(key_pressed(KEY_SIGN_2))
20
{
21
state=KEY_SIGN_2;
22
}
23
if(key_pressed(KEY_CLEAR))
24
{
25
state=KEY_CLEAR;
26
}
27
28
if(key_pressed(KEY_CCAP_1))
29
{
30
state=KEY_CCAP_1;
31
}
32
}
Wie gesagt, definierte Dir eigene Makros für die Zustände und nimm nicht
die Tastendefinitionen. Es gibt keinen Zustand CLEAR. Wenn Du eine
CLEAR-Taste haben willst, denn würde die einen Zustandsübergang nach
STATE_MANUAL verursachen. Da ist dann das Licht aus (außer man drückt
von Hand die Taste MANUAL). Du kannst dafür aber auch einfach die
MANUAL-Taste nehmen. Wenn man das Programm verlassen will, tippt man
also MANUAL kurz an und das Licht bleibt aus. Dann hast Du eine Taste
frei, um in den Zustand PLAY zu gehen, den Du bisher nie erreichst.
Den else-Fall bei if (state != STATE_CUSTOM_CAPTURE) kannst Du Dir
übrigens sparen. Diese Abfrage soll verhindern, dass man beim
Aufzeichnen einer Sequenz in den Zustand MANUAL umschaltet. Denn das ist
ja nicht gewünscht. Wenn die Taste MANUAL während des Aufzeichnens
gedrückt wird, passiert einfach kein Zustandsübergang.
1
uint8_tkey_pressed(intinput)
2
{
3
if(PINC&(1<<PC0))
4
returnKEY_MANUAL;
5
if(PINC&(1<<PC1))
6
returnKEY_SIGN_1;
7
if(PINC&(1<<PC2))
8
returnKEY_SIGN_2;
9
if(PINC&(1<<PC3))
10
returnKEY_CCAP_1;
11
if(PINC&(1<<PC4))
12
returnKEY_CLEAR;
13
}
OK, Du hast den Code definitiv nicht ausprobiert. Schau Dir die Funktion
mal an, wozu hat die den Parameter input? Den benutzt Du überhaupt
nicht. Die Funktion soll überprüfen, ob die Taste input (nenn es lieber
key) gedrückt ist oder nicht. Wenn diese Taste gerade gedrückt ist,
liefert die Funktion true bzw. 1 zurück und wenn nicht false bzw. 0.
Deine Funktion liefert dagegen die Nummer der erstbesten Taste zurück,
die gedrückt ist ... Das kann nicht funktionieren.
1
while(1)
2
{
3
key_task();
4
switch(state)
5
{
6
caseKEY_MANUAL:manual_task();break;
7
caseKEY_SIGN_1:sign_1_task();break;
8
caseKEY_SIGN_2:sign_2_task();break;
9
caseKEY_CCAP_1:capture_1_task();break;
10
caseKEY_CLEAR:clear();break;
11
default:break;
12
}
13
}
Wieder das gleiche: Dieses switch-Statement ist nicht dazu gedacht, die
Tasten abzufragen! Das passiert schon in key_task(). Sondern es wird der
aktuelle Programmzustand (oder Modus) abgefragt: Geben wir gerade eine
gespeicherte Sequenz aus, nehmen wir gerade eine Sequenz auf oder sind
wir im manuellen Modus? Je nach Modus wird eine andere Funktion
aufgerufen, die das realisiert. Und das in einer Endlosschleife, also
sehr sehr oft pro Sekunde. Anhand des Timers und der MANUAL-Taste
entscheiden diese Funktionen, was mit dem Licht zu tun ist. Die werden
dauernd aufgerufen, auch wenn keine Taste zum Moduswechsel gedrückt
wurde.
Hoffe, es ist jetzt klarer geworden. Wie gesagt: Probier das Programm
aus! Lass die Funktion mit dem Aufzeichnen zunächst weg und stell
sicher, dass die einfachen Funktionen überhaupt erst mal laufen.
Hi Sascha!
Vielen Dank für deinen umfassenden Beitrag, ich werde mich nun dran
machen und meine Fehler anhand deiner tollen Beschreibung beheben.
Ich lade danach den Quellcode hoch!
Gruß
Sascha