Tastatur-Scrollrad mit Digispark USB-Entwicklungsboard realisieren

Schon im März 2015, als ich meine neue Microsoft Sculpt Ergonomic Desktop Tastatur auspackte, fiel mir etwas auf:
Als ich die Sculpt-Tastatur auspackte, fiel mir sofort das Loch in der Mitte auf. Was und insbesondere wozu sollte das denn gut sein? Da hätte man doch einfach das Plastik durchziehen können, oder noch besser eine Wippe oder Scrollrad anbringen oder zusätzliche Tasten. Außerdem sah das wirklich komisch aus. Einen praktische Nutzen hat es in Kombination mit der Schnurlosigkeit: man kann die Tastur mit einer Hand greifen und mal eben zur Seite stellen. Für die perfekte Tastatur würde ich mir aber hier ein Scrollrad oder Scrollpad wünschen.

Drei Jahre später war es dann endlich soweit sein, dass die Lücke gefüllt werden sollte. Als ich über das echt bezahlbare USB-Entwicklungsboard namens Digispark stolperte, kam mir gleich die Idee, dieses doch dafür zu nutzen, einen Joystick abzufragen und dessen Position in Maus-Signale umzuformen, um damit scrollen oder sich frei bewegen zu können.



Das hier beschriebene Joystick-Modul KY-023 sollte dazu zum Einsatz kommen. Es würde perfekt von der Größe in die Lücke passen, verfügt über zwei Achsen und einen Taster, der durch Niederdrücken ausgelöst wird.

Digispark USB Entwicklungsboard


Das Digispark USB-Entwicklungsboard ist ein Projekt von Digistump, die ein einfache Plattform für die Entwicklung von HID-USB-Geräten schaffen wollte. HID steht dabei für Human Interface Device, auf deutsch heißt das soviel wie Eingabegerät, also Tastatur, Maus und Joystick.

Digispark lässt sich einfach in die Arduino IDE integrieren und stellt eine API bereit, mit der man dann Tastatureingaben oder Mausbefehle an einen PC schicken kann.

Programmiert wird der Digispark ebenfalls über den USB-Port des PCs. Das bringt es mit sich, dass man ihn zur Programmierung jeweils abziehen muss und beim Sketch hochladen wieder anstecken muss. Der Digispark erkennt dann durch seinen Bootloader, dass der Programmiermodus erwünscht ist und lässt sich programmieren. Danach schaltet er sich wieder in den normalen Modus und meldet sich als USB-Gerät am PC an. Dieses hin und her ist während der Entwicklungsphase ein wenig nervig, fällt später aber weg, wenn das Programm fertig ist. Ein USB-Hub mit einzeln schaltbaren Ports, wie ich ihn habe, senkt den Nervigkeitslevel enorm.

Auf dem Digispark werkelt ein ATtiny 85, der 6 kB für eigene Programme und 512 Byte für Variablen mitbringt. Das ist schon recht knapp. Besonders die Library für die Tastatur braucht für sich schon einiges an Speicher und man muss sich die Befehle, die man einsetzen will sorgfältig überlegen. So hatte ich selbst bei diesem kleinen Projektchen schon mit dem Speicher zu kämpfen und musste ein paar Befehle umstellen, damit sie gerade noch so in den Speicher passen. Im Debug-Modus werden 99% belegt, im Maus-Modus 84%.


Die technischen Daten lesen sich wie folgt:

Arduino IDE einrichten für Digispark

Zuerst einmal aber muss das Board der Arduino Entwicklungsumgebung bekannt gemacht werden.

Dazu trägt man unter Datei / Voreinstellungen bei Zusätzliche Boardverwalter-URLs http://digistump.com/package_digistump_index.json in eine neue Zeile ein.

Danach installiert man über Werkzeuge Board / Boardverwalter die Digistump AVR Boards by Digistump, die eigentlich auch die entsprechenden Windows-Treiber mit installieren sollten. Das hat bei mir allerdings nicht geklappt. Ich erhielt die Fehlermeldung in Arduino IDE beim Installieren der Digistump VR Boards, das für C:\Users\xxx\AppData\Local\Arduino15\ packages\digistump\ tools\micronucleus\2.0a4\ post_install.bat die Berechtigung fehle.

Ich musste also eine Kommandozeile in Windows öffnen und C:\Users\xxx\AppData\Local\Arduino15\packages\digistump\tools\micronucleus\2.0a4\post_install.bat (xxx durch den eigenen Usernamen auf dem Windowssystem ersetzen) manuell ausführen, was alle Treiber installierte - was allerdings einige Zeit brauchte und meine Geduld ein wenig auf die Probe stellte. Normalerweise sind Treiberinstallationen bei mir schneller.

Als nächstes wählen wir unter Werkzeuge das Board Digispark (Default - 16.5mhz) aus und können dann schon ein paar Beispiele von Datei / Beispiele / Digispark... hochladen und ausprobieren. Seltsamerweise funktionierte zu Anfang das Board bei mir nur mit Digispark Pro (Default - 16mhz), dann mal mit 16 MHz und mal mit 16.5 Mhz. Hier muss man evtl. etwas probieren oder das Board ohne jegliche Bauteile daran ausprobieren. Ich habe festgestellt, dass es dem Board nicht gefällt, wenn an den Ports über einen geringeren Widerstand (die Potis in dem Joystick sind ja nichts anderes) eine Spannung anliegt. Dann wirft Windows das USB-Gerät gleich wieder aus und das Programmierung funktioniert u. U. auch nicht richtig. Ich habe einen zusätzlichen Widerstand in Reihe schalten müssen, damit das Board stabil funktioniert.

Programmierung des ATtiny / Digisparks

Die Programmierung des ATtiny / Digisparks ist ganz ähnlich wie beim schon bekannten Arduino Uno, es gibt allerdings ein paar Feinheiten bezüglich der Adressierung zu beachten.

Die sechs Pins P0 bis P5 sind Mehrzweck-Pins. Manche können als Analog und als Digital-Pins angesprochen werden. Dazu wird aber nicht gewohnt A0 bis A5 als Adressierung genutzt sondern ein ganz eigenes, nicht unbedingt logisches nur mit einer Ziffer, das unterscheidet, ob es via digitalRead oder analogRead angesprochen wurde: Pin-Adressierung mit digitalRead und analogRead: digital analog belegt P0 0 P1 1 out: LED P2 2 1 P3 3 3 USB-Programmierung, 1.5 kOhm fest eingebaut P4 4 2 USB-Programmierung P5 5 0 Andere Besonderheiten des Boards findet man auf den Wiki-Seiten von Digistump. Die möglichen Befehle zur Maus-, Tastatur- und Joysticksteuerung entnimmt man am besten den entsprechenden Beispielen.


Ich habe mich wie folgt entschieden den Joystick anzuschließen: digital analog belegt P0 0 Joy S (pullup) P1 1 out: LED P2 2 1 Joy X P3 3 3 USB-Programmierung, 1.5 kOhm fest P4 4 2 USB-Programmierung P5 5 0 Joy Y über 100 kOhm Widerstand (Vollausschlag sonst Reset) Wie bereits erwähnt schmiss mir Windows das USB-Gerät immer wieder aus, bis ich einen Widerstand mit min. 100 kΩ zusätzlich zum Poti bei einer Achse einbaute. Ich schätze mal, dass hängt damit zusammen, dass bei einem Vollausschlag des Poti der Widerstand ja gegen Null geht und dann komplette 5V am Pin anliegen, der wohl auch gleichzeitg über USB mit dem PC verbunden ist. Der das dann als Kurzschluss erkennt und das USB-Gerät abhängt.

Das ist auch deswegen ein wenig seltsam, weil ja lt. Tabelle nur P3 und P4 für die USB-Programmierung zuständig sein sollen. Aber vielleicht auch nur für die USB-Programmierung und nicht den USB-Betrieb. Es schadet also nichts, im Hinterkopf zu behalten, dass man mit den Eingängen aufpassen muss, weil sie u. U. auch Auswirkungen nach außen, nämlich der USB <-> PC Verbindung haben.

Die Software

Die Software ist zweigeteilt. Einmal in einen Debug-Teil, der die Tastatur-Bibliothek benutzt und einmal in den Mouse-Emulationsteil, der die Maus-Bibliothek benutzt.

Das aus dem Grund, weil Tastatur und Maus-Library nicht gleichzeitig zusammen benutzt werden können. Das schließt sich durch die Art, wie die Libraries programmiert sind aus; man erhält einen Fehler, sollte man versuchen, beide Libs einzubinden. Außerdem würde wahrscheinlich durch die Anwendung beider Libs der Speicher zu knapp sein.

Den Debug-Teil aktiviert man, indem man die Zeile #define DEBUG 1 auskommentiert. Die weiteren Präprozessor-Anweisungen (#if defined (DEBUG))regeln dann dadurch, welche Programmteil benutzt wird.

Im Debug-Modus werden alle Sekunde die ausgelesenen Analog-Werte der X und Y- Achse sowie des Joystick-Tasters ausgegeben. Zum einem als Funktionstest und zum anderen, um ein Gefühl für die Empfindlichkeit des Joysticks zu bekommen, um damit die Geschwindigkeit des Scrollens / der Mausbewegungen optimal einzustellen. Und nicht zu vergessen, um festzustellen, wo die Werte denn nun mit dem 100 kOhm-Widerstand liegen, durch den sich die Widerstandswerte natürlich verschieben.

Sind alle Werte und Berechnungsformeln fertig, wird die Debug-Zeile wieder auskommentiert und wir befinden uns dann im Mouse-Modus.

Diese hat auch zwei Teile: den Scroll und den Mouseersatz-Modus.

Im Scrollmodus fungiert der Joystick als Scrollrad. Nach unten bewegt, scrollt er nach unten und nach oben bewegt er sich nach oben. Je stärker der Ausschlag, desto schneller scrollt der Joystick. Erst hatte ich es so, dass ein Vollausschlag den Turbomodus einschaltete, der einem superschnell an Seitenanfang/-ende bringt. Doch dann habe ich den zuoft ausversehen ausgelöst und mich dazu entschieden, den Turbo-Modus nur zu aktivieren, wenn auch die X-Position erhöht ist, sprich: der Joystick am Anschlag unten und rechts (oder links) ist. Damit lässt sich gut arbeiten.

Klickt man den Joystick, also drückt man ihn nieder, wird in den zweiten Modus gewechselt, den Mausersatz-Modus. Hier kann man den Mauspfeil mit dem Joystick steuern und so z. B. auf ein anderes Fenster positionieren, um dann dieses zu scrollen. Ein weiterer Klick bringt einen wieder in Modus 1 - Scrollen.

Hier eine kleine Demonstration des Programmes und des Joysticks:



Source-Code

scrollrad.ino (klicken, um diesen Abschnitt aufzuklappen)
//////////////////////////////////////////////////////// // (C) 2019 by Oliver Kuhlemann // // Bei Verwendung freue ich mich über Namensnennung, // // Quellenangabe und Verlinkung // // Quelle: http://cool-web.de/arduino/ // //////////////////////////////////////////////////////// //#define DEBUG 1 // auskommentieren, um Poti-Werte ausgeben zu lassen #include <math.h> #if defined (DEBUG) #include <DigiKeyboard.h> #else #include <DigiMouse.h> #endif void setup() { #if defined (DEBUG) #else DigiMouse.begin(); //start USB-Mouse #endif pinMode(0, INPUT_PULLUP); } void loop() { int x = 500; int y = 500; float y2 = 0; int s = 0; char msg[20]; char tmp[20]; byte mode = 1; #if defined (DEBUG) mode=0; #endif while (1) { s = digitalRead(0); if (s == 0) { // Taster gedrückt -> Mode wechseln // warten bis wieder losgelassen while (digitalRead(0)==LOW) delay(10); mode++; #if defined (DEBUG) if (mode > 1) mode = 0; #else if (mode > 2) mode = 1; for (int i=0; i < mode;i++) { // LED blinken lassen, Mode anzeigen digitalWrite(1, HIGH); //schaltet die LED an delay (200); digitalWrite(1, LOW); //schaltet die LED aus delay (200); } #endif } x = analogRead(1); y = analogRead(0); #if defined (DEBUG) sprintf (tmp, "%d, %d, %d", x, y, s); #endif // in Wert mit Vorzeichen umwandeln, 0=Mitte -512...0...+512 x = abs(x - 1023) - 512; //y=((y-626/2)-512)*2.5; // 100 kOhm Widerstand y2=(log10((float) y)-2.9)*5000.; y=(int) y2; #if defined (DEBUG) if (mode == 0) { // TEST: Ausgabe der Werte sprintf (msg, "%d, %d, %d\n", x, y, s); DigiKeyboard.println (tmp); DigiKeyboard.println (msg); DigiKeyboard.delay(1000); } #else if (mode == 1) { // scrollrad int eins = (y / abs(y)) * -1; if (abs(y) > 150) { if (abs(y) < 250) { DigiMouse.scroll(eins); DigiMouse.delay(500); } else if (abs(y) < 350) { DigiMouse.scroll(eins); DigiMouse.delay(250); } else if (abs(y) < 450) { DigiMouse.scroll(eins); DigiMouse.delay(125); } else if (abs(y) <500) { DigiMouse.scroll(eins); DigiMouse.delay(62); } else if (abs(x) > 300) { DigiMouse.scroll(eins*5); DigiMouse.delay(50); } else { DigiMouse.scroll(eins); DigiMouse.delay(62); } } } if (mode == 2) { // mausersatz if (abs(x) > 100 || abs(y) > 100) { if (abs(x) < 200 && abs(y) < 200) { DigiMouse.move((int) (x/100), (int) (y/100), 0); } else { DigiMouse.move((int) (x/40), (int) (y/40), 0); } } DigiMouse.delay(10); } #endif } }

Einbau in die Tastatur


Mit dem Mini-Breadbord und den Jumper-Kabeln ist die Schaltung so schlecht unter der Tastatur zu verbauen. Da muss ein wenig mehr Stabilität her.

Erfreulicherweise hatte ich noch ein paar passende Lochrasterplatinen herumliegen, die ich letztens zum Schnäppchempreis vom Chinessen erworben hatte. Deren Größe war von Haus aus schon perfekt, so dass ich nichts mehr sägen oder schneider musste.

Der Digisark wurde links auf die Platine mit ein paar Headerleiste und etwas Abstand zum Board festgelötet. Platz genug darunter, um noch die Buchse vom USB-Verlängerungskabel einzustecken. Das Stückchen Platine darunter gibt der Buchse zusätzlichen Halt. So lässt sich das Kabel schnell abziehen, wenn ich die Tastatur einmal zu Seite legen möchte. Und genauso schnell ist sie wieder angestöpselt.

In passendem Abstand findet das Joystick-Modul seinen Platz, dass einmal an eine Headerleiste festgelött wird und außerdem Stabilität durch Klebeknete auf der Unterseite bekommt. Dadurch erhält er auch die richtige Höhe und ist gut bedienbar. Leicht erreichbar, aber nicht beim Tippen störend.

Der 100 kOhm Widerstand kommt auch auf die Vorderseite und verbindet so VRY mit P5 gleich auf elegante Weise.


Die Verbindungen befindet sich wie üblich auf der Rückseite der Lochrasterplatine. Das einzig isolierte Kabel ist hier +5V in rot. Den Rest habe ich direkt mit kleinen Kuperdrahtstücken verbunden, die ich außerdem auf dem Board festgelötet habe. Da sollte so schnell nichts abreissen.

Ich habe versucht, die Rückseite möglichst flach zu halten.



Für die Platine habe ich dann einen passenden Rahmen ausgedruckt, in die die Platine genau hineingesetzt werden kann. Zur zusätzlichen Sicherung kommt noch ein bisschen Klebeknete in die Ecken.

Von der Höhe ist der Bumper genau so gedruckt, dass er ohne die Tastatur geklebt genau auf dem Schreibtisch aufliegt, so dass man den Joystick ohne Gefahr niederdrücken kann, was manchmal ein bisschen schwergängig ist. Hierbei darf es kein Spiel geben, sonst würde sich die Platine von der Tastatur lösen.



Mit reichlich Klebeknete wird die plane Platine dann unter die gewölbte Tastatur geklebt und die runden Zwischenabstände gefüllt. Ziel ist es, die Platine so anzubringen, das USB-Stecker und Joystick mittig sind und der Abstand genau so ist, dass der Rahmen auf der Schreibtischoberfläche aufliegt, ohne das die Tastatur wackelt. Das ist mir gut gelungen.

Erst habe ich noch überlegt, ob ich eine kleine Abdeckung für das Dreieck in der Tastatur drucke. Aber dann ist mir aufgefallen, dass das nicht lohnt. Zum einem braucht der Joystick Bewegungsspielraum und zum Anderen möchte ich ja weiterhin die rote LED sehen können, die den Modi anzeigt. Und die grüne LED zu sehen, kann auch nichts schaden.

Und wegen des einen Zentimeters, den man abdecken könnte, wollte ich nun wirklich keinen zustäzlichen Aufwand betreiben. Außerdem gefällt mir der Technik-Charme irgendiwe.



Die Klebeknete erfüllt ihren Zweck gut. Klar hätte man auch Silikon drunter spritzen können, aber so lässt sich die Platine ohne größere Scherereien wieder abmontieren und bei der nächsten Sculpt wieder verwenden.


Das Gesamtergebnis sieht dann so aus:




Das ist funktionell und sieht gar nicht mal so schlecht aus. Nur der Umstand, dass die Tastatur jetzt irgendwie doch wieder an einem Kabel hängt ist etwas unschön. Aber damit kann ich gut leben.

Nachtrag 2019-05-13: 2. Widerstand


Nachdem Windows dann doch noch hin und wieder meckerte, dass das angeschlossene USB-Gerät unbekannt sei, und das nur sicher durch Drücken des Sticks nach unten beim Anschließen vermeidbar war, habe ich mich entschlossen, auch auf die Y-Achse einen 100 Kiloohm-Widerstand einzulöten.

Dass ging überraschend gut und ohne das Digispark-Board von der Tastatur lösen zu müssen. Die USB-Fehlermeldungen sind damit gänzlich verschwunden.

Der Source musste nicht geändert werden, denn etwa zu meiner Verwunderung blieben die Analog-Werte am 2. Poti trotzdem die gleichen.