Forum: Compiler & IDEs Externes Interrupt / Led mit Taster ein-u. ausschalten


von Tho W. (tommyprog)



Lesenswert?

Grüß Euch,

bin neu hier im Forum (eher Anfänger), um ein aktuelles Problem mit 
eurer Hilfe zu lösen, da ich nicht weiter komme.

                              Hardware:

- myAVR Board Mk2 (aus den myAVR Einsteigerset) mit einen Atmet ATmega8
- dieses Board ist mit einen selbstgebautem Adapterkabel (anstelle der 
grünen Platine) mit einen
AVRISP MK2 Programmer verbunden
- Der Programmer ist über ein USB Kabel mit den Rechner verbunden
- Entwicklungsumgebung ist das Atmel Studio 6
- Konstat- Spannungsversorgung: Voltcraft DPS-4005PFC 9.01V, 0.009A im 
Idle

                            Ziel:
Eine LED auf Anschluss PIN B0 soll über einen Taster1 auf Pin D2 ein- 
und ausgeschaltet werden.
Anfangs soll die rote led nicht leuchten.
Wird Taster gedrückt (UND LOSGELASSEN FÜR EINE UNBESTIMMTE ZEIT), so 
geht die LED an.
WIRD nun in einen beliebigen Intervall nochmals gedrückt, geht die LED 
aus.

Realisiert werden soll das ganze durch einen externen Interrupt über 
INT0_ect auf Pin4 auf'n Atmel.

Es dürfen keine Delays verwendet werden, auf Nesting soll verzichtet 
werden.

                           Problem:

1. Anfangs leuchtet nichts. --> OK
2. Bei drücken von TAster 1 leuchet die rote led --> OK
3. bei drücken von Taster 1 geht die rote led wieder aus --> OK
4. Manchmal geht bei drücken von Taster 1 die Rote led garnicht aus, 
obwohl sie davor an war --> NICHT OK

--> Manchmal realisiert er den Tastendruck nicht. Funktionen für das 
Entprellen habe ich bereits in meinem Code drin (taster_was_pressed und 
taster_was_pressed2()).
Die Taster_was_pressed- methode geht jedoch nicht, sie funktionert aber 
in einen anderen Programm tadellos.
Die ausdokumentierte Methode "taster_was_pressed" funktioniert, nimmt 
jedoch nicht jeden Tastendruck war.


Artikel wie

Beitrag "Unterbrechung mit Taster"
Beitrag "Entprellen für Anfänger"
Beitrag "Interrupt Taster "flackert""

die über das entprellen und interrupt handeln, sind mir bekannt, aber 
ich komme nicht weiter!
Könnte mir bitte jemand von euch helfen?

Vielen Dank.

Mit freundlichen Grüßen,
tommyProg
                       >>>>CODE IM ANHANG<<<<

von Tho W. (tommyprog)


Lesenswert?

Ergänzend müsste ich noch erwähnen, dass ich den Interrupt aktuelle von 
einer fallenden Flanke (High auf Low) programmiert habe, da der Schalter 
auf Logisch 0 ist, wenn dieser gedrückt wird.

Mit freundlichen Grüßen,
TommyProg

von Daniel V. (danvet)


Lesenswert?

Hast du das schon gelesen?:
http://www.mikrocontroller.net/articles/Entprellung

Ich kann bei dir nirgends eine Entprellung sehen.

von Tho W. (tommyprog)


Lesenswert?

*** Ergänzend:
Dank der Debounce Methode von Peter 
(http://www.mikrocontroller.net/attachment/67964/debounce.c)

funktioniert das System einwandfrei.

Einziges Problem ist, dass in dieser Methode ein _delay_us(xx) drin ist.
Ein Delay darf ich eben nicht benutzen^^.

von Justus S. (jussa)


Lesenswert?

Daniel V. schrieb:
> Ich kann bei dir nirgends eine Entprellung sehen.

wahrscheinlich meint er sein konfuses sei() und cli()-Konstrukt ist eine 
Entprellung...

von Tho W. (tommyprog)


Lesenswert?

@Daniel

Ja, ich hatte diesen Artikel gelesen. Scheinbar hat mir der Anhang mein 
längeeres Codestück nicht mitgenommen.

Ich poste es einfach mal hier:

*************************************************************
1
bool taster_was_pressed2(int input_port,int input_bit)        //Funktion, um den Taster 1 auf Status "gedrückt" zu prüfen
2
{
3
  int state=0;                            //Deklariere Statusvariable
4
  while(1)                            //while- Schleife, da er die Statusse immer wieder überprüfen muss
5
  {
6
    if ((state==0) &&(!(input_port&(1<<input_bit))))      //wenn der Schalter davor noch nicht gedrückt wurde, und wenn er gerade gedrückt wird
7
    {
8
      state=1;                        //setze den Status auf 1 (einmal gedrückt)
9
    }
10
    else
11
    {
12
      if((state==1) && (!(input_port&(1<<input_bit))))    //wenn der Schalter davor gedrückt worden ist, und der Taster noch gedrückt wird,
13
      {                            //also der Schalter gehalten wird
14
        state=2;                      //setze den Status auf 2
15
      }
16
      else
17
      {
18
        if((state==1||state==2) &&(!(input_port&(1<<input_bit))))    //fast gleiches wie darüber, nur der Taster kann auch länger gehalten werden
19
        {
20
          state=2;                    //status zurücksetzen
21
        }
22
        else
23
        {
24
          if((state==2) &&(input_port&(1<<input_bit)))  //erst wenn der Taster gehalten worden ist, und losgelassen wurde, wird
25
          {                        //der Schalter offiziell als gedrückt gemeldet
26
            state=0;                  //und der Status wieder für die nächst Tastendruckprüfung auf 0 gesetzt
27
            return true;
28
          }
29
          else
30
          {
31
            return false;                //ist nichts gedrückt, wird false als ergebnis zurückgeliefert
32
          }
33
        }
34
      }
35
    }
36
  }
37
}
**********************************************************************

Diese Funktion nimmt auch das entprellen weg, funktioniert aber 
scheinbar in diesem Problemfall überhaupt nicht.


Mfg,
tommyProg

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

@Justus

Nein, das sei() und cli() ist keine Entprellung.
Es wird damit das global interrupt enable im SREG- Register gesetzt und 
geweils gelöscht.
Dies ist mir bewusst.

Entprellung war wie gesagt meine letzte Funktion "taster_was_pressed2". 
Meines Achtens macht die Funktion "taster_was_pressed" aber auch die 
entprellung, oder irre ich mich da?

dennoch danke euch ;)

Mfg,
tommyProg

von Justus S. (jussa)


Lesenswert?

Tho Wes schrieb:
> oder irre ich mich da?

und wie...

von Tho W. (tommyprog)


Lesenswert?

@justus

Dann sag mir bitte genau, was die Funktion "taster_was_pressed" bewirkt.

Mfg,
tommyProg

von AVR-Großmeister (Gast)


Lesenswert?

Wieso machst du deine Hausaufgaben eigentlich nicht komplett selbst, die 
Aufgabenstellung ist doch trivial. Wenn dir das Forum das löst ist der 
Lerneffekt gleich null.

von Justus S. (jussa)


Lesenswert?

Tho Wes schrieb:
> Dann sag mir bitte genau, was die Funktion "taster_was_pressed" bewirkt.

omg. kann es sein, dass du gar nicht weißt, wie sich Prellen auswirkt?

von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:
> @justus
>
> Dann sag mir bitte genau, was die Funktion "taster_was_pressed" bewirkt.

keine Ahnung, müsste man genauer analysieren.
Auf jeden Fall ist es keine Entprellung, denn Entprellung bedeutet 
immer, dass es in irgendeiner Form eine hinreichend lange Zeitkomponente 
geben muss und die kommt in dieser Funktion nun mal nicht vor. Da werden 
ein paar Status Variablen hin und her geschoben und irgendwann mündet 
das dann in einem der beiden returns. Da dieses hin und herschieben aber 
um Zehnerpotenzen schneller geht als das Tastenprellen, ist irgendeiner 
der returns erreicht noch ehe der Taster mechanisch überhaupt eine 
Chance hatte zu prellen. qed.

Ich kann mich nur immer wieder wiederholen.
Die PeDa Entprellung mittels Timer-Interrupt ist zwar nicht leicht zu 
verstehen, dafür aber in der Anwendung äusserst simpel
1
....
2
3
   // Initialisierung aus dem PeDa Code übernehmen
4
5
   while( 1 ) {
6
7
     if( get_key_press( 1 << KEY ) )
8
       PORTB ^= ( 1 << PB0 );   // oder wo auch immer die LED sitzt
9
   }
10
}

fertig. Einfacher gehts nicht mehr. Einfach die Codeteile aus dem PeDa 
Code übernehmen, die #define auf die eigenen Verhältnisse anpassen. In 5 
Minuten hat man funktionierende Taster, die alle Stückeln spielen, die 
man je brauchen wird.

Und nein. Den Kern des PeDa Codes muss man auch nicht verstehen um ihn 
zu verwenden. Könntest du eine Funktion schreiben, die eine Wurzel aus 
einer Zahl zieht? Nein? Dann dürftest du der 'ich benutze nur Dinge, die 
ich auch verstehe' Doktrin nach auch eine sqrt() Funktion nicht 
benutzen.

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

AVR-Großmeister schrieb im Beitrag #3825917:
> Wieso machst du deine Hausaufgaben eigentlich nicht komplett selbst, die
mach ich, aber nun häng ich, und schein von etwas nicht soviel ahnung zu 
haben. Deshalb bitte ich um Hilfe. Über Tipps würde ich mich auch 
freuen, bruache ja net gleich die Lösung


>Wenn dir das Forum das löst ist der
> Lerneffekt gleich null.

Das ist nicht ganz richtig, wenn ich die Lösung nachvollziehen kann, 
habe ich auch möglichkeiten aufgefasst, wie man ein Problem umsetzt. 
Aber das ist eher jetzt nicht relevant.
Ich bröchte nen Tipp, vlt. von dir


mfg,Thomas

von Justus S. (jussa)


Lesenswert?

Karl Heinz schrieb:
> Die PeDa Entprellung mittels Timer-Interrupt ist zwar nicht leicht zu
> verstehen, dafür aber in der Anwendung äusserst simpel

das hier ist aber doch offensichtlich eine Hausaufgabe oder so, also 
wird er "seinen" Code auch erklären können müssen...und wenn er schon 
nicht versteht, was seine eigene kurze Funktion macht, wird er bei PeDas 
Entprellung erst recht nicht durchsteigen...

von Karl H. (kbuchegg)


Lesenswert?

Justus Skorps schrieb:
> Karl Heinz schrieb:
>> Die PeDa Entprellung mittels Timer-Interrupt ist zwar nicht leicht zu
>> verstehen, dafür aber in der Anwendung äusserst simpel
>
> das hier ist aber doch offensichtlich eine Hausaufgabe oder so, also
> wird er "seinen" Code auch erklären können müssen...und wenn er schon
> nicht versteht, was seine eigene kurze Funktion macht, wird er bei PeDas
> Entprellung erst recht nicht durchsteigen...

Im Artikel Entprellung ist die PeDa Entprellung dem Prinzip nach 
auch erklärt und ich hab auch mal eine Langform dafür geschrieben, die 
nicht so dicht gepackt ist und eigentlich nicht schwer verständlich sein 
sollte. Ist ja schliesslich nur ein Zähler pro Taster und ein bischen 
Logik in einem Timer-Interrupt, die bestimmt wann der Zähler um 1 
verringert bzw. rückgesetzt wird.

Am Timer allerdings führt kein Weg vorbei.
Entprellung ist unmittelbar mit einer zeitlichen Komponente verknüpft. 
Und da gibt es nur 2 Möglichkeiten. Entweder delay oder Timer. Wenn 
delay nicht erlaubt ist, bleibt nur Timer. Was ja auch die vernünftigere 
der beiden Lösungen ist.

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

> keine Ahnung, müsste man genauer analysieren.
> Auf jeden Fall ist es keine Entprellung, denn Entprellung bedeutet
> immer, dass es in irgendeiner Form eine hinreichend lange Zeitkomponente
> geben muss

das warten habe ich doch eigentlich in den geschweiften klammern bei dem 
while in der funktion taster_was_pressed eingebaut
da steht das so da:

while (!(PIND&(1 << input_bit))) {}                //geht das nicht ?


>Da dieses hin und herschieben aber
> um Zehnerpotenzen schneller geht als das Tastenprellen, ist irgendeiner
> der returns erreicht noch ehe der Taster mechanisch überhaupt eine
> Chance hatte zu prellen. qed.

Das war mir nicht bewusst, danke.








> Ich kann mich nur immer wieder wiederholen.
> Die PeDa Entprellung mittels Timer-Interrupt ist zwar nicht leicht zu
> verstehen, dafür aber in der Anwendung äusserst simpel
Ah okay, danke dir für den Tipp. Timer- Interrupts darf ich noch nicht 
verwenden, muss noch die externen Interrupts verwenden, so ist die 
Aufgabenstellung xD. Aber ich schaus mir zusätzlich an, danke dir.

von Karl H. (kbuchegg)


Lesenswert?

Justus Skorps schrieb:
> Tho Wes schrieb:
>> Dann sag mir bitte genau, was die Funktion "taster_was_pressed" bewirkt.
>
> omg. kann es sein, dass du gar nicht weißt, wie sich Prellen auswirkt?

Das könnte allerdings sein, dass es hier ein gewaltiges 
Begriffs-Missverständnis gibt.

von Tho W. (tommyprog)


Lesenswert?

> Am Timer allerdings führt kein Weg vorbei.
> Entprellung ist unmittelbar mit einer zeitlichen Komponente verknüpft.
> Und da gibt es nur 2 Möglichkeiten. Entweder delay oder Timer. Wenn
> delay nicht erlaubt ist, bleibt nur Timer. Was ja auch die vernünftigere
> der beiden Lösungen ist.

Ah, da ist der Groschen gefallen, das wusste ich garnicht. Wollte das 
ganze ohne zeit realisieren.
Man merkt's das das forum was bringt^^.
Nochmals danke, und dann sage ich mal topic closed hier im forum, und 
ich schau mir nochmals die Beiträge an.

von AVR-Großmeister (Gast)


Lesenswert?

Tho Wes schrieb:
> Das ist nicht ganz richtig, wenn ich die Lösung nachvollziehen kann,
> habe ich auch möglichkeiten aufgefasst, wie man ein Problem umsetzt.

Das ist der falsche Ansatz. Selbst auf die Lösung kommen ist extrem 
wichtig!
Lösung produzieren -> Fehler finden, verstehen, lösen -> Lösung 2 
produzieren -> Fehler finden und verstehen -> ... and so on. Deine 
Variante lässt dich spätestens dann scheitern, wenn es dir keiner 
vorkaut und es mal keine fertige Lösung (hallo reale Welt!) gibt und 
eigene Kreativität gefragt ist.

Das Forum hat dir doch eigentlich alles geliefert.
Ich kaue mal vor:
1) Verstehe was Prellen macht. Verstehe den Unterschied zwischen langem 
Tastendruck und Prellen. Jetzt solltest du wissen wieso deine Methode 
nicht zur Entprellung beigetragen hat.
2) Erkennen, dass man zur Entprellung nach einem Tastendruck eine 
gewisse Zeit weitere Tastendrücke ignorieren sollte
3a) Fertige Methoden zur Entprellung nehmen (das MC Wiki liefert da ja x 
Varianten)
oder
3b) Eigenen Code dafür schreiben
 -> da Delay Funktionen nicht erlaubt sind, Warten nach einem 
Tastendruck per Timer realisieren.

von AVR-Großmeister (Gast)


Lesenswert?

Ah zu spät.

Wenn du weder Timer noch Delay verwenden darfst, bietet dir das MC Wiki 
ja die Flankenerkennung an, die ohne Zeitkomponente auskommt (aber hier 
u.U. ungenügend ist).

von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

> Ah okay, danke dir für den Tipp. Timer- Interrupts darf ich noch nicht
> verwenden, muss noch die externen Interrupts verwenden, so ist die
> Aufgabenstellung xD. Aber ich schaus mir zusätzlich an, danke dir.


Wenn du Timer nicht benutzen darfst, delay nicht erlaubt ist, dann gibt 
es keine Software-Lösung für das Entprell-Problem.

Bist du sicher, dass du Entprellen überhaupt behandeln musst? Denn 
Entprellen macht das Problem schweirig. Kann man Entprellen ignorieren 
(was in Produktionscode natürlich unsinnig ist, aber man kann ja nicht 
alles auf einmal lernen), dann ist eine Tastenerkennung nichts anderes 
als eine Flankenerkennung. Die wiederrum ist einfach zu realisieren.
Kurz und gut: Bist du sicher, dass du selbst nicht eine einfache 
Hausaufgabe eigentlich schwieriger machst, als sie sein muss? Einfach 
nur, weil du eine Perfektion erreichen willst, die du mit deinem Wissen 
noch gar nicht erreichen kannst?

(Denn Hand aufs Herz. Der Code im Eröffnungsposting ist ziemlich konfus)

Weiters: Ist das hier
> Realisiert werden soll das ganze durch einen externen Interrupt über INT0_ect 
auf Pin4 auf'n Atmel.

Teil der Aufgabenstellung oder ist es etwas, was du selbst ins Spiel 
gebracht hast, in der Annahme das ein externer Interrupt dir helfen 
kann?

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

Karl Heinz schrieb:

> Wenn du Timer nicht benutzen darfst, delay nicht erlaubt ist, dann gibt
> es keine Software-Lösung für das Entprell-Problem.
Okay


> Bist du sicher, dass du Entprellen überhaupt behandeln musst?
Ja, ich muss das Entprellen (verhindern des"Nachschwingens" eines 
schalters) behandeln.

> Entprellen macht das Problem schweirig. Kann man Entprellen ignorieren
> (was in Produktionscode natürlich unsinnig ist, aber man kann ja nicht
> alles auf einmal lernen), dann ist eine Tastenerkennung nichts anderes
> als eine Flankenerkennung. Die wiederrum ist einfach zu realisieren.

Flankenerkennung wollte ich auch durchsetzen,indem ich mein MCUCR auf 
fallende Flanke programmiert hab.
Drücke ich jedoch den Taster, so muss ich manchmal mehrmals den Taster 
drücken, dass das passiert, was ich haben will.

> Kurz und gut: Bist du sicher, dass du selbst nicht eine einfache
> Hausaufgabe eigentlich schwieriger machst, als sie sein muss? Einfach
> nur, weil du eine Perfektion erreichen willst, die du mit deinem Wissen
> noch gar nicht erreichen kannst?

Es ist keine Hausaufgabe, sondern eine Einarbeitung in das Thema.
Ja, da könntest du recht haben. Aber ich versuch auch viel zu 
dokumentieren udn zu vereinfachen, wie es nur geht.

> Weiters: Ist das hier
>> Realisiert werden soll das ganze durch einen externen Interrupt über INT0_ect
> auf Pin4 auf'n Atmel.

> Teil der Aufgabenstellung oder ist es etwas, was du selbst ins Spiel
> gebracht hast, in der Annahme das ein externer Interrupt dir helfen
> kann?

Das ist die Aufgabenstellung. Der Pin4 ist ja der PIND2 auf den Board, 
und somit hängt da der Schalter dran, der Auf masse schaltet.
Durch das Drücken des Schalters wird ein Interrupt ausgelöst.

von M. N. (Gast)


Lesenswert?

Karl Heinz schrieb:
> Am Timer allerdings führt kein Weg vorbei.
> Entprellung ist unmittelbar mit einer zeitlichen Komponente verknüpft.
> Und da gibt es nur 2 Möglichkeiten. Entweder delay oder Timer.

Es gibt noch eine weitere Möglichkeit, nämlich ein RC-Glied zu 
verwenden. Ein Beitrag dazu steht in der Codesammlung. Ich will hier 
aber nicht Alles wieder vorkauen.

von Karl H. (kbuchegg)


Lesenswert?

M. N. schrieb:
> Karl Heinz schrieb:
>> Am Timer allerdings führt kein Weg vorbei.
>> Entprellung ist unmittelbar mit einer zeitlichen Komponente verknüpft.
>> Und da gibt es nur 2 Möglichkeiten. Entweder delay oder Timer.
>
> Es gibt noch eine weitere Möglichkeit, nämlich ein RC-Glied zu
> verwenden.

Schon klar.
Ich hatte mich dann in weitere Folge noch auf die zusätzliche 
Einschränkung 'in Software' geeinigt. Damit sind Hardware-Lösungen in 
dieser Einschränkungen automatisch nicht mit drinnen.
Ausserdem hat er sein Board erwähnt und ich ging davon aus, dass eine 
Board-Modifikation nicht erlaubt ist.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Karl Heinz schrieb:
> Wenn du Timer nicht benutzen darfst, delay nicht erlaubt ist, dann gibt
> es keine Software-Lösung für das Entprell-Problem.

Es gibt immer eine Lösung:

1
#ifndef F_CPU
2
  #error F_CPU not defined.
3
#endif
4
5
#include <avr/io.h>
6
#include <avr/interrupt.h>   
7
8
volatile long nDebounce = 0;
9
10
#define DEBOUNCE F_CPU / 400
11
12
int main(void)
13
{
14
  DDRB |= (1 << 0);
15
  PORTD |= (1 << 2);
16
  EIMSK |= (1 << INT0);
17
  sei();
18
19
  while(1)
20
  {
21
    if(nDebounce == DEBOUNCE)
22
    {
23
      PINB |= (1 << 0);
24
      nDebounce++;
25
    }
26
    
27
    if((nDebounce != DEBOUNCE) && (PIND & (1 << 2))) nDebounce = 0;
28
  }
29
}
30
31
ISR(INT0_vect)
32
{
33
  if (nDebounce < DEBOUNCE) nDebounce++;
34
}

Bisschen doof ist nur, dass er unbedingt den Interrupt benutzen muss.

mfg.

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

Danke auch Dir für die Info, aber ich hätte dazu mal einige Fragen.
(Hab das Problem wie gesagt bereits mit der Debounce- Methode vom PeDa 
gelöst)

>   EIMSK |= (1 << INT0);
Für welches Register steht EIMSK? Im Atmega8 Datenblatt kontte ich es 
nicht finden. Ist damit das GICR gemeint?

Warum teilst du anfangs die F_CPU exakt durch 400?..Es könnten auch 500 
oder 800 sein..

Mit freundlichen Grüßen,
TommyProg

von Thomas E. (thomase)


Lesenswert?

Tho Wes schrieb:
> Für welches Register steht EIMSK? Im Atmega8 Datenblatt kontte ich es
> nicht finden. Ist damit das GICR gemeint?

Das ist Atmega48..328. Beim 8er ist das GICR.

Tho Wes schrieb:
> Warum teilst du anfangs die F_CPU exakt durch 400?..Es könnten auch 500
> oder 800 sein..

Die 400 habe ich eingesetzt, damit man das mit der Hand testen kann. 
Wenn man mit dem Finger den Specht macht, wird das weggefiltert. Der 
Wert darf gern etwas grösser sein.

Die Funktion ist nicht unbedingt zur Nachahmung empfohlen. Ich wollte 
nur zeigen, dass es ohne Delay und Timer auch geht.

mfg.

von Tho W. (tommyprog)


Lesenswert?

ah okay, trotzdem danke^^.

Mfg,
tommyProg

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.