Steuern Sie verschiedene Funktionen mit derselben Taste. ARM 7

Ich versuche, ein kleines Stück Code zu implementieren, und kann im Grunde wie folgt vereinfacht werden.

Ich habe drei verschiedene LEDs (zB P0.0, P0.1 & P0.2). Ich habe einen Taster, der beim Drücken zuerst die LED an P0.0 einschalten sollte. Beim erneuten Drücken sollte P0.1 eingeschaltet werden und so weiter. Die LED soll so lange an bleiben, bis der nächste Taster erkannt wird.

Im folgenden Testcode beziehe ich mich auf jede LED als Funktion. Meine Idee war, einen Zähler zu erhöhen und abhängig von der Zählung eine bestimmte LED aufleuchten zu lassen.

Die Ausgabe dieses Codes entspricht nicht meiner Erwartung. Es gibt keinen Übergang zwischen den Funktionen. Irgendwelche Vorschläge, wie ich diesen Code umstrukturieren könnte, wären hilfreich.

Ich möchte keine Interrupts für diesen Code verwenden. Außerdem habe ich keine Entprellung einbezogen, da ich darauf abziele, diesen Code in 15 Minuten von Grund auf neu reproduzieren zu können.

else if ( SW1 != (0x00000002) )  //when pressed     
    {
    delay();  //for debouncing
    count++;
    }   

    if (count == 1) {
        IO0SET = (1<<0);
        pattern1();
}
 else   if (count == 2) {
        IO0SET = (1<<6);
        pattern2();
}
     else   if (count == 3) {
        IO0SET = (1<<7);
        pattern3();
}

Gibt es eine Möglichkeit, die aktuelle Funktion sofort zu beenden, anstatt warten zu müssen, bis sie beendet ist?

Sie lesen den Switch-Zustand einmal am Anfang Ihrer while(1)-Hauptschleife, aber Sie scheinen weiter unten Codezeilen zu haben, die darauf warten, dass er sich ändert. Ihre SW1-Variable ändert sich nicht, bis Sie sie erneut von IO0PIN lesen.
Zusätzlich zu Finbarrs Argument warten Sie auch nicht darauf, dass der Schalter vor dem While losgelassen wird, sodass Ihre While-Bedingung immer falsch ist, da der Code dort ankommt, bevor der Schalter losgelassen wird.
Danke für eure beiden Kommentare. Ich werde versuchen, einige Änderungen entsprechend umzusetzen.

Antworten (2)

Ohne eine grundlegende Entprellung wird es nicht funktionieren, was, wenn Sie keine Interrupts verwenden möchten, eine grundlegende Wartefunktion bedeutet, es sei denn, Sie entprellen in Hardware.

Die beabsichtigte Funktionalität Ihres Codes scheint darin zu bestehen, die eingestellten LED-Funktionen ständig aufzurufen, während die Taste gedrückt wird. Nach Ihrer Beschreibung ist dies nicht erforderlich. Sie können sie einmal aufrufen und dann warten, bis die Taste losgelassen wird. Sie bleiben erleuchtet, bis eine andere LED-Einstellungsfunktion aufgerufen wird.

Wenn Sie schließlich das IO-Register mit 0x02 UND-verknüpfen, ist das Ergebnis entweder 2 oder 0. Anstatt nach einem bestimmten Wert zu suchen, können Sie die c-Konvention verwenden, dass 0 falsch und alle anderen Werte wahr sind, dies macht den Code viel sauberer suchen. Das Verschieben in eine Funktion macht es noch schöner zu lesen.

int SW1Pressed (void) {
  return !(IO0PIN & 0x00000002) //switch connected on P0.1. Low when pressed.
}

....

count = 0;
while (1){
  if (SW1Pressed()) {                         //when pressed
    wait_ms(100);                             // wait 100 ms
    if (SW1Pressed()) {                       // still pressed.
      if (count==0)                           // turn on correct led
        function1();
      else
        function2();

      if (++count == 2)                       // update count
        count = 0;

       while(SW1Pressed())                  // do nothing until the button is released
         ;
    }    
  }
}
Hallo Andreas, danke für deinen Einblick in dieses Thema. Ich habe meinen Code in der ursprünglichen Frage aktualisiert. Der Code funktioniert wie erwartet. Bei jedem Tastendruck gehe ich zur nächsten Funktion. Die Funktion muss jedoch beendet werden. Wenn ich also eine Art LED-Muster habe, das 30 Sekunden dauern kann, muss ich warten, bis es sich ändert. Hast du eine Idee, wie ich sofort wechseln kann? Vielleicht eine Switch-Case-Anweisung?
@JohnSmith Lassen Sie Ihre Anzeigemuster im Hintergrund arbeiten. Sie können dies beispielsweise tun, indem Sie eine Zustandsmaschine mit einem Timer ansteuern. Die Alternative besteht darin, Ihre Musterroutinen mit Schlüsselüberwachungscode zu "salzen", und das halte ich auf lange Sicht für "sehr schlecht". Es ist ein Hack. Es könnte Ihr unmittelbares Problem "innerhalb einer vernünftigen Vorstellung" lösen, aber es ist kein guter Weg, weil sich alles nur in ein Alptraum-Rattennest verwandelt, wenn Sie mehr Code entwickeln. Gehen Sie niemals in dieses Kaninchenloch.
@jonk, ich bin mir nicht 100% sicher, ob ich dich richtig verstehe. Ich werde diese Methoden jedoch nachschlagen und versuchen, sie zu implementieren.
@JohnSmith Wenn Sie mit den Ideen nicht vertraut sind, sollten Sie sich damit vertraut machen. Sie sind ein wichtiges Werkzeug. Brechen Sie Ihre Muster in den kleinsten Zeitraum dazwischen (oder als den größten gemeinsamen Faktor [siehe GCD]) auf. Implementieren Sie dann einen Timer mit dieser Rate. Wenn also ein Muster 15 ms, 12 ms und 30 ms verwendet, wäre Ihr GCD T = 3 ms. Also würdest du deinen Timer dafür einstellen. Dann ist Ihr Timing 5T, 4T und 10T. Einfach zu setzende Zähler für ganze Zahlen. Wenn der Zähler von 5 abläuft, rücken Sie zum nächsten Zustand vor und stellen seinen Zähler auf 4 ein usw. Aber es ist einfach, das Muster jetzt zu beenden (man stoppt vielleicht einfach den Timer?).
@JohnSmith Ihr neuer Code muss warten, bis der Schalter freigegeben wird. Kein Problem, wenn das LED-Muster 30 Sekunden dauert, aber es wird sein, sobald Sie das behoben haben. Wie Jonk angedeutet hat, ist der beste Weg, das LED-Muster zu verlassen, ein Timer-Interrupt mit einer festen Rate, der die LEDs aktualisiert. Ihr Schaltflächencode kann dann diesen Timer entweder starten/stoppen oder eine Variable setzen, die der Timer überprüft, um zu sehen, welches Muster er anzeigen soll.

Ich denke, das grundlegende Problem ist, dass Ihr Code den Schalter nicht entprellt. Beim Drücken eines mechanischen Schalters rattert dieser zunächst schnell auf und zu. Dies führt dazu, dass Ihr Code die verschiedenen Funktionen schnell durchläuft.

Ihr Code enthält unnötige Zustandsprüfungen, die ebenfalls bereinigt werden könnten. Grundsätzlich möchten Sie warten, bis die Taste gedrückt wird, prüfen, ob sie noch 75-100 ms später gedrückt wird, und wenn ja, warten, bis die Taste losgelassen wird, und dann Ihren Funktionszähler erhöhen und loslegen.

Hallo, habe das gemacht, was du gesagt hast. Ich werde meinen Code aktualisieren. Funktioniert gut, außer dass, wenn ich den Schalter drücke, die Funktion noch ausgeführt werden muss, bevor mit der nächsten Funktion fortgefahren wird. Gibt es eine Möglichkeit, dass ich sofort ausbrechen kann, wenn ich den Schalter drücke?
Die Logik zur Steuerung der verschiedenen LEDs könnte etwa so aussehen: If Count ==1 then do this. Wenn Count ==2, dann tun Sie dies. Wenn Count ==3, dann tun Sie dies. Gehen Sie am Ende dieser Bedingungsaussagen einfach zurück zur Überwachung des Tasters.
Ist der neu bearbeitete Code das, wovon Sie sprechen? Ich habe die Codierung eingerichtet und alles funktioniert gut, außer dass ich anscheinend nicht sofort zwischen den Funktionen wechseln kann. Dies bedeutet, dass ich warten muss, bis die aktuelle Funktion beendet ist, bevor das Drücken des Schalters registriert wird.
Normalerweise wäre es der richtige Weg, den Schalter auf einen Interrupt-Eingang zu stellen. Eine Alternative wäre, einen internen Timer-Interrupt zu verwenden, um den Schalter zu überprüfen. Eine weniger attraktive Alternative besteht darin, die Switch-Check-Funktion regelmäßig innerhalb Ihrer längeren Funktionen aufzurufen (insbesondere während interner Warteschleifen).