Zählen der Anzahl der Tastendrücke durch externe Unterbrechung

Es ist eine Anforderung, dass ich die Anzahl der Tastendrücke durch externe oder andere Unterbrechungen zählen sollte.

Wenn ich also den externen Interrupt verwende, um den Zähler um 1 zu erhöhen, wird er manchmal um 2 oder 3 aufgrund von Entprellung erhöht. Kann mir jemand sagen, wie man in diesem Fall genau zählt?

void Handle_PB() // my ISR called by pushbutton press falling edge
{
    pb++;
    if(pb>3)
    {  num1=1;
    }
    if(pb>4)
    {  num2=1;
       pb=0;
    }
} 

pb ist der Drucktastenzähler. und num1 und num2 sind Flags.

Nach 4-maligem Drücken der Taste möchte ich also eine andere Aufgabe erledigen. Gleich nach 5-maligem Drücken der Taste möchte ich eine andere Aufgabe erledigen. Wichtig ist also, eine genaue Anzahl von Tastendrücken zu zählen. Ich kenne das Entprellprinzip. Aber wo kann ich diesen Entprellverzögerungscode einfügen, da er unterbrechungsgesteuert ist?

Sie können einfach eine Verzögerung von beispielsweise 50 ms nach dem ersten Bounce hinzufügen, wenn Ihr Programm mit so viel Verzögerung zufrieden ist. Das ist keine sehr gute Lösung, aber es könnte funktionieren.
Können Sie eine externe Entprellschaltung hinzufügen und den GPIO für die Erkennung steigender Flanken einstellen?
Ich denke, Sie sind besser dran, um abzustimmen. Ich habe es immer getan, indem ich überprüft habe, ob ein Wert zwei Abfragen hintereinander gleich ist (wenn ich Druckschalter für die menschliche Schnittstelle mache), und das hat immer perfekt funktioniert. Sie können einen Timer verwenden, um diese Abfrage durchzuführen, den Wert protokollieren und dann in der Hauptschleife überprüfen oder einfach innerhalb der Hauptschleife abfragen.
Ich kann keine externe Schaltung verwenden. Und ich muss es per externem Interrupt machen, da es ein zeitkritisches Projekt ist. Ich kann mir keinen ISR leisten, nur um einen Druckknopf abzufragen.
Wie zeitkritisch ist Ihr Projekt genau? Verfügt die MCU über Hardware-Timer, die Sie verwenden können?
Was Sie sagen, ergibt keinen Sinn. Wenn Sie dafür einen externen Interrupt verwenden, verwenden Sie eine ISR. Sie würden stattdessen einen Timer-Interrupt verwenden .

Antworten (3)

1) Es ist besser, wenn Sie das Entprellen in der Hardware selbst erledigen können. Legen Sie, wenn möglich, einen geeigneten Kondensator auf den Interrupt-Pin auf Masse.

2) In Software können Sie wie folgt vorgehen: (Angenommen, das Springen kann bis zu 50 Sekunden dauern)

void my_interrupt_handler()
{
 interrupt_time = currentmilliseconds();

 if (interrupt_time - last_interrupt_time > 50) 
 {
   press++;
   last_interrupt_time = interrupt_time;
 }

}

last_interrupt_time hat den Anfangswert 0. Der Code erhöht den Druckwert für den allerersten Druck. Aber es wird nicht für 50 ms inkrementiert, egal wie viele Tasten-Interrupts aufgrund von Prellen dazwischen kommen. Dies funktioniert nur dann effizient, wenn der Mikrocontroller Interrupts innerhalb von Interrupts unterstützt, andernfalls besteht die Möglichkeit, dass der Timer-Überlauf-Interrupt fehlt.

3) Eine andere Methode besteht darin, einfach eine Verzögerung von 50 ms nach dem Erhöhen von press hinzuzufügen . Es klappt. Aber keine gute Methode.

4) Eine andere Idee, indem Sie eine Flag-Variable verwenden:

void my_interrupt_handler()
    {     
      if (flag == 0)
         { 
          press++;
          flag = 1 
         }
    }

flag ist eine flüchtige Variable, die von main() und ISR geteilt wird. Der Code ist in main() so geschrieben, dass er das Flag erst wieder auf 0 initialisiert, nachdem 50 ms gezählt wurden. Das ist also wie das Deaktivieren von Tastenunterbrechungen für 50 ms. Wie auch immer, Menschen können nicht schneller drücken.

"Es ist immer besser, wenn wir das Entprellen in der Hardware selbst erledigen können." Falsch! In Fällen, in denen Sie bereits einen Mikrocontroller haben, ist es sinnvoll, dass dieser auch die Entprellung übernimmt. Es benötigt nur einen Bruchteil der Rechenleistung der meisten modernen Mikros. Das Hinzufügen von Hardware würde nur Größe, Gewicht und Kosten ohne Nutzen erhöhen.

Sie müssen das tun, was Entprellen genannt wird . Es gibt viele Möglichkeiten, und es gibt sicherlich viel darüber geschrieben.

Die Methode, die ich normalerweise verwende, besteht darin, einen neuen Zustand nicht als gültig zu betrachten, bis der Eingang 50 aufeinanderfolgende 1-ms-Takt-Interrupts in diesem Zustand war. 50 ms sind länger, als die meisten Schalter zurückprallen, sind aber in menschlicher Zeit immer noch augenblicklich. Anders ausgedrückt, ein Mensch wird eine Verzögerung von 50 ms zwischen dem Drücken einer Taste und dem Auftreten einer Aktion nicht bemerken.

In seltenen Fällen, in denen das System schneller als die Entprellzeit des mechanischen Schalters reagieren muss, können Sie die erste Zustandsänderung auslösen und dann neue Zustandsänderungen blockieren, bis sich die vorhandene Änderung eingestellt hat. Dies gibt Ihnen fast keine Latenz, macht das System jedoch anfällig für kurze Störungen. Sie müssen entscheiden, was wirklich wichtig ist.

Denken Sie auch hier daran, dass Verzögerungen von bis zu etwa 50 ms von menschlichen Benutzern unbemerkt bleiben.

Können Sie mir sagen, wie ich hier Debounce implementieren kann, weil ich Interrupt verwende? Alle Spitzen rufen sofort meinen ISR an.
@litunbls, Sie können innerhalb der ISR warten (obwohl es im Allgemeinen eine schlechte Praxis ist, eine ISR zu blockieren), neue Interrupts sollten die ISR nicht erneut auslösen.
Ich bin etwas verwirrt, ob das Verzögern von 30-50 ms innerhalb von ISR eine geeignete Methode ist, da es sich um eine sehr zeitkritische Anwendung handelt.
@lit: In der ISR zu warten ist eine schlechte Idee. Wie gesagt, ich habe normalerweise einen periodischen 1-ms-Interrupt. Dies ist oft aus verschiedenen Gründen sinnvoll. Eines der Dinge, die dieser Interrupt tut, ist zu zählen, ob sich jeder Schaltereingang für 50 aufeinanderfolgende Interrupts im selben Zustand befunden hat.
@litunbls, wenn es zeitkritisch ist, haben Sie keine andere Wahl, als den Schaltflächenstatus abzufragen. Sie könnten jedoch bis zur ersten steigenden Flanke warten und dann einen Timer einrichten, der 50 ms später ausgeht, um den Status erneut zu überprüfen. Wenn der Zustand noch gleich ist - super! Die Taste wird gedrückt. Sie können ein Flag in Ihrem Button press ISR halten, um anzuzeigen, ob Sie bereits warten oder ob Sie den Timer starten müssen, oder Sie können den Button ISR deaktivieren, wenn Sie auf den Timer warten, damit Sie nicht auf die von Ihnen angelegten Interrupts reagieren müssen egal.

Es ist schwierig, eine Lösung vorzuschlagen, ohne zu wissen, um welche Art von MCU es sich handelt. Hast du einen Timer oder Systick?

Vielleicht so etwas:

volatile unsigned long PBStart;

void Handle_PB() // my ISR called by pushbutton press falling edge
{
    if (getSysTickTimer() - PBStart > 50)   // Where 50 is some threshold like 50ms       
    {
        PBStart = 0;
    }

    if (PBStart == 0)   // Is ok to count
    { 
        PBStart = getSysTickTimer();

        pb++;
        if(pb>3)
        {  num1=1;
        }
        if(pb>4)
        {  num2=1;
           pb=0;
        }
    }
} 
Es funktioniert ähnlich wie beim Abfragen mit einem Timer-Interrupt. Ich möchte nicht 2 ISR ausführen, nur um die Tastendrücke zu zählen. Gibt es eine Möglichkeit, dies durch nur einen externen Interrupt zu tun, der durch einen Druckknopf ausgelöst wird, der sich auch um das Entprellen kümmert?
Ist es eine gute Idee, den Pin dreimal hintereinander innerhalb des Interrupts zu lesen und wenn das logische ODER aller 3 Ergebnisse 0 ist, dann den Zähler zu erhöhen? Kann jemand eine andere Out-of-Box-Idee vorschlagen?
Sie brauchen keine zwei ISR. getSysTickTimer() kann nur die Timer-Zählung zurückgeben. Wenn Sie einen freien Timer haben, stellen Sie ihn einfach mit einem hohen Prescaler ein (damit er langsam ist) und lesen Sie einfach seinen Wert (keine ISR erforderlich). Auch hier weiß ich nicht, über welche MCU wir sprechen. Ist ARM oder AVR? 32 oder 8bit? In Bezug auf das fortlaufende Lesen ist dies möglicherweise keine Lösung. Stellen Sie sich vor, Sie drücken die Taste, Sie gehen zum ISR, dann lesen Sie 10 Mal die Taste. Wie lange wird es dauern? Wenige hundert Nanosekunden? Es kann zu schnell sein, um eine Entprellung durchzuführen. Können Sie einfach so etwas wie delay_ms() in ISR verwenden? Und dann den Knopf ein paar Mal lesen?
Sie benötigen einige zusätzliche Ressourcen, um das Entprellen durchzuführen. Timer oder Verzögerungsfunktion oder irgendetwas. Wenn Sie nicht möchten, können Sie vielleicht Hardware-Entprellen mit Kondensator verwenden?