Forum: Mikrocontroller und Digitale Elektronik Leds mit gleichen Taster durchschalten


von Alex (Gast)


Lesenswert?

Hallo! Ich bin ein Anfänger in der  Microkontrollerprogrammierung. Ich 
habe sämtliche Beiträge angesehen, aber keiner konnte mich weiter 
bringen. Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster 
zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck 
leuchtet nächste Led. Ich habe myAVR mk2 board. Hier ist ein mehr oder 
weniger passender 
Beitrag(Beitrag "Taster als Schalter"), aber das 
bringt mich nicht weiter. Hier ist mein Quellcode mit einem Led. Ich 
wäre dankbar, wenn jemand den Quellcode vervollständigen könnte oder 
neuer Code mit Timer oder anderem Lösung schreibt.

Alex
1
#include <avr/io.h>
2
3
4
int main(void)
5
{
6
  DDRB|=(1<<PD3)|(1<<PD4)|(1<<PD5);// Pin 3,4,5 im Port B auf Ausgang 
7
  DDRB&=~(1<<PD0); // Pin 0 im Port B auf Eingang (Taster)
8
  PORTB|=(1<<PD0); // Pull-Up aktivieren
9
    while(1)
10
    {
11
        if (!(PINB&(1<<PB0))) // Taster Abfrage high oder low?
12
        {
13
      PORTB|=(1<<PB3); // Led an
14
        }
15
  else 
16
  {
17
    PORTB&=~(1<<PB3); // Ansonsten Led aus
18
  }
19
    
20
  // Code soll weiter gehen: nach nächsten gleichen Tastendruck soll
21
  //Led an PD4 an gehen, und nach nächsten GLEICHEN Tastenbetätigung Led an PD5
22
  //wie soll die Code weiterlaufen?
23
    }// Ende while Schleife
24
}// Ende main

: Bearbeitet durch User
von Markus G. (mgebha)


Lesenswert?

Zerlege die Aufgabe in kleinere Teile , die Du leichter 
lösen/beherrschen kannst, z.B.:

- zähle mit jedem Tastendruck einen Zähler hoch

- lass die zum jeweiligen Zäherstand passende LED leuchten

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Alex schrieb:
> // Code soll weiter gehen: nach nächsten gleichen Tastendruck soll
>   //Led an PD4 an gehen, und nach nächsten GLEICHEN Tastenbetätigung Led
> an PD5
>   //wie soll die Code weiterlaufen?

 Was hat PD4 an PortB zu suchen ? Wenn schon PortB, dann PB4.
 Code einrücken.
 Arithmetische und Logische Operationen mit einem Leerzeichen trennen.


 Erst einmal eine Variable deklarieren:
1
  uint8t TasterCnt = 3;

 Der Else Teil deiner if Abfrage ist auch unnötig, also:
1
    while(1)
2
    {
3
        if (!(PINB & (1<<PB0)))      // Taster Abfrage high oder low?
4
        {
5
          PORTB &=~(1<<TasterCnt);   // Led aus
6
          TasterCnt += 1;
7
          if (TasterCnt > 5)
8
              TasterCnt = 3;  
9
          PORTB |= (1<<TasterCnt);   // Led an
10
        }
11
    }// Ende while Schleife

 Normale Taster prellen gern, das muss man auch berücksichtigen.

von mx (Gast)


Lesenswert?

So wie der Code jetzt ist, braucht es keine Entprellung, denn er stellt 
eh einen Zufallsgenerator dar. ;)

von oldmax (Gast)


Lesenswert?

Hi
Ich kenne nicht dein Board und auch deine Sprache ist nicht mein Ding, 
aber prinzipiell solltest du deine Aufgabe in Module packen. Dazu 
benötigst du ein paar Variablen. Nur keine Angst, das kostet nix extra, 
macht die Arbeit etwas leichter. Beginnen wir mit dem Einlesen der 
Eingänge. Auch wenn du hier nur einen Eingang hast, macht es Sinn, eine 
Variable zu benutzen und dort die Bits für Eingänge abzulegen. Dazu 
schreibst du eine eigene Routine z.B. Read_IO. In einer Variablen New_In 
legst du nun das Bit des Tasters an. Hast du später mal mehrere 
Eingänge, packst du diese in die Variable. Nun mußt du entprellen. Dazu 
schaffst du dir 2 Variablen, eine für ein Zeitzähler und eine für einen 
Spiegel der Variablen New_In. Also z.B.Deb_Time als Zählvariable und 
In_Debounce für den Spiegel der Variablen New_In. Die Routine zum 
Entprellen prüft mit einer Exclusiv-Veroderung, ob zwischen New_In und 
In_Debounce ein Unterschied ist. Das erkennst du sehr leicht, da die 
unterschiedlichen Bits im Ergebnis "1" sind. Hast du Unterschiede, setzt 
du den Zeitzähler auf einen Wert, der ca. 10 - 20 ms bedeuten sollte und 
kopierst den Wert von New_In nach In_Debounce. Ist beim nächsten 
Durchlauf der Entprellroutine könnte nun der Inhalt von New_In und 
In_Debounce gleich sein, dann zählst du den zeitzähler runter. Hat er 
bis 0 gezählt, hast du keineunterschiedlichen Informationen in den 
beiden Variablen mehr gehabt und das Eingangssignal ( die Eingänge ) ist 
(sind) stabil. Nun kopierst du New_In in eine Variable Akt_In für den 
aktuellen Portwert.
Um nun eine einmalige Aktion durchzuführen, LED 1x weiterschalten, mußt 
du eine Flankenauswertung machen. Auch das ist mit einer 
Exclusiv-Veroderung und einer Spiegelvariable machbar. Zusätzlich 
brauchst du eine Flankenvariable. In einer Routine zur Flankenbildung 
werden Alt_In und Akt_In Exclusiv verodert. Ergebnisbit ist "1", wenn 
ein Unterschied erkannt wird. Das Ergebnis verundest du wieder mit dem 
Inhalt von Akt_In. Klar, nur "1" und "1" ergibt eine "1". Wenn also das 
veränderte Bit in Akt_In eine "1" hat, dann ist ein Signalwechsel auf 
"1" erfolgt, also Taste gedrückt. Dieses Bit legst du in eine 
Ereignisvariable Event_1 ab.
Nun brauchst du nur noch die Routine, um ein Bit in einer weiteren 
Variable zu schieben, um dann diese den Ausgängen mit der LED 
zuzuweisen. Auf eines solltest du achten: Taster sind nicht selten auf 
GND bezogen, um die internen PullUp-Widerstände zu nutzen. Das bedeutet, 
ein betätigter Taster (Kontakt) entspricht einer "0", also ganz 
entgegengesetzt dem Verständnis "Taster gedrückt" = "1" ! Daher muss 
dann in der Einleseroutine das Bit entsprechend gedreht werden, um im 
Programm mit der "1"-Logik zu arbeiten. Hier nochmal grob die 
Main-Routine mit den Aufrufen der einzelnen Subroutinen
Main
   Aufruf Eingänge lesen. Ergebnis in der Variablen New_In
   Aufruf Entprellen. Benutzte Var. New_In, In_Debounce und Deb_Time
                      Ergebnnis in Akt_In
   Aufruf Flankenbilden benutzte Var. Akt_In, Alt_In
                      Ergebnis in Event_1
   Aufruf Eventbearbeitung
              Eventbit prüfen, Arbeitsvariable schieben, Eventbit 
löschen
   Aufruf Ausgabe der Arbeitsvariablen an den Port
Sprung zu MAin (Hauptschleife)
Nun hast du 5 überschaubare Subroutinen zu erstellen. Fällt dir eine 
weitere Verwendung ein oder ein weiteres Experiment, ist die Anpassung 
durch neue Subroutinen oder Änderung bestehender überhaupt kein Problemm 
mehr.
Gruß oldmax

von alex (Gast)


Lesenswert?

@oldmax

Hallo oldmax!
Danke für deine Mühe, du hast so viel geschrieben, ich bin Anfänger und 
etwa in der Mitte von deiner Erklärung stieg ich ab, tut mir leid. Für 
mich wäre ein Teil von Quellcode mit Kommentaren hilfreicher.  Ansonsten 
es ist egal was für ein Board ich habe, Quellcode kann ich zu meinem 
Atmega8 auf dem myAVR mk2  Board anpassen.

von Alex (Gast)


Lesenswert?

!!!!!! schrieb im Beitrag #3880070:
> Du Depp !

Jemanden Depp  und fauler Hund zu nennen nur weil er um Hilfe bietet 
finde ich mega gemein!  Ich dachte dieser Forum existiert hier nicht 
dafür um jemanden zu beleidigen, sondern um Erfahrungen auszutauschen 
und jemanden Helfen, der nicht weiter weist. Ich habe erst vor zwei 
Monaten damit angefangen, und davor habe ich nur gehört, dass es Sprache 
C überhaupt gibt vor allem habe ich noch nie etwas programmiert. Oder du 
denkst, dass  ich keine Tutorial von mickrokontroller.net nicht 
durchgearbeitet habe, weil ich fauler Hund  bin? Wenn du mir zeigst wo 
im Tutorial genau mein Problem beschrieben ist, dann nehme ich alles 
zurück! Bis jetzt habe ich gefunden, wie man einen Taster abfragt. Wenn 
du keine Lust und vor allem nicht weist wie das geht, dann lass es sein 
mit dienen Beleidigungen vom Sofa.

von Bitflüsterer (Gast)


Lesenswert?

Jedenfalls wird hier kein Code eben mal vervollständigt - vor allem wenn 
er so weit vom Ziel entfernt ist. Vielmehr wird hier Hilfe zur 
Selbsthilfe geleistet.

Was Dir wahrscheinlich fehlt, ist ein Verständnis für die Grundprobleme 
Deines Vorhabens.

Siehe dazu: http://www.mikrocontroller.net/articles/Entprellung
und: http://www.mikrocontroller.net/articles/Bitmanipulation

Wäre es anders, würde man nämlich erwarten, dass Du wenigstens in Prosa 
den Ablauf, wie er sein soll, erklären könntest. Es fehlt im übrigen 
eine Erklärung welches Problem Du konkret hast.

So hat Deine Frage eine gewisse Ähnlichkeit zu solchen, die zwecks 
effizienter Erledigung einer Hausarbeit eben mal nach 'nem Code fragen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Alex schrieb:
> Jemanden Depp  und fauler Hund zu nennen nur weil er um Hilfe bietet
> finde ich mega gemein!  Ich dachte dieser Forum existiert hier nicht
> dafür um jemanden zu beleidigen, sondern um Erfahrungen auszutauschen
> und jemanden Helfen, der nicht weiter weist.

 Also, nochmal:
1
 volatile uint8t TasterCnt = PB3; // Falls du das mal in der ISR abfragen willst
2
3
    while(1)
4
    {
5
        if (!(PINB & (1<<PB0)))      // Taster Abfrage high oder low?
6
        {
7
          PORTB &=~(1<<TasterCnt);   // Led aus
8
          TasterCnt += 1;
9
          if (TasterCnt > PB5)
10
              TasterCnt = PB3;  
11
          PORTB |= (1<<TasterCnt);   // Led an
12
         /* Normale Taster prellen gern, das muss man auch berücksichtigen,
13
           deshalb hier 50mS warten, ist nicht schlimm, LED ist schon an.
14
           Sollte man in der ISR nicht machen, aber hier ist es OK*/
15
          _delay_ms(50);
16
        }
17
    }// Ende while Schleife
 Ist dir damit geholfen ?

 EDIT:
 Taster sind normalerweise auf High, beim drücken gehen die auf Low, so
 kann man interne Pullups benutzen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Marc Vesely schrieb:

>  Ist dir damit geholfen ?

Kaum.

Der springende Punkt ist die Unterscheidung zwischen der "Erkennung 
einer gedrückten Taste" und der "Erkennung eines Tastendrucks".

Er braucht letzteres, da hilft es ihm auch nichts, wenn du ihm ersteres 
anbietest.
Das Problem: Das Erkennen eines Tastendrucks ist an und für sich nicht 
so schwer (Flankenerkennung), wenn da nicht das Tstenprellen wäre.

@TO
stell diese konkrete AUfgabe noch zurück. Das Erkennen einer gedrückten 
Taste ist leicht. Das zuverlässige Erkennen eines Tastendrucks ist 
hingegen ungleich schwieriger. Und genau letzteres würdest du aber 
brauchen. Solange du noch nicht mehr Erfahrung hast, stell alle Aufgaben 
zurück, oder bau die Aufgabenstellung um, die darauf basieren, dass 
durch durch einmaliges Drücken einer Taste eine Aktion ein einziges mal 
(und NUR ein einziges mal) auslöst.

von Alex (Gast)


Lesenswert?

OK.  Ich versuche mal anders rum. Als erste schreibe ich was ich schon 
kann. Ich verstehe zu 100% wie man Bitmanipulationen gemacht werden. Ich 
verstehe das Problem von Tasten Entprällung, das werde ich dem Code 
hinzufügen. Ich bewege mich jetzt auf dem Niveau: Leds an und ausmachen, 
Lauflicht, eben mit mehreren Tasten.  Ich möchte folgendes lernen: Mit 
einem Taster hintereinander bestimmte Aufgaben ausführen. Zum Beispiel 
ich möchte folgendes Algorithmus haben: Tastendrück #1 = „Lauflicht 5 
Leds“, Tastendrück  #2  = „Led 1 und 3 an“, Tastendrück  #3 = „alle 5 
Leds blinken lassen“,  Tastendrück  #4 = „alle Leds aus“, mit dem 
nächsten Tastendrück wird alles wiederholt. Wenn das nicht geht, dann 
schreibt das bitte!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Karl Heinz schrieb:
> Der springende Punkt ist die Unterscheidung zwischen der "Erkennung
> einer gedrückten Taste" und der "Erkennung eines Tastendrucks".
>
> Er braucht letzteres, da hilft es ihm auch nichts, wenn du ihm ersteres
> anbietest.

 Hmmm.
 Sehe ich ein bisschen anders.
 Er ist Anfänger, wird wohl kaum etwas mit Interrupts und Flanken
 anfangen können.
 Durch _delay_ms(50) wartet er Tasterprellen ab, beim nächsten Durchgang
 wird wieder nur auf Tasterdruck reagiert, also praktisch auf Flanke.

 Somit ist seine Aufgabe:

Alex schrieb:
> Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster
> zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck
> leuchtet nächste Led.
 gelöst, oder irre ich mich ?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Alex schrieb:
> einem Taster hintereinander bestimmte Aufgaben ausführen. Zum Beispiel
> ich möchte folgendes Algorithmus haben: Tastendrück #1 = „Lauflicht 5
> Leds“, Tastendrück  #2  = „Led 1 und 3 an“, Tastendrück  #3 = „alle 5
> Leds blinken lassen“,  Tastendrück  #4 = „alle Leds aus“, mit dem
> nächsten Tastendrück wird alles wiederholt. Wenn das nicht geht, dann
> schreibt das bitte!

 Wenn du das willst, dann schreibt das bitte!
 Ich wiederhole mich, aber das war deine Frage am Anfang:

Alex schrieb:
> Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster
> zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck
> leuchtet nächste Led.

 Was willst du jetzt nun ?

von Karl H. (kbuchegg)


Lesenswert?

Alex schrieb:


> Lauflicht, eben mit mehreren Tasten.  Ich möchte folgendes lernen: Mit
> einem Taster hintereinander bestimmte Aufgaben ausführen.

Das ist schon der zweite SChritt vor dem ersten.
Der erste Schritt lautet:
Wie kann ich einen Tastendruck erkennen?

Und die Antwort drauf ist an und für sich einfach.
Ein Tastendruck kennzeichnet sich dadurch, dass die Taste vorher noch 
nicht gedrückt war, jetzt ist sie aber gedrückt. Es ist genau dieser 
UNterschied im 'Status' des Tasters, der deinem Programm sagt: Jetzt hat 
der Benutzer die Taste niedergedrückt.

Die Erkennung dieses Wechsels ist an und für sich einfach: In einer 
Variablen merkt man sich immer den Zustand von 'vorher'. In der 
Hauptschleife wird dann der Zustand 'Jetzt' mit dem Zustand 'VOrher' 
verglichen und wenn sich die beiden Unterscheiden, dann muss es einen 
Tastendruck gegegeben haben
1
uint8_t vorher;
2
uint8_t jetzt;
3
4
int main()
5
{
6
  ....
7
8
  if( PINB & ( 1 << PB0 ) )
9
    vorher = 1;
10
  else
11
    vorher = 0;
12
13
  while( 1 )
14
  {
15
    if( PINB & ( 1 << PB0 ) )
16
      jetzt = 1;
17
    else
18
      jetzt = 0;
19
20
    if( vorher != jetzt )    // Unterschied! Taste wurde gedrückt
21
    {
22
      vorher = jetzt;        // merken, damit im nächsten Durchlauf
23
                             // beim Vergleich nicht mehr reagiert wird
24
                             // sondern erst wieder beim nächsten
25
                             // WEchsel
26
27
      if( jetzt == 0 )       // Was war das eigentlich? Niederdrücken
28
                             // oder Loslassen
29
                             // Wir wollen nur niederdrücken. Wie die Taste
30
                             // jetzt steht, verrät uns diese INformation
31
      {
32
        .... mach was
33
      }
34
    }
35
36
    ....
37
  }
38
}

Im Prinzip also nicht schwer. Eine simple Flankenerkennung.
Wenn da nicht das Tastenprellen wäre.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Marc Vesely schrieb:

>  Hmmm.
>  Sehe ich ein bisschen anders.
>  Er ist Anfänger, wird wohl kaum etwas mit Interrupts und Flanken
>  anfangen können.
>  Durch _delay_ms(50) wartet er Tasterprellen ab, beim nächsten Durchgang
>  wird wieder nur auf Tasterdruck reagiert, also praktisch auf Flanke.

Als normaler Benutzer drückst du eine Taste und lässt sie wieder los in 
50 Millisekunden?

von Alex (Gast)


Lesenswert?

Marc Vesely schrieb:
> Ich wiederhole mich, aber das war deine Frage am Anfang:
>
> Alex schrieb:
>> Ich möchte folgende Aufgabe lösen: Mit einem einzigen Taster
>> zwischen LEDs umschalten, das heißt, dass nach jedem Tastendruck
>> leuchtet nächste Led.
>
>  Was willst du jetzt nun ?

Danke sehr! Ich habe erste Variante von dir ausprobiert. Es 
funktionierte. Nur die zweite Variante mit _delay_ms(50) hat nicht 
funktioniert. So sieht es aus: (ich weiß nicht was ich da falsch ist?)
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#define F_CPU 8000000
4
5
int main(void)
6
{
7
  volatile uint8_t TasterCnt = PB3; // Falls du das mal in der ISR abfragen willst
8
9
    while(1)
10
    {
11
        if (!(PINB & (1<<PB0)))      // Taster Abfrage high oder low?
12
        {
13
          PORTB &=~(1<<TasterCnt);   // Led aus
14
          TasterCnt += 1;
15
          if (TasterCnt > PB5)
16
              TasterCnt = PB3;  
17
          PORTB |= (1<<TasterCnt);   // Led an
18
         /* Normale Taster prellen gern, das muss man auch berücksichtigen,
19
           deshalb hier 50mS warten, ist nicht schlimm, LED ist schon an.
20
           Sollte man in der ISR nicht machen, aber hier ist es OK*/
21
          _delay_ms(50);
22
        }
23
    }//
24
  }

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Karl Heinz schrieb:
> Als normaler Benutzer drückst du eine Taste und lässt sie wieder los in
> 50 Millisekunden?

 LOL.
 Ich schaffe es, aber du hast natürlich Recht.
   a) Delay für normale Benutzer verlängern ?
   b) Hast du schon gepostet, erübrigt sich.

 Und für das, was er jetzt machen will, braucht er sowieso Interrupts
 und state machine.

von Karl H. (kbuchegg)


Lesenswert?

Marc Vesely schrieb:
> Karl Heinz schrieb:
>> Als normaler Benutzer drückst du eine Taste und lässt sie wieder los in
>> 50 Millisekunden?
>
>  LOL.
>  Ich schaffe es, aber du hast natürlich Recht.
>    a) Delay für normale Benutzer verlängern ?
>    b) Hast du schon gepostet, erübrigt sich.
>
>  Und für das, was er jetzt machen will, braucht er sowieso Interrupts
>  und state machine.


Und Timer.
Spätestens bei 'Blinken' (oder irgendwann mal 'Lauflicht') kommt er mit 
delays nicht mehr weit.

von Alex (Gast)


Lesenswert?

Karl Heinz schrieb:
> Die Erkennung dieses Wechsels ist an und für sich einfach: In einer
> Variablen merkt man sich immer den Zustand von 'vorher'. In der
> Hauptschleife wird dann der Zustand 'Jetzt' mit dem Zustand 'VOrher'
> verglichen und wenn sich die beiden Unterscheiden, dann muss es einen
> Tastendruck gegegeben haben

Danke! Klasse! Ich versuche es mit dem Quellcode auch! Ich bin jetzt auf 
jedem Fall weiter als noch vor 5 Tagen.

Marc Vesely schrieb:
> Und für das, was er jetzt machen will, braucht er sowieso Interrupts
>  und state machine.

Wie würde der Code mit Interrupts aussehen? Kompliziert?

von Bitflüsterer (Gast)


Lesenswert?

> Wie würde der Code mit Interrupts aussehen? Kompliziert?

An und für sich nicht. Schau mal hier:

http://www.mikrocontroller.net/articles/Interrupt

Insbesondere der Abschnitt 
http://www.mikrocontroller.net/articles/Interrupt#Steuersignale_zwischen_ISR_und_Hauptprogramm 
zeigt Dir ein einfaches Beispiel, mit dem Du erstmal eine LED zum 
Blinken bringen kannst.

Zu dem Stichwort: "Statemachine" siehe hier: 
http://www.mikrocontroller.net/articles/Statemachine

von Bitflüsterer (Gast)


Lesenswert?

Das:

> Insbesondere der Abschnitt
> http://www.mikrocontroller.net/articles/Interrupt#...
> zeigt Dir ein einfaches Beispiel, mit dem Du erstmal eine LED zum
> Blinken bringen kannst

sollte eigentlich heissen:

Insbesondere der Abschnitt
http://www.mikrocontroller.net/articles/Interrupt#...
zeigt Dir ein einfaches Beispiel, mit dem Du erstmal eine LED zum
Blinken bringen kannst, indem Du die Anweisungen für die LED einfügst 
und Dir den Zeitabstand der Interrupts anpasst, bzw. eine Zählvariable 
verwendest. Fortgeschrittene machen das mit der Flag-Variable.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Alex schrieb:
> Wie würde der Code mit Interrupts aussehen? Kompliziert?

 Kommt darauf an.
 Aber wie der Karl Heinz sagte, du wirst dann auch einen Timer brauchen.
 Im Prinzip:
 Interrupt wird auf fallende Flanke eingestellt, wenn eine erkannt wird,
 werden entsprechende Flags gesetzt, unter anderem:
  a) Flag für gedrückten Taster.
  b) Flag für Timer, damit die Prellzeit abgezählt werden kann. Während
     dieser (Prell-) Zeit, wird ISR gleich wieder verlassen. Dieser Flag
     wird wiederum in der Timerroutine zurückgesetzt.
  c) Wenn du willst, kannst du auch Interrupt umdrehen, d.h. deine ISR
     wird nun auf steigende, statt auf fallende Flanke feuern.

 Aber nicht gleich übertreiben. Mit einfachem Beispiel anfangen, später
 komplizieren, noch später alles wegschmeissen und neu anfangen...

von Thomas E. (thomase)


Lesenswert?

Marc Vesely schrieb:
> Interrupt wird auf fallende Flanke eingestellt, wenn eine erkannt wird,
>  werden entsprechende Flags gesetzt, unter anderem:
Jetzt erzähl ihm doch nicht so einen Scheiss.

Alex schrieb:
> Wie würde der Code mit Interrupts aussehen? Kompliziert?

Eher einfacher. Aber Interrupts, genauer einen Interrupt, stehen erst an 
zweiter Stelle.
Was du brauchst ist ein vernünftiges Timing, um deinem bisher frei 
laufenden Controller Manieren beizubringen.
Dazu brauchst du einen Timer. Mit Hilfe dieses Timers führst du in der 
Mainloop zyklisch diverse Aufgaben aus. Das kann man ganz einfach mit 
einem Interrupt machen. Es geht aber auch ohne.
Eine dieser Aufgaben ist das Einlesen der Taster.

Arbeite nacheinander die Artikel zu Timern und zu Entprellung durch. 
Wenn du es schaffst per Tastendruck eine Variable sicher hochzuzählen, 
hast du die meisten Probleme, die dein Controller dir jetzt bereitet und 
in Zukunft bereiten wird, gelöst.

mfg.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas Eckmann schrieb:
>> Interrupt wird auf fallende Flanke eingestellt, wenn eine erkannt wird,
>>  werden entsprechende Flags gesetzt, unter anderem:
> Jetzt erzähl ihm doch nicht so einen Scheiss.

 Schon wieder schlechte Laune ?

von Peter D. (peda)


Lesenswert?

Marc Vesely schrieb:
> Interrupt wird auf fallende Flanke eingestellt

Wozu?

Drückst Du die Taste nicht, hast Du erstmal auch keine Interrupts.

Es sei denn, Du kommst mit dem elektrostatisch geladenen Pullover dem 
Taster zu nahe. Dann hast Du Interrupts ohne Drücken.

Drückst Du die Taste, kriegst Du zwar Interrupts. Die Anzahl hat 
allerdings nur entfernt mit der Anzahl der Drücke zu tun.


Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste 
Lösungsversuch.

: Bearbeitet durch User
von hp-freund (Gast)


Lesenswert?

Vielleicht ist es am Anfang einfacher wenn es einem jemand zeigt und 
erklärt:

http://www.youtube.com/watch?v=MCrFHswqD60&list=PLg8rGAQEOsuh9ZCwP6aW5ycCM5PFFqoNe&index=2

in den weiteren videos kommen dann Interrupt, Timer, ADC usw.

von oldmax (Gast)


Angehängte Dateien:

Lesenswert?

Hi
Was ist denn so schnell, das man taster mit Interrupts einlesen muss? 
Was ist so kompliziert, das ein Delay von 50 ms für ein Entprellen von 
Eingängen Probleme macht? Natürlich sind Timer irgendwann einmal 
nützlich oder gar wichtig, doch dieses Vorhaben ist doch so banal, das 
mit ein wenig nachdenken ein Programm nach meiner Anleitung durchaus 
auch von einem blutigen Anfänger erstellt werden kann. K.H.B. hat es 
ebenfalls gesagt, wie eine Flanke ermittelt wird. Wenn Bitmannipulation 
kein Problem sind, wo ist dann das Problem? Alex, ich hab dir den Ablauf 
erklärt. Ein Programm ist eine Endlosschleife und ackert immer wieder 
die gleichen Befehle ab. Die Kunst ist nun zu erfassen, was sich ändert 
und darauf zu reagieren. Ändern kann sich nur etwas von außen, also 
werden erst mal Informationen eingelesen. Nun werden die Änderungen 
untersucht und behandelt. Das ist die Verarbeitung und schließlich 
wollen wir ja wissen, was nun das Ergebnis dieser Verarbeitung ist, 
sowas nennt man dann Ausgabe oder kurz EVA-Prinzip. Nun kannst du 
ellenlange ineinander verschachtelte Programme schreiben und dann den 
Durchblick verlieren oder du machst eine Schleife in der du immer wieder 
Routinen aufrufst, die Einlesen, Verarbeiten und Ausgeben. Da ich dir in 
C nicht mit Code dienen kann, hab ich dir die Blöcke genannt, die du dir 
zu Herzen nehmen solltest und auch, wie es funktioniert, das man einen 
Eingang irgendwann in einem stabilen Status hat. Wie eine 
Flankenerkennung aufgebaut ist  und wie daraus eine Event- oder 
Ereignisbearbeitung abgeleitet wird. Was du in der Ereignisbearbeitung 
machst ist dein Job. Schau dir mal die Skizze an. Da wird deutlich, das 
es keine Kunst ist, mit kleinen Programmblöcken ein umfangreiches 
Programm zu schreiben, nur das du dabei die Übersicht nicht verlierst. 
Grad als Anfänger solltest du dich mit diesen kleinen Aufgaben vertraut 
machen.
Gruß oldmax

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter Dannegger schrieb:
>> Interrupt wird auf fallende Flanke eingestellt
>
> Wozu?
>
> Drückst Du die Taste nicht, hast Du erstmal auch keine Interrupts.
 So soll es auch sein, was genau wolltest du andeuten ?

Peter Dannegger schrieb:
> Drückst Du die Taste, kriegst Du zwar Interrupts. Die Anzahl hat
> allerdings nur entfernt mit der Anzahl der Drücke zu tun.
 Deswegen nimmt man Prellzeit und während dieser Zeit wird ISR zwar
 angesprungen, aber auch gleich wieder verlassen.

Peter Dannegger schrieb:
> Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste
> Lösungsversuch.
 Natürlich nicht.
 Der arme Timer kann (und soll) nicht die ganze Arbeit übernehmen.
 Bei mir schuftet der auch am meisten, aber ein einziges Flag, welches
 in der Taster-ISR gesetzt wird, sagt ihm, dass er einen ganzen Code-
 block überspringen soll.

von Peter D. (peda)


Lesenswert?

Marc Vesely schrieb:
> Der arme Timer kann (und soll) nicht die ganze Arbeit übernehmen.
>  Bei mir schuftet der auch am meisten

Ja, mein Timer beschwert sich auch ständig, daß er so wenig zu tun hat.
Wenn man ganz nah mit dem Ohr an den MC geht, ist ein leises Schnarchen 
zu hören.

Die Entprellroutine braucht im Timerinterrupt 28 Zyklen für 1..8 Tasten. 
Das sind zusätzliche 0,04% CPU-Last bei 10ms Timerrate und F_CPU = 8MHz.
Hat der Timer nichts anderes zu tun, kommen noch die 41 Zyklen 
Interruptoverhead hinzu, das ergibt insgesamt stolze 0,09% CPU-Last.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter Dannegger schrieb:
> Die Entprellroutine braucht im Timerinterrupt 28 Zyklen für 1..8 Tasten.
> Das sind zusätzliche 0,04% CPU-Last bei 10ms Timerrate und F_CPU = 8MHz.

 Mein Timer muss 10 Mal so viel schuften.
 Ich kenne deine Entprellroutine, habe nichts daran auszusetzen, nur ist
 diese Routine etwas, dass der TO verwenden, aber z.Zt. wahrschenlich
 nicht ganz verstehen kann.
 Was ich sagen will:
 Wenn der TO etwas braucht das funktioniert, kann er deine Routine
 nehmen. Wenn er aber etwas lernen oder selbst versuchen soll, ist die
 Aussage:
 "Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste
 Lösungsversuch." nicht angebracht.
 Erstens ist das nicht der Fall und zweitens, wie du selber sagst, dein
 Timer feuert alle 10ms.
 Flankeninterrupt reagiert aber nach 3-4 Taktzyklen und das kann
 manchmal ziemlich wichtig sein.
 Was aber wichtiger ist:
 Timer arbeitet (bei mir) in Codeblocks, ohne zu wissen wie das alles
 hardwaremässig funktioniert. Ein Flag bleibt ein Flag, auch wenn sich
 entsprechendes PortPin oder sogar ganzes Port geändert hat. Oder man
 einen Taster durch einen Lichtsensor ersetzt hat.
 Man kann alles in Timer ISR abfragen, aber das wäre dann der denkbar
 ungeeignetste Lösungsversuch. Deswegen hat ATMEL den neueren uC für
 jedes Portpin ein PCI spendiert.
 Timer ISR soll koordinieren, nicht die ganze Arbeit verrichten.

von Peter D. (peda)


Lesenswert?

Marc Vesely schrieb:
> Wenn er aber etwas lernen oder selbst versuchen soll, ist die
>  Aussage:
>  "Der Flankeninterrupt ist für Tasten daher der denkbar ungeeignetste
>  Lösungsversuch." nicht angebracht.

Ist nur meine persönliche Erfahrung, daß externe Interrupts viel Ärger 
machen und besonders für Anfänger deren Probleme schwer zu verstehen und 
zu bereinigen sind.
Neben dem Prellen auch die ESD-Empfindlichkeit bei längeren Leitungen 
oder zu Bedienelementen.
Und wenn man dazu doch noch den Timerinterrupt braucht, ist das auch von 
der Software her deutlich aufwendiger.

Ich benutze externe Interrupts daher nur zum Aufwachen oder für 
zeitkritische Sachen (externe Ethernet-, CAN-Controller).

Tasten sind aus MC-Sicht alles mögliche, aber nicht zeitkritisch.

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.