Forum: Compiler & IDEs Leuchtschriftsteuerung


von Sascha (Gast)


Angehängte Dateien:

Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

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.

von Sascha (Gast)


Lesenswert?

>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! :)

von Sascha (Gast)


Lesenswert?

>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...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Sascha (Gast)


Lesenswert?

ok,

>Das Problem ist, dass der ganze Codeaufbau nicht stimmt.

Inwiefern?


Gruß
Sascha

von Sascha (Gast)


Lesenswert?

>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?

von Fabian O. (xfr)


Lesenswert?

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

von Sascha (Gast)


Lesenswert?

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ß

von Sascha (Gast)


Angehängte Dateien:

Lesenswert?

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!

von Sascha (Gast)


Lesenswert?

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.

von Fabian O. (xfr)


Lesenswert?

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
static uint8_t state = MANUEL;

Außerdem eine Funktion, die die Tasten auswertet und Zustände wechselt:
1
void key_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
void manual_task(void)
2
{
3
  if (key_pressed(KEY_MANUAL) {
4
    light_on();
5
  } else {
6
    light_off();
7
  }
8
}
9
10
void program_1_task(void)
11
{
12
  if (counter < 10) {
13
    light_on();
14
  } else if (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
    case STATE_MANUAL:
5
      manual_task();
6
      break;
7
    case PROGRAM_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.

von MaWin (Gast)


Lesenswert?

> > 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.

von Sascha (Gast)


Angehängte Dateien:

Lesenswert?

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!

von Fabian O. (xfr)


Lesenswert?

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.

von Sascha (Gast)


Angehängte Dateien:

Lesenswert?

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ß

von Fabian O. (xfr)


Lesenswert?

Dann gehen wir es mal durch:
1
#define KEY_MANUAL    1
2
#define KEY_SIGN_1    2
3
#define KEY_SIGN_2    3
4
#define KEY_CCAP_1    4
5
#define KEY_CLEAR     5
6
7
uint8_t state = 1;
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_t timer_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:
2
uint8_t recorded_captures[10]    = {0,0,0,0,0,0,0,0,0,0};
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
void light_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
void light_toggle(void)
2
{
3
  PORTD ^= (1 << PD0);
4
}

Dann der Task:
1
void sign_1_task(void)
2
{
3
  static uint16_t counter = 0;
4
  if (counter < 10) 
5
  {
6
    light_on();
7
  } 
8
  else if (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
void capture_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:
1
void init_timer(void)
2
{
3
  MCUCR |= (1 << ISC01) | (1 << ISC00);  // Prescaler = F_CPU / 256
4
  TCNT0 |= 0;
5
}
6
7
void inc_counter(void)
8
{
9
  init_timer();
10
  if(TIFR & (1 << TOV0)                
11
  {
12
    timer_counter++;  // Timercounter erhoehen
13
    TIFR |= (1 << TOV0); // // Overflowflag loeschen
14
  }
15
}
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
void capture_1_play_task(void)
2
{
3
  for(int i=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
void key_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_t key_pressed(int input)
2
{
3
  if(PINC & (1 << PC0))
4
    return KEY_MANUAL;
5
  if(PINC & (1 << PC1))
6
    return KEY_SIGN_1;
7
  if(PINC & (1 << PC2))
8
    return KEY_SIGN_2;
9
  if(PINC & (1 << PC3))
10
    return KEY_CCAP_1;
11
  if(PINC & (1 << PC4))
12
    return KEY_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
    case KEY_MANUAL: manual_task();   break;
7
    case KEY_SIGN_1: sign_1_task();   break;
8
    case KEY_SIGN_2: sign_2_task();   break;
9
    case KEY_CCAP_1: capture_1_task();   break;
10
    case KEY_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.

von Sascha (Gast)


Lesenswert?

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

von Sascha (Gast)


Lesenswert?

> Hi Sascha


sorry, habe einen Fehler beim kopieren eines Kommentars gemacht ;)

Doof diese Schizo...

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
Noch kein Account? Hier anmelden.