====== Vermeidung von Kontaktprellung ====== //Vajalikud teadmised: [HW] [[en:hardware:homelab:digi]], [AVR] [[en:avr:io]], [LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]], [PRT] [[en:examples:digi:switch]]// ===== Theorie ===== [{{ :examples:digi:switch:switch_bounce.png?200|Kontaktprellung eines Schalters}}] Wie bereits im einleitenden Kapitel zu Schaltern erwähnt, gibt es im Ungang mit mechanischen Schaltern den Effekt des Prellens (ungewolltes, kurzzeitiges, wiederholtes Öffnen und Schließen eines Kontaktes bei dessen Betätigung). Dieses Problem wird durch die Elastizität des Metalls, aus dem die Schalter bestehen, verursacht. Im Moment des Ein- oder Ausschaltens prellen die Kontakte, was zu einer Vielzahl falscher Schaltungen führt. Die Anzahl und Dauer der Schaltungen hängt von dem Schalter ab, liegt aber gewöhnlich im Bereich von wenigen Millisekunden. Für den Fall, dass ein Schalter genutzt wird, um ein elektronisches Gerät zu starten, hat dieses Problem keine großen Auswirkungen. Wird er jedoch zur Steuerung eines Gerätes verwendet kann mehrfaches Schalten das Gerät beschädigen. [{{ :examples:digi:switch:switch_input_rc_filter.png?200|RC-filter eines Schalters}}] Die bekannteste Methode zur Vermeidung von Kontaktprellung ist die Filtrierung. Dieses kann elektrisch oder durch Software erfolgen. Um elektrisch zu filtern muss der Schalter an einen Tiefpassfilter angeschlossen werden - zum Beispiel an einen RC Filter - welcher die Spannungschwankungen beseitigt sodass der Pin des Mikrocontrollers keine schwankenden Werte erhält. Ein solcher RC Filter ist auf der Zeichnung abgebildet. Filtrierung mittels Software wird durchgeführt, indem dem Pin, an welchem der Schalter angeschlossen ist, ein Wert zugewiesen wird. Bleibt dieser Wert zu verschiedenen Zeitpunkten innerhalb eines zuvor gesetzten Zeitlimits gleich, kann angenommen werden, dass der Schalter stabil ist und kein Flimmer-Problem aufweist. Es muss jedoch bei jeder Art der Filtrierung ein Verzögerungsfaktor bei Definition des Status berücksichtigt werden. ===== Praktisches Beispiel ===== Elektrische Filtrierung wird für die HomeLab Schalter nicht verwendet, da hier die Beseitigung von Fehlschaltungen mit Hilfe von Software geübt werden soll. Die Übung besteht aus zwei Teilen. Das Ziel des ersten Teils ist, das Prellen der Schalter des digitalen Input/Output Moduls zu zeigen. Hierzu wird das folgende Programm genutzt; durch jede Betätigung des Schalters wird die nachfolgende LED aufleuchten. Eine Fehlschaltung lässt die LEDs mehrfach und zufällig aufleuchten. Electrical filtering is not used on HomeLab switches, since it would not allow practicing the elimination of miss switching’s with software. The exercise is in two parts. The goal of the first part is to demonstrate the bouncing of Digital i/o module switches. The following program is used for this; each pressing on the button will light the next LED in line. Wrongly pressed button will causes LEDs to light several times and it appears as the LEDs light randomly. // // Das Programm um Kontaktprellung am digitalen Input/Output Modul zu demonstrieren. // #include // // Festlegung der LED-Pins und Schalter. // pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) }; pin button = PIN(C, 0); // // Hauptprogramm // int main(void) { unsigned char new_value, old_value = 0; unsigned char index, counter = 0; // LED-Pins als Output setzen. for (index = 0; index < 3; index++) { pin_setup_output(leds[index]); } // Schalter-Pins als Input setzen. pin_setup_input(button); // Endlosschleife while (true) { // Status des Schalters auslesen. new_value = pin_get_value(button); // Kontolle, ob der Schalter heruntergedrückt wurde, // was bedeutet, dass der neue Status 1 ist, der alte 0. if ((new_value) && (!old_value)) { // Erweiterung des Lesegerätes und Nutzungvon Modul 3 counter = (counter + 1) % 3; // Aufleuchten der LED, welche mit dem Wert des Lesegerätes übereinstimmt. for (index = 0; index < 3; index++) { pin_set_to(leds[index], index != counter); } } // Berücksichtigung des alten Status. old_value = new_value; } } Es gibt diverse Softwarelösungen zur Filtrierung. Sie können einfach oder komplex sein, wobei jede ihre Vor- und Nachteile hat. Sieht das Programm nur wenige seltene Betätigungen des Schalters vor, kann eine lange Pause als Folge der Betätigung eingefügt werden. Auf diese Weise können durch Kontaktprellung verursachte Wirkungen auf die Schaltung vermieden werden. Jedoch muss bei Anwendung dieser Lösung bedacht werden, dass, sofern der Nutzer den Schalter für eine längere Zeit gedrückt hält, das Programm ebenfalls auf die Fehlschaltung, welche durch Lösen des Schalters hervorgerufen wird, reagiert. Ein Programm, welches den Status des Schalters in einer festgeleten Zeitperiode mehrfach überprüft ist zuverlässiger (das Ergebnis ist umso besser, je länger die Periode und je größer die Anzahl der Kontrollen ist). Nachfolgend ist eine Funktion abgebildet, um filtrierte Werte eines Schalters für das digitale Input/Output Mpdul auszulesen: // // Funktion zum Auslesen filtrierter Werte aus dem I/O Erweiterungsmodul. // unsigned char pin_get_debounced_value(pin button) { unsigned char buffer = 0xAA; unsigned char timeout = 100; // Abwarten, bis der Status des Schalters We wait until the status of the button is celar or clearing the state expires while (timeout-- > 0) { // Having 8 place (bit) bufffer of state. // All previous states (bits) are shifted to left // and a new state(bit) is added to the right. buffer <<= 1; buffer |= (pin_get_value(button) ? 0x01 : 0x00); // If all 8 bits are high, then the button is definitely pressed down if (buffer == 0xFF) { return 1; } // If all 8 bits are low, then the button is definitely up. if (buffer == 0x00) { return 0; } // 1 ms break. // This function can be found from the library of the HomeLab. sw_delay_ms(1); } // If we can not examine the state, then we assume that the button was not pressed. return 0; } Diese Funktion generiert eine Verzögerung durch Nutzung einer Funktion, die in der entsprechenden Übung erläutert wurde. Zu dieser Zeit müssen wir nur wissen, dass die Verzögerungsfunktion eine Verzögerung von 1 ms am Ende jedes Zyklus generiert, um den Status des Schalters lesen zu können. Befindet sich der Schalter 8 Lesezyklen lang in der gleichen Position, If the button is in the same position during 8 readings, it returns to the counted position. In case the button is unstable the entire procedure may take up to 100 ms. This function is included in the library of pins, hence there is no need to add it to the program for passing the example. In order to try this first part of the exercise, it has to be altered a little - include library of generating the delay in the program and at the point where the value of the button was read, directly apply the function with filter. The result is as follows: // // The program for filtering the debounce of buttons of Digital i/o module. // #include #include // // Determining pins of LEDs and buttons. // pin leds[3] = { PIN(C, 5), PIN(C, 4), PIN(C, 3) }; pin button = PIN(C, 0); // // Main program // int main(void) { unsigned char new_value, old_value = 0; unsigned char index, counter = 0; // Setting the pins of LEDs as outputs. for (index = 0; index < 3; index++) { pin_setup_output(leds[index]); } // Setting the pins of button as input. pin_setup_input(button); // Endless loop. while (true) { // Reading the state of the button. new_value = pin_get_debounced_value(button); // Control whether the button was pressed down, that means, // is the new state 1 and the old state 0. if ((!new_value) && (old_value)) { // Widening the counter and taking module number 3. counter = (counter + 1) % 3; // Lighting the LED witch corresponds to the value of the counter. for (index = 0; index < 3; index++) { pin_set_to(leds[index], index != counter); } } // Remember the old state. old_value = new_value; } } Testen wir das Programm nun, leuchten die LEDs in genau der Sequenz auf, in welcher der Nutzer den Schalter betätigt.