Nachdem ich einmal genug von allen Arten von „Während alle spielen“ gesehen hatte, wollte ich auch meinen Himbeer-Pi spielen. Ja, nicht nur spielen, sondern mit einem echten Gerät spielen. Warum in der U-Bahn für 150 Rubel ein Joystick von Dandy gekauft wurde (na ja, nicht von einem Dandy, sondern von Simbas Junior). Diejenigen, die daran interessiert sind, was daraus entstanden ist, können auf die Schaltfläche unten klicken. Am Ende des Artikels befindet sich ein Link zum Beweis.Unsere chinesischen Freunde haben es unter dem Motto gesammelt - es gibt keine Qualität, aber Sie halten fest. Sofort wurde ein natives Kabel mit einem Leiterquerschnitt von 2 Quadratmikron gelötet und durch ein Kabel eines industriellen Schnittstellenkonverters ersetzt, das nach der nächsten Inbetriebnahme nur 5 Drähte hatte.Bevor Sie Änderungen am Code vornehmen, mussten Sie herausfinden, wie das Gamepad selbst funktioniert. Das Gamepad hat ein Schieberegister. Das Gamepad verfügt über 5 Drähte - 2 - Strom, 3 Informationen - Latch (Strobe), Clock (Pulse) und Daten. Wenn eine logische Einheit an Latch geliefert wird, wird der Zustand der Eingänge des Schieberegisters gespeichert, und an den Ausgangsdaten ist der Zustand der Taste "A" sofort verfügbar, und wenn sich der logische Pegel auf der Taktleitung an den Ausgangsdaten ändert, erscheinen Spannungspegel, die dem Zustand der anderen sieben Tasten entsprechen in sequentieller Form. Der gedrückte Knopf entspricht - 0, nicht gedrückt - 1. Außerdem ist für das Spiel alles genau umgekehrt, es ist notwendig, die Inversion durchzuführen. Die folgende Abbildung zeigt das Diagramm des Gamepads.
Darauf folgte eine Auswahl an Emulatoren. Die Wahl fiel auf die alte fceu-Version 0.98.12, da sie eine ausgezeichnete Modularität aufweist und die Konsolenarchitektur ziemlich genau emuliert und in C geschrieben ist. Darauf folgte die Wahl einer Bibliothek für die Arbeit mit GPIO. Ich entschied mich für bcm2835 von Mike McCauley, das ebenfalls in C geschrieben ist und eine gute Leistung aufweist.Da ich ein Anfänger in der Programmierung bin, musste ich mich an einen der Prominenten aus demselben „Während alle spielen“ wenden, mit der Bitte, Codeabschnitte zu kommentieren. Und stecken Sie Ihre Nase in die Funktionen, die für die Übertragung des Status der Tasten an das Spiel verantwortlich sind. Sie erklärten mir in einer zugänglichen Sprache, was und wie. Daher ist die Datei input.c für die Emulation der Eingabe verantwortlich, und hier treten die wichtigsten Änderungen auf. Es gibt mehrere Funktionen, die für die Simulation eines Gamepads verantwortlich sind - FCEU_UpdateInput, ReadGP und DECLFW (4016). Tatsächlich gibt es noch mehr, dies sind die wichtigsten. Zusätzlich zu input.c musste ich Änderungen an file.c und fceu.c. vornehmen. Im ersten Fall gab es Fehler in der Datei file.c, aber dieses Problem ist Google, es gibt einen Patch für diese Datei, und in der Datei fceu.c habe ich die Initialisierung der Bibliothek bcm2835 in der int-Funktion FCEUI_Initialize (void) hinzugefügt:bcm2835_init();
Vorab Hinzufügen der Header-Datei#include <bcm2835.h>
Jetzt input.c habe ich auch die bcm2835-Bibliotheksheaderdatei (ähnlich wie fceu.c) und die <unistd.h> -Bibliotheksheaderdatei hinzugefügt, um mit usleep zu arbeiten. Als nächstes kündigte ich die GPIO-Ports an, die beteiligt sein werden: #define LATCH RPI_V2_GPIO_P1_11
#define CLK RPI_V2_GPIO_P1_13
#define DATA RPI_V2_GPIO_P1_15
In der Funktion void InitializeInput (void) habe ich einen Code hinzugefügt, in dem ich den Betriebsmodus jedes GPIO-Ports registriert und die für Latch (Strobe) und Takt verantwortlichen Ports sofort auf 0 zurückgesetzt habe. bcm2835_gpio_fsel(LATCH, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_fsel(CLK, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_fsel(DATA, BCM2835_GPIO_FSEL_INPT);
bcm2835_gpio_set_pud(DATA, BCM2835_GPIO_PUD_UP);
bcm2835_gpio_write(CLK, LOW);
bcm2835_gpio_write(LATCH, LOW);
Nun zu den Funktionen:Und so ist DECLFW (4016) - für die Simulation des Latch-Signals (Strobe) verantwortlich. Wie gesagt, um den Status der Schaltflächen zu lesen, müssen Sie für eine Weile auf Latch-1 anwenden. Es gibt eine Laststrobe-Variable, in die der zuletzt in dieses Register geschriebene Wert geschrieben wird. Wenn Laststrobe 0 war, wird jeweils logische 1 geschrieben, und der GPIO-Pin, der als Latch bezeichnet wird, wird ebenfalls mit 1 gespeist und nach 1 μs auf 0 zurückgesetzt. Wenn Laststrobe gleich 1 war, wird dieser Codeabschnitt ignoriert.static DECLFW(B4016)
{
if (FCExp)
if (FCExp->Write)
FCExp->Write(V & 7);
if (JPorts[0]->Write)
JPorts[0]->Write(V & 1);
if(JPorts[1]->Write)
JPorts[1]->Write(V&1);
if((LastStrobe&1) && (!(V&1)))
{
if(JPorts[0]->Strobe)
JPorts[0]->Strobe(0);
if(JPorts[1]->Strobe)
JPorts[1]->Strobe(1);
if(FCExp)
if(FCExp->Strobe)
FCExp->Strobe();
}
if (LastStrobe==0)
{
bcm2835_gpio_write(LATCH, HIGH);
usleep(1);
bcm2835_gpio_write(LATCH, LOW);
}
LastStrobe=V&0x1;
}
Nun, jetzt die Abfrage des Joysticks selbst, void FCEU_UpdateInput (void) - in dieser Funktion werden Daten von den Eingabetreibern gelesen, die ausgewählt wurden, als der Emulator konfiguriert wurde oder als er durch Eingabe bestimmter Tasten gestartet wurde, z. B. eines Gamepads, eines Terpads, einer Light Gun usw. ., alles, was mit der Konsole verbunden werden könnte. Darin werden die Bytes des Status der Schaltflächen der Gamepads joy [0] ... joy [3] in einer Menge von 2 bis 4 gebildet, da Sie die Emulation des Pribluda aktivieren können, um 2 weitere Gamepads zu verbinden. Hier fanden die wichtigsten Änderungen statt. Da ich nicht die Fähigkeit nutzen muss, mit 4 Gamepads zu arbeiten und Daten von anderen Treibern zu empfangen, habe ich den gesamten Code verworfen und meinen eingegeben: joy[0] = 0;
joy[1] = 0;
for (i = 0; i <= 7; i++)
{
joy[0] ^= bcm2835_gpio_lev(DATA) << i;
joy[0] ^= (1 << i);
joy[1] ^= bcm2835_gpio_lev(DATA) << i;
joy[1] ^= (1 << i);
bcm2835_gpio_write(CLK, HIGH);
usleep(1);
bcm2835_gpio_write(CLK, LOW);
usleep(1);
}
Außerdem bilde ich sofort zwei Bytes des ersten und zweiten Joysticks. Da viele Spiele den Status von Schaltflächen an zwei Ports gleichzeitig lesen, gibt es für sie kein Konzept für einen Prioritätsport. Es gibt jedoch Spiele, für die ein solches Konzept existiert - zum Beispiel alle Mario, Kirby, Terminator 2 usw. Das heißt, sie lesen den Status der Tasten nur vom ersten Port (in Mario für den ersten Spieler, für den zweiten nur vom zweiten), dh vom Register 4016. Es ist auch wichtig, beim Aufrufen dieser Funktion den Wert Null zuzuweisen, da sonst der vorherige Wert in ihnen gespeichert wird neue werden ihnen bereits überlagert. Im Prinzip war es möglich, das Byte für den zweiten Joystick gleich Null zu lassen, aber ich habe es möglich gemacht, Mario zusammen zu spielen.ReadGP - es extrahiert bereits Bits aus Bytes joy [0] ... joy [3], und die Variable ret gibt den Status der jeweiligen Schaltfläche im Moment des Spiels zurück. Die Schaltflächennummer wird durch die Variable joy_readbit [w] festgelegt, wobei w die Portnummer des Joysticks ist. erste oder zweite. Aber in dieser Funktion habe ich keine Änderungen vorgenommen. Links wie es ist.Fügen Sie für eine erfolgreiche Kompilierung im Makefile (das nach Ausführung des Befehls Configure erstellt wurde) im Verzeichnis src -lbcm2835 -lm -lrt an der Stelle hinzu, an der die Bibliotheksabhängigkeiten geschrieben werden. Zeile:LIBS =
Und im Allgemeinen hat alles funktioniert. Ich verließ die Grundlagen, als ich mich plötzlich entschied, einen zweiten Joystick zu kaufen, um zusammen in denselben Panzern zu spielen.» Link zum Proof
» Daten von der Site wurden verwendet
»Besonderer Dank geht an diese Person , die mir geholfen hat, den Emulatorcode zu verstehen