将Nintendo Classic Mini游戏手柄连接到Raspberry Pi

假期快要结束了,这意味着该是后悔肝脏并打开头部的时候了。所以我想到了另一个主意。在我从Dendy连接了游戏手柄之后(他是一个操纵杆,他是一个控制器,他是一个操纵杆,他是一个游戏机,等等)geektimes.ru/post/281520,我想到了将第二个连接到Raspberry pi。我不想购买第二个带有干扰按钮的垃圾,顺便说一句,在这里,我被扔到了Nintendo Classic Mini的架子上。目标不是要购买4K模拟器,而是我决定购买游戏手柄。幸运的是,我设法购买了它,这是商店中的最后一个。感兴趣的人可以单击下面的按钮。如果未激活常规证明,则

这是直接链接到证明

图片

毫无疑问,此游戏手柄可以同时连接到Wii和Wii U,这意味着可以通过i2c接口对其进行询问。令人鼓舞的是,游戏手柄采用3.3 V电源供电,这意味着您不必为匹配的电压电平而烦恼。为了将游戏手柄连接到Raspberry pi,我决定购买速卖通上Wiimote的连接器,然后将其焊接在板上。尽管包装中有2个连接器,并且它们处于同一气泡中,但是其中一个连接器损坏了。没有锡不能在这里做。一切焊接完毕后,有必要检查一下是否可行。为此,我决定使用i2c-tools软件包中的实用程序。这个想法是要确定地址为52的设备。启动i2cdetect之后,我看到了宝贝:

i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          03 04 05 06 07 -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- 52 -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

我的心立刻变暖(好像一个陌生的女孩在春天的大街上对你微笑),所以它起作用了。接下来,您必须在Google上搜索有关将外围设备连接到Wii的信息。我找到了Wii双节棍如何连接到Raspberry pi的示例。从此示例中,我发现必须通过将0写入0x40寄存器来初始化游戏手柄,然后在每次读取之前,您只需要写入0并读取前6个字节即可。

在这种情况下,我还面临选择i2c库的问题。由于我没有成功使用bcm2835库,因此我决定使用示例中使用的库-这是WirinPi库。一切都和她在一起。根据经验,我发现按钮信息包含4个字节和5个字节(如果您从零开始计算字节)。关于选择,开始,向下,向右按钮的信息在第四个字节中,关于A,B,向上,向左按钮的信息在第五个字节中。此外,有关选择,向下,向右按钮的信息位于字节的高4位,而有关开始按钮的信息位于较低的字节。对于第5个字节也是如此,关于按钮A,B的信息在字节的高4位中,关于按钮的信息在左下方。以下是按钮代码:A-0xcf,B-0xbf,向上-0xf0,左侧-0xf1,选择-0xcf,开始-0xf3,向下-0xbf,右侧-0x7f。联合按下按钮的结果(有关信息位于一个字节和相同的位中)是其代码的逻辑“与”。因此,例如,同时按下按钮A和B会得到值0x8f。

这是表格链接

图片

接下来,我编写了一个用于读取按钮的小型测试程序,下面将对其进行完整列出并解释发生了什么:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <errno.h>
char i, a, b, c, d, state;
char bytes[6];
int main(void) {
wiringPiSetup();
int fd = wiringPiI2CSetup(0x52);
wiringPiI2CWriteReg8(fd, 0x40, 0x00);
delayMicroseconds(20);
while(1) 
{
	state = 0;
	wiringPiI2CWrite(fd, 0x00);
        delayMicroseconds(100);
        for (i=0; i<6; i++)
	{
           bytes[i] = wiringPiI2CRead(fd);
        }
	a = bytes[5] >> 4;
	b = bytes[5] << 4;
	c = bytes[4] >> 4;
	d = bytes[4] << 4;
	if (a == 0xc)
	state ^= (1 << 0);
	if (a == 0xb)
	state ^= (1 << 1);
	if (c == 0xc)
	state ^= (1 << 2);
	if (d == 0x30)
	state ^= (1 << 3);
	if (b == 0x00)
	state ^= (1 << 4);
	if (c == 0xb)
	state ^= (1 << 5);
	if (b == 0x10)
	state ^= (1 << 6);
	if (c == 0x7)
	state ^= (1 << 7);
	printf("%x \n", state);
	}
    return 0;
}

在一开始就声明了变量,借助这些变量可以确定特定按钮的状态。变量的类型必须为char,这一点很重要,否则,向左移一点,只添加4个零即可。解释将是错误的。不管听起来多么有趣,都必须使用该咒语

接下来,在程序的主体中,将初始化WiringPi库-wireingPiSetup();,然后将设备i2c地址设置为0x52。接下来,初始化控制器:


wiringPiI2CWriteReg8(fd, 0x40, 0x00);
delayMicroseconds(20);

好吧,那么,已经在循环体内,读取了6个字节,并且在读取之前,每次写入零。然后,确定按下的按钮。通常,所有这些代码都迁移到仿真器文件中。

上一次,库的初始化注册在fceu.c文件中:


int FCEUI_Initialize(void)
{
    if(!FCEU_InitVirtualVideo())
    return 0;
    memset(&FSettings,0,sizeof(FSettings));
    FSettings.UsrFirstSLine[0]=8;
    FSettings.UsrFirstSLine[1]=0;
    FSettings.UsrLastSLine[0]=231;
    FSettings.UsrLastSLine[1]=239;
    FSettings.SoundVolume=100;
    FCEUPPU_Init();
    X6502_Init();
    wiringPiSetup();
    return 1;
}

那么,所有更改仅涉及input.c文件。最初,在FCEUI_Initialize(void)int函数中,设置了用于旧游戏手柄(来自Simba)的gpio端口操作模式,并初始化了游戏手柄。


pinMode (0, OUTPUT);
pinMode (2, OUTPUT);
pinMode (3, INPUT);
digitalWrite (0, HIGH);
digitalWrite (2, LOW);
fd = wiringPiI2CSetup(0x52);
wiringPiI2CWriteReg8(fd, 0x40, 0x00);
usleep(20);

首先,您还需要声明将确定按钮按下次数的变量。

在静态DECLFW(B4016)功能中,为旧游戏手柄提供了闪光灯,而无需使用新闪光灯:


if (LastStrobe==0)
{
	digitalWrite (0, LOW);
}


在创建测试程序时,我无法解决识别按下在一起的按钮的问题,有关按钮的信息在一个字节和一位中。最后,我应用了switch case结构而不是if。
好吧,函数本身就是读取按钮状态的函数:


void FCEU_UpdateInput(void)
{
joy[0] = 0;
joy[1] = 0xff;
wiringPiI2CWrite(fd, 0x00);
usleep(100);
for (i = 0; i <= 7; i++)
	{
	bytes[i] = wiringPiI2CRead(fd);
	joy[1] ^= digitalRead(3) << i;
	digitalWrite (2, HIGH);
	delayMicroseconds (20);
	digitalWrite (2, LOW);
	delayMicroseconds (20);
	}
	a = bytes[5] >> 4;
	b = bytes[5] << 4;
	c = bytes[4] >> 4;
	d = bytes[4] << 4;
	switch (a){
	case 0xc:
	joy[0] ^= (1 << 0);
	break;
	case 0xb:
	joy[0] ^= (1 << 1);
	break;
	case 0x8:
	joy[0] ^= (1 << 0);
	joy[0] ^= (1 << 1);
	break;
	}
	switch (b){
	case 0x00:
	joy[0] ^= (1 << 4);
	break;
	case 0x10:
	joy[0] ^= (1 << 6);
	break;
	case 0x20:
	joy[0] ^= (1 << 4);
	joy[0] ^= (1 << 6);
	break;
	}
	switch (c){
	case 0xc:
	joy[0] ^= (1 << 2);
	break;
	case 0xb:
	joy[0] ^= (1 << 5);
	break;
	case 0x7:
	joy[0] ^= (1 << 7);
	break;
	case 0x8:
	joy[0] ^= (1 << 2);
	joy[0] ^= (1 << 5);
	break;
	case 0x4:
	joy[0] ^= (1 << 2);
	joy[0] ^= (1 << 7);
	break;
	case 0x3:
	joy[0] ^= (1 << 5);
	joy[0] ^= (1 << 7);
	break;
	}
	switch (d){
	case 0x30:
	joy[0] ^= (1 << 3);
	break;
	}
	digitalWrite (0, HIGH);
	}
	

在一个周期中,我将两个游戏手柄上的按钮读取结合在一起,好吧,我认为要再读取2个字节,这没关系,但是所有操作都同时发生。而且没有延迟。

总的来说,一切都很好。

PS:我记得,明天的工作已经扭曲了。

PPS我忘了添加它以成功编译,该文件位于src目录中的Makefile(在执行Configure命令后形成)中,您需要在写入库依赖项的位置添加-lwiringPi -lm -lrt。行:

LIBS =

Source: https://habr.com/ru/post/zh-CN400445/


All Articles