Donnerstag, 30. April 2020

C - Taster entprellen softwareseitig - Programmcode

Hinweis: Der Code wurde für einen STM32 mit SystemWorkBench geschrieben. 




Wenn du Ihn für Arduino verwenden möchtest, ersetze:


HAL_GetTick(); mit millis();
HAL_GPIO_ReadPin(); mit digitalRead(pin);
while(1) mit void loop()


dann läuft es!





Wieso entprellt man Taster?!

Damit ein Taster an einem Mikrocontroller auch als Taster funktioniert, muss sichergestellt werden, dass er während der Aktivierungszeit vom Programm nur einmal abgefragt wird.

Aufgrund hochfrequenter Programmablaufzyklen wird ein Taster trotz subjektiv kurzer Aktivierungszeit durch das Programm immer mehrfach als aktiv befunden.

Um dies zu verhindern, bedient man sich einem einfachen Trick. In einer if-Abfrage sollen zwei Bedingungen aktiv sein, damit Anweisungen ausgeführt werden: 

Der Taster selbst muss betätigt sein. — Nennen wir ihn B1
Wir fragen eine Variabel (im Beispiel: „a“) auf einen bestimmten Wert ab, und verändern ihn innerhalb der if-Anweisungen. So geraten wir im nächsten Programmzyklus nicht wieder in die Anweisungsliste unserer if-Abfrage. Wird im zweiten Programmzyklus der B1 weiterhin betätigt, wird der Variable „a“ innerhalb der else-Anweisung der Wert von B1, also „1“ zugewiesen. — Solange, bis der Taster losgelassen wird.




int a = 0;

while (1){
  int B1 = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
  
  if (B1==1 && a == 0){
    a++; 
  } 
  else {
     a = B1; 
  }
}



und Wieso noch?

Zusätzlich tritt bei mechanischen Tastern oft, wenn nicht sogar immer, ein Störeffekt namens Prellen auf. Die Betätigung eines elektromechanischen Tasters verursacht kurzzeitig ein mehrfaches Schließen und Öffnen des Kontakts. Die Ursache ist zurückprallen der Schaltkontakte durch die Federung im Taster. Dieser Effekt des mehrfachen Schließen und Öffnen des Kontaktes führt bei schnellen elektronischen Schaltungen, deren zeitliche Auflösung hoch genug ist um das Prellen zu erfassen, zu unerwünschten Mehrfachereignissen.


Bei den Tastern die ich verwendete, wird eine Prellzeit von 10ms angegeben. 
So könnte man beispielsweise eine delay von 15ms innerhalb der if-Anweisungsliste anbringen, um sicher zu gehen, dass das Prellen während der Buttonabfrage nicht auftritt. Allerdings verlangsamen delays immer das gesamte Programm und somit versuche ich sie möglichst zu meiden.





Erklärung der Funktion 

entprellen(tasternr, taster, modus)
tasternr = Fortlaufende Nummer für jeden weiteren verwendten Taster.
taster = Dein Eingangssignal. Zum Beispiel digitalRead(pin).
modus = 0: hold 1: toggle 




Funktion zum entprellen von Tastern mit hold und toggle Funktion


#define b1 HAL_GPIO_ReadPin(b1_GPIO_Port, b1_Pin)

  uint8_t entprellen (int tasternr, int taster, int modus){

  uint64_t zeit1[10];
  uint8_t nur_einmal_zeitabfrage[10];
  uint8_t nur_einemal_burronabfrage[10];
  uint8_t schaltzustand[10];
  uint8_t entprellzeit_in_ms=12; //Meine Taster haben laut Datenblatt eine Prellzeit von 10ms. Daher 12 (Dann ist es auf jeden Fall Sauber)

     if (taster){
    if (!nur_einmal_zeitabfrage[tasternr]){
     nur_einmal_zeitabfrage[tasternr]++;
     zeit1[tasternr]=HAL_GetTick();
    }

    if (taster && HAL_GetTick()-zeit1[tasternr] > entprellzeit_in_ms && nur_einemal_burronabfrage[tasternr]==0){
     nur_einemal_burronabfrage[tasternr]++;

     if (modus){
      if (schaltzustand[tasternr]==0){
       schaltzustand[tasternr]=1;
      }
      else{
       schaltzustand[tasternr]=0;
      }
     }
     else{
      schaltzustand[tasternr]=1;
     }
     my_printf("[%d] - Taster %d wurde betätigt.\n",HAL_GetTick()/1000, tasternr);
   }
   }
   else{
    zeit1[tasternr]=HAL_GetTick();
    nur_einmal_zeitabfrage[tasternr]=0;
    nur_einemal_burronabfrage[tasternr]=0;
    if (!modus){
     schaltzustand[tasternr]=0;
    }
   }
  return schaltzustand[tasternr];
  }

while(1){
  if(entprellen(1,b1,1)){
    led1ein
  }
  else{
    led1aus
  }
}










Keine Kommentare:

Kommentar veröffentlichen