Anschließen einer PC-Maus an Dandy. Wie bequem ist es? / Sudo Null IT-Nachrichten

Einmal kam mir die verrückte Idee, Dandy statt eines Joysticks eine Maus anzubringen. Wozu? Wofür? Ja, nur zum Spaß. Denn das hat noch niemand zuvor gesehen. Formal wurde diese Idee von einem Video angeregt, in dem Leute Punisher spielten. Ich weiß nicht viel über dieses spezielle Spiel, aber trotzdem war es bei dieser Art von Spielen immer unpraktisch, das Visier von der Querstange zu drehen. Gepaart mit dem sportlichen Interesse “Geht das?” und um “rein wiehern” zu können, beschloss ich, etwas Freizeit dem Koppeln einer gewöhnlichen Computermaus mit einem alten Dandy zu widmen.

Der Arduino Nano wurde als funktioneller Klebstoff zum Verbinden zweier Eisenstücke gewählt, einfach weil er zur Hand war. Außerdem deutete die Fünf-Volt-Logik aller Komponenten auf eine einfache Verbindung ohne Level-Matcher und anderes Bodykit hin. Die Maus ist die billigste mit PS/2-Schnittstelle, frisch gekauft, extra für dieses Projekt. Eigentlich ist das alles. Trotz der weit verbreiteten Verwendung von PS/2-Zubehör war es keine leichte Aufgabe, eine funktionierende Bibliothek zu finden. Einige Bibliotheken waren ziemlich alt und wurden nicht unter dem frischen ARDUINO SDK gebaut, andere wurden gebaut, aber sie funktionierten krumm oder funktionierten überhaupt nicht. Am Ende wurde die am besten geeignete Bibliothek dennoch gefunden und schien sogar zu funktionieren. Ich gestehe, ich bin in Ohnmacht gefallen. Ich hätte mir etwas mehr Zeit nehmen können, um das Mausprotokoll zu lernen, aber für eine einmalige Aufgabe wollte ich das überhaupt nicht tun. Dann gab es einen Teil der Emulation der Gamepad-Klicks der Konsole. Hier ist es in der Tat am einfachsten, es selbst zu schreiben, zumal es dort nichts Besonderes gibt. Im Inneren des NES-Controllers von Dandys Joystick befindet sich ein Schieberegister-Chip.

Schema eines gewöhnlichen Joysticks (Daten zu Q7 rückwärts, ochepyatka)Schema eines gewöhnlichen Joysticks (Daten zu Q7 rückwärts, ochepyatka)

Jedes Eingangsbit ist mit einer Controller-Taste verknüpft. Einfach ausgedrückt wandelt es eine Kombination gleichzeitig gedrückter Tasten in eine Sequenz um, die die Konsole bereits liest und darauf mit einer Aktion auf dem Bildschirm reagiert. Bei dem Signal LATCH (Read Reset) setzt die Mikroschaltung ihren Zähler zurück und wartet darauf, dass das Taktsignal CLOCK jedes Bit des Eingangs abfragt. Bei jedem Zyklus wird der Zustand jedes nächsten Bits der Mikroschaltung angegeben, d. h. es dauert 8 Zyklen, um alle 8 Tasten des Controllers abzufragen. Und dann im Kreis – erneutes Zurücksetzen, Registrierung aktueller Tastendrücke und 8 Zyklen Statusabfrage. Aber hier ist die Nuance. CLOCK- und Tastenzustände können als inverse Signale bezeichnet werden. Das heißt, der aktive Pegel der Uhr ist, wenn er gleich Null ist, und wenn Sie die Taste drücken, wird er auf Pegel 0 sein.

Detaillierter AbfragemechanismusDetaillierter Abfragemechanismus

Dies bedeutet, dass Arduino das LATCH-Signal auf der Vorderseite abfangen muss, dann, ohne auf das Taktsignal zu warten, sofort das Nullbit des Registers setzt und dann nach dem Ändern von CLOCK das erste, zweite … siebte Bit gibt . Wahrscheinlich werden ein paar Codezeilen viel klarer sein als meine Erklärung.

WaitLatch(); for (int i = 0; i < 8; i++) { if (dataPad & (1 << i)) writeLo(); sonst schreibeHi(); WaitClock (HIGH); } schreibeHi();

„Das ist es“, dachte ich naiv. Wir fragen die Maus ab, interpretieren ihre Tasten / Bewegungsrichtung in Controller-Befehle und senden diese. Probleme begannen bei den ersten Tests. Der Controller wurde eindeutig falsch emuliert. Es gab spontane „Klicks“ dieser Knöpfe, die ich nicht gedrückt hatte, Auslassungen von Befehlen und andere Teufelszeugs. Nachdem ich angefangen hatte herauszufinden, was los war, stellte ich zu meiner Überraschung fest, dass das Arduino nicht schnell genug ist – zum Zeitpunkt der Mausumfrage punktet es (natürlich) bei der Konsolenumfrage. Und wenn es nicht punktet, überspringt es eine bestimmte Anzahl von LATCH-Signalen, aber selbst wenn es das nicht tut, stolpert es über die CLOCK-Taktsignale. Mit Uhrensignalen hatte sie es am schwersten. Die Impulse (es ist schwierig, sie Zyklen zu nennen) sind so kurz, dass

digitalWrite (HIGH); digitalWrite (LOW);

werden viel länger ausgeführt als der Impuls selbst, und 5-7 Bits werden entweder gar nicht oder verspätet gesendet, wenn es überhaupt nicht mehr nötig ist. Ehrlich gesagt bin ich das erste Mal darauf gestoßen, bevor die Reaktionszeit der regulären Funktionen immer für alles ausreichte. Das ist aber nicht beängstigend, denn statt digitalWrite() kann man direkt auf die Zustände der Ports einwirken, was zig (!!!) mal schneller ist. digitalRead() wird auch dorthin gesendet, da es auch nicht sehr schnell ist.

void Gamepad::waitClock(int state) { if (state) { while (PIND & (1 << PIND2)) {}; } else { while (!(PIND & (1 << PIND2))) {}; } } void Gamepad::waitLatch() { while (!(PIND & (1 << PIND3))) {}; } void Gamepad::writeLo() {PORTD &= ~(1 << 4); } void Gamepad::writeHi() { PORTD |= (1 << 4); }Prüfung, Leid und kindliche FreudePrüfung, Leid und kindliche Freude

Ein Projekt starten… schon viel besser. Besser, aber immer noch schlecht. Fehlklicks sind fast weg, aber die Lücken bleiben. Am offensichtlichsten habe ich versucht, LATCH auf einen externen Interrupt zu schieben und einen Puffer mit gedrückten Tasten davon zu senden. Hat nicht funktioniert. Die Konsole pollt den Controller mit einer Frequenz von 50 oder 60 Hz (abhängig von der Region der Konsole), aber einige Spiele können 2 Mal gleichzeitig pollen, was Interrupts nicht mehr bewältigen können. Nach einer Weile habe ich das Problem immer noch besiegt und das Arduino so funktionieren lassen, wie es sollte. Nun … fast richtig. Für die anstehende Aufgabe reicht es. Ich musste Interrupts zum Zeitpunkt des Sendens des Pakets vollständig deaktivieren, sonst könnte der Arduino zur falschen Zeit denken und das Paket verderben. Ich bin mir sicher, dass es eine elegantere Lösung gibt, aber ich wollte schon schneller damit anfangen.

WaitLatch(); // Auf NES-Reset-Signal warten cli(); // Interrupts deaktivieren, damit nichts die korrekte Bildung des Pakets stört // Jedes Bit senden, wenn sich das Signal ändert Clock for (int i = 0; i < 8; i++) { if (dataPad & (1 << i)) writeLo(); sonst schreibeHi(); WaitClock (HIGH); } schreibeHi(); sei(); // Maus-Polling-Interrupts aktivieren

Die Maussteuerung wurde wie folgt zugewiesen: Mausbewegungen werden als Drücken von Steuerkreuztasten interpretiert. Die linke und rechte Taste sind die Tasten B und A des Controllers, und Start und Select hängen am Scrollrad.

Projektquellen hier

Und wie das alles in der Praxis funktioniert – willkommen bei YouTube

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *