{"id":722,"date":"2022-01-28T14:31:58","date_gmt":"2022-01-28T13:31:58","guid":{"rendered":"https:\/\/followthescore.org\/schueler-labor\/?page_id=722"},"modified":"2022-01-28T17:54:30","modified_gmt":"2022-01-28T16:54:30","slug":"arduino-keyboard-mit-16-tasten","status":"publish","type":"page","link":"https:\/\/followthescore.org\/schueler-labor\/arduino-keyboard-mit-16-tasten\/","title":{"rendered":"Arduino Keyboard mit 16 Tasten"},"content":{"rendered":"\n<p>Es gibt f\u00fcr den Arduino (bzw. ganz generell) ein Keyboard aus 4 x 4 Tasten, welches es erlaubt, eine gedr\u00fcckte Taste \u00fcber eine analoge Spannung zu identifizieren. Das Keyboard beruht auf einer Widerstandsmatrix. Die Versorgungsspannung (3.3 Volt, nicht 5 Volt) wird je nach gedr\u00fcckter Taste in einem bestimmten Verh\u00e4ltnis geteilt, so dass man beim Abfragen an einem analogen GPIO Werte zwischen 0 (keine Taste gedr\u00fcckt) und  ca. 600 .. 4096 erh\u00e4lt, je nachdem, welche Taste gedr\u00fcckt wurde.<\/p>\n\n\n\n<p><em>AUFGABE:<\/em> <strong>Miss diese Spannungen mit einem Voltmeter und erstelle eine entsprechende Tabelle! Markiere die Mitte zwischen den jeweiligen Intervallen und benutze dieser Werte zur Entscheidung dar\u00fcber, welche Taste gedr\u00fcckt ist.<\/strong><\/p>\n\n\n\n<p>Wenn man \u00fcber ein Case-Statement oder \u00fcber einen Array diese Wert zur Entscheidung benutzt, sollte es eigentlich ein Leichtes sein, die jeweilige Taste zu identifizieren.<\/p>\n\n\n\n<p>In der Praxis zeigt es sich jedoch, dass dies nur f\u00fcr bestimmte Tasten robust funktioniert, die <strong>relativ gro\u00dfe Spannungen<\/strong> liefern.<\/p>\n\n\n\n<p>Bei manchen Tasten liegen hingegen die Spannungswerte, die man ermittelt, so nahe beieinander, dass durch die <strong>\u00dcberlagerung mit Netzbrumm-Anteilen <\/strong>auch schon mal eine falsche Taste ermittelt werden kann. Au\u00dferdem k\u00f6nne fremde Elektroger\u00e4te (z.B. Staubsauger) st\u00f6rende Spannungsimpulse in das Netz abgeben, die zu Messfehlern f\u00fchren.<\/p>\n\n\n\n<p>Man sollte daher einige <strong>Stichproben<\/strong> hintereinander durchf\u00fchren und dann den <strong>Mittelwert<\/strong> bilden.<\/p>\n\n\n\n<p>Im Idealfall k\u00f6nnte man z.B. 10 Stichproben im Abstand von 2 msec verwenden, dann w\u00fcrden sich die Wechselspannungsanteile mathematisch bei einer Durchschnittsbildung kompensieren.<\/p>\n\n\n\n<p>Der Nachteil einer solchen L\u00f6sung ist jedoch, dass man dazu den Prozessor f\u00fcr 20 msec blockieren w\u00fcrde, nur um die Tastatur abzufragen. F\u00fcr einen Regelungsprozess kann das schon eine zu gro\u00dfe Einschr\u00e4nkung sein.<\/p>\n\n\n\n<p>Besser ist es, innerhalb der Haupt-Verarbeitungsschleife (&#8222;loop()&#8220;) immer nur ganz kurz den jeweilige Analogwert auszulesen und dann entweder sofort oder nach einigen Aufrufen zu entscheiden, ob bzw. wann ein g\u00fcltiger Tastendruck vorliegt. Zu kl\u00e4ren ist auch, wie mit einem anhaltenden Auftreten sehr \u00e4hnlicher Werte umgegangen werden soll. Der Prozessor w\u00fcrde sonst m\u00f6glicherweise sehr viele  Tastendr\u00fccke derselben Taste pro Sekunde liefern! Ein gewisser statistische Ausgleich wird auch bei diesem Verfahren stattfinden, wenn auch nicht so perfekt wie bei dem obigen Beispiel mit 10 Messungen exakt alle 2 msec. Abgesehen von der Mittelwertbildung muss man auch ein Verfahren implementieren, um Ausrei\u00dfer zu erkennen und zu eliminieren.<\/p>\n\n\n\n<p><strong>Ein m\u00f6gliches Vorgehen dazu<\/strong>:<\/p>\n\n\n\n<ul><li>Liest man einen ziemlich gro\u00dfen Wert, so akzeptiert man ihn sofort und betrachtet die entsprechende Taste als gedr\u00fcckt.<\/li><li>Liest man eine Null, so ist definitiv keine Taste gedr\u00fcckt. Eine eventuell zuvor begonnene Erkennung wird abgebrochen und beim ersten Auftreten eines Wertes, der \u00fcber 0 liegt, neu gestartet.<\/li><li>Liest man einen mittleren oder kleinen Wert, so sammelt man mehrere solche Werte nacheinander (die Keyboard-Erkennungsroutine wird bei jedem Loop-Durchgang aufgerufen, also in der Regel sehr, sehr oft). Hat man gen\u00fcgend Werte (z.B. 3, 10 oder 20), so bildet man den Durchschnitt und zieht diesen zur Ermittlung der gedr\u00fcckten Taste heran.<\/li><li>Verfeinern l\u00e4\u00dft sich das Verfahren noch, indem man &#8222;Ausrei\u00dfer&#8220; erkennt (mitunter treten spontane Spannungen auf, die stark abweichen, man nennt sie &#8222;Spikes&#8220;) und f\u00fcr die Mittelwertbildung ignoriert. Man k\u00f6nnte aber auch nach dem Auftreten eines Spike mit der Durchschnittsbildung von vorn beginnen. Als Spike k\u00f6nnte man z.B. Werte ansehen, die um mehr als 30% des Abstands bis zur n\u00e4chsten Taste von den bisher empfangenen Werten abweichen.<\/li><\/ul>\n\n\n\n<p>Beispiel: Drei Tasten (A,B,C) m\u00f6gen (im Mittel) die Werte 1000, 1100 und 1200 Millivolt liefern. Man empf\u00e4ngt nacheinander die Werte <br><strong>0, 0, 975, 995, 1010, 800, 1110, 1120, 1144, 0, 0<\/strong><\/p>\n\n\n\n<p>Die Software verwendet 1050 und 1150 als Grenzen, um zwischen den drei Tasten zu unterscheiden. Au\u00dferdem m\u00f6ge sie so programmiert sein, dass sie mindestens drei konsistente Werte (= mit einer Abweichung &lt;=30 mV) ben\u00f6tigt, bevor sie entscheidet, dass ein g\u00fcltiger Tastendruck vorliegt.<\/p>\n\n\n\n<p>Je nach den Details des Algorithmus k\u00f6nnen <strong>unterschiedliche Ergebnisse<\/strong> entstehen:<\/p>\n\n\n\n<ul><li>Vergleicht man immer gegen\u00fcber dem ERSTEN Wert, der von Null verschieden ist, so wird keine einzige Taste erkannt, weil nur der zweite Wert nahe genug bei 975 liegt. Alle anderen Werte werden ignoriert.<\/li><li>Vergleicht man mit dem Durchschnitt der bislang passenden Werte, so wird 1010 mit 985 verglichen und weil diese Differenz kleiner als 30 ist, wird Taste A erkannt.<\/li><li>Allerdings gibt es hier bei stetig steigenden oder fallenden Werten die Gefahr einer &#8222;Drift&#8220; des Durchschnitts (wenn man z.B. 10 konsistente Werte erwartet). Es werden dann Werte als konsistent akzeptiert, die f\u00fcr sich alleine betrachtet besser zu einer anderen Taste passen w\u00fcrden.<\/li><li>Noch st\u00e4rker w\u00e4re der Effekt des &#8222;Hineinrutschens in eine andere Taste&#8220;, wenn man immer gegen\u00fcber dem letzten Wert vergleicht. Verlangt man 5 Werte, so k\u00f6nnte eine Folge wie 975, 1000, 1025, 1050, 1075 als konsistent betrachtet werden, wobei die ersten dei Werte besser zu Taste A passen, der 4. Wert auf der Grenzlinie liegt und der 5. Wert eindeutig besser zu B passen w\u00fcrde. Zieht man den Anfangswert oder den Gesamtdurchschnitt zur Entscheidung heran, dann erh\u00e4lt man A. Verl\u00e4\u00dft man sich auf den letzten, quasi aktuellsten Wert, erkennt man B. Man kann Beispiele f\u00fcr 10 konsistente Werte konstruieren, bei denen sogar A, B oder C herauskommen k\u00f6nnen, je nach Algorithmus.<\/li><\/ul>\n\n\n\n<p>Was soll eigentlich passieren, nachdem man sich entschieden hat, eine Taste als &#8222;erkannt&#8220; zu bezeichnen?<\/p>\n\n\n\n<ul><li>Nehmen wir an, die ersten drei Signalwerte haben zur Erkennung von A gef\u00fchrt und danach wir die 800 gelesen. Soll dieser Wert ab jetzt als neuer Referenzwert verwendet werden? Oder will man warten, bis eine 0 auftritt (= der Benutzer hat die zuvor erkannte Taste losgelassen). Es k\u00f6nnte immerhin sein, dass der Benutzer die erste Taste losgelassen und inzwischen eine andere Taste gedr\u00fcckt hat, OHNE dass wir dies mitbekommen haben, weil er sehr schnell war und wir in genau dem Moment zwischen den beiden Tastendr\u00fccken das Signal nicht abgefragt haben. Oder er ist auf die zweite Taste mit geringf\u00fcgiger zeitlicher \u00dcberlappung gewechselt. Dann w\u00fcrden wir selbst bei extrem schneller Abfrage KEINE 0 sehen, dennoch w\u00e4re der Finger aber auf einer anderen Taste! <\/li><li>Es spricht also einiges daf\u00fcr, die 800 als den m\u00f6glichen Beginn einer neuen Taste anzusehen &#8211; oder als einen Spike. Interesanterweise passen die folgenden Wert nicht zu der 800. Wir k\u00f6nnten sie nat\u00fcrlich alle ignorieren. Oder wir k\u00f6nnten die 1110 als den m\u00f6glichen Beginn einer neuen Folge ansehen, insbesondere, weil die folgenden Wert so gut dazu passen. Allerdings kann der Algorithmus nicht vorausschauen. Er m\u00fcsste sich &#8211; wenn er entsprechend schlau sein soll &#8211; die 800 und die 1110 merken und dann beim Eintreffen der 1120 entscheiden, dass 1110 oder der Mittelwert aus 1110 und 1120 ab jetzt als Referenzwert f\u00fcr Konsistenzentscheidungen benutzt werden soll. Im letzteren Fall w\u00fcrde beim Eintreffen der 1144 die Taste C erkannt werden, weil 1144 nahe genug bei 1115 liegt.<\/li><li>Oder der Algorithmus akzeptiert jeden Spike als m\u00f6glichen Neubeginn. Dann w\u00fcrde aber (bei 5 konsistenten Werten) eine Folge wie 900,900,1000,900,900,900 keinen g\u00fcltigen Tastendruck liefern. Ob das wirklich ideal ist?<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>Ganz generell stellt sich au\u00dferdem noch die Frage, <strong>wie man mit einer l\u00e4nger gedr\u00fcckten Taste umgehen soll. <\/strong>Man kann den Tastendruck als beendet erkl\u00e4ren, nachdem drei passende Signale erkannt wurden. Was soll man tun, wenn direkt danach wieder die selbe Taste erkannt wird? Ein Benutzer kann durchaus 200 msec auf einer Taste mit der Hand liegen bleiben. Bei entsprechend hoher Abfragefrequenz durch die loop() w\u00fcrde man dann m\u00f6glicherweise 30 oder mehr einzelne Tastendr\u00fccke &#8222;erkennen&#8220;.<\/p>\n\n\n\n<p>Soll man identische Wert grunds\u00e4tzlich immer ignorieren, egal wier lange sie anhalten? Das w\u00e4re auch schade, denn der Benuztzer erwartet m\u00f6glicherweise ein AUTO-REPEAT Verhalten, wenn er die Taste besonders lang gedr\u00fcckt h\u00e4lt. Au\u00dferdem k\u00f6nnen wir &#8211; wie zuvor erkl\u00e4rt &#8211; nicht sicher sein, dass wir eine 0 sehen, wenn der Benutzer gleitend von einer Taste zur anderen wechselt.<\/p>\n\n\n\n<p>Man wird also eine Sperrdauer (&#8222;Totzeit&#8220;) nach dem Erkennen einer Taste vorsehen m\u00fcssen &#8211; die aber nur gilt, solange Werte gemessen werden, die zu der zuletzt erkannten Taste passen. Ist diese initiale Sperrzeit abgelaufen, sollte immer wieder ein Tastendruck &#8222;erkannt&#8220; werden und eine zweite, k\u00fcrzere Sperrzeit immer wieder neu gestartet werden.<\/p>\n\n\n\n<p>Wenn man beispielsweise eine Taste hat, die einzelne Motorschritte ausl\u00f6st, dann w\u00e4re ein solches Verhalten extrem w\u00fcnschenswert. Man w\u00fcrde vielleicht sogar erwarten, dass ein Art Beschleuinigung eintritt, je l\u00e4nger man die Taste gedr\u00fcckt h\u00e4lt, d.h. die zweite Sperrzeit m\u00fcsste (bis zu einer Untergrenze) immer weiter verk\u00fcrzt werden mit jedem weiteren Tastenereignis, das man erkennt.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>AUFGABE<\/strong><\/p>\n\n\n\n<p>Schreibe ein Programm, das m\u00f6glichst robust, mit Tastaturmesswerten umgeht und daraus &#8222;Tastendr\u00fccke&#8220; erzeugt.<\/p>\n\n\n\n<p>Verwende eine nicht abgeschirmte Leitung, um die Tastatur anzuschlie\u00dfen und platziere die Leitung neben einem Netzteil o.\u00e4., um St\u00f6rungen einzufangen.<\/p>\n\n\n\n<p>Verwende in der loop variierende Delays (z.b. Zufallswerte zwischen 1 und 10 msec) um zu simulieren, dass andere Aufgaben den Prozessor unterschiedlich lange besch\u00e4ftigen, bevor er wieder dazu kommt, die Tastatur abzufragen. Schreibe alle Spannungswerte des Tastatur GPIO Pins auf die serielle Schnittstelle und gib dort auch aus, wann und wie oft du einen (welchen) Tastendruck identifizierst.<\/p>\n\n\n\n<p>Benutze zwei Tasten, um Einzelschritte des Motors auszul\u00f6sen.<\/p>\n\n\n\n<p>Setze die Verz\u00f6gerung in der loop() auf konstant 1 msec und programmiere nun die Tastatur so, dass eine Repeat-Funktion mit Beschleunigung ausgef\u00fchrt wird, wenn Tasten auf dem Keypad l\u00e4nger gedr\u00fcckt gehalten werden.<\/p>\n\n\n\n<p>Zeige, dass du auf diese Weise den Motor einigerma\u00dfen &#8222;ergonomisch&#8220; mit den beiden Tasten zu einer bestimmten Wunschposition hin bewegen kannst. Passe die Zeitkonstanten so an, dass es sich &#8222;gut anf\u00fchlt&#8220;.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Es gibt f\u00fcr den Arduino (bzw. ganz generell) ein Keyboard aus 4 x 4 Tasten, welches es erlaubt, eine gedr\u00fcckte Taste \u00fcber eine analoge Spannung zu identifizieren. Das Keyboard beruht auf einer Widerstandsmatrix. Die Versorgungsspannung (3.3 Volt, nicht 5 Volt) wird je nach gedr\u00fcckter Taste in einem bestimmten Verh\u00e4ltnis geteilt, so dass man beim Abfragen&hellip; <a class=\"more-link\" href=\"https:\/\/followthescore.org\/schueler-labor\/arduino-keyboard-mit-16-tasten\/\"><span class=\"screen-reader-text\">Arduino Keyboard mit 16 Tasten<\/span> weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"_links":{"self":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/pages\/722"}],"collection":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/comments?post=722"}],"version-history":[{"count":5,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/pages\/722\/revisions"}],"predecessor-version":[{"id":730,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/pages\/722\/revisions\/730"}],"wp:attachment":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/media?parent=722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}