嵌入式Linux:V3s移植NES游戏,声音,游戏手柄

19 篇文章 54 订阅

一、前言

参考博客:v3S移植NES游戏
参考博客二:V3S移植nes游戏模拟器(附带游戏合集)

下载启动器源码:https://github.com/nejidev/arm-NES-linux
下载游戏合集:链接:https://pan.baidu.com/s/16hIWwYQQEX9aOBDG1dVa0A 提取码:asdf

步骤是这样的:
1、Ubuntu上进行交叉编译出启动器:InfoNES,USB手柄xxx.ko
2、下载并解压出游戏合集(需要改名字xxxx.nes)
3、以上都拷贝到目标板上去,安装xxx.ko
4、运行:./InfoNES xxx.nes

二、下载、解压、更改配置,编译源码

这里要基于自己的buildroot制作根文件系统的文件夹

下载源码

下载启动器源码:https://github.com/nejidev/arm-NES-linux

解压出来

$ unzip arm-NES-linux-master.zip

配置源码

1、在linux目录下新建一个work文件夹

$ mkdir /linux/work

2、修改linux目录下的Makefile文件:vim Makefile
全部内容

CC = /home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/host/bin/arm-linux-gnueabihf-gcc
TARBALL = InfoNES08J

# InfoNES
.CFILES =       ./../K6502.cpp \
                ./../InfoNES.cpp \
                ./../InfoNES_Mapper.cpp \
                ./../InfoNES_pAPU.cpp \
                ./InfoNES_System_Linux.cpp joypad_input.cpp

.OFILES =       $(.CFILES:.cpp=.o)

CCFLAGS =  -O2 -fsigned-char -I/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/include
LDFILGS = -lstdc++ -L/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/lib       # gcc3.x.x

all: InfoNES

InfoNES: $(.OFILES)
        $(CC) $(INCLUDES) -o $@ $(.OFILES) $(LDFILGS) -lm -lz -lpthread -lasound

.cpp.o:
        $(CC) $(INCLUDES) -c $(CCFLAGS) $*.cpp  -o $@

clean:
        rm -f $(.OFILES) ../*~ ../*/*~ core

cleanall:
        rm -f $(.OFILES) ../*~ ../*/*~ core InfoNES

release: clean all

tar:
        ( cd ..; \
        tar cvf $(TARBALL).tar ./*; \
        gzip $(TARBALL).tar \
        )

install:
        install ./InfoNES /home/liefyuan/Liefyuan/Nes/arm-nes-linux/linux/work

1.在CCFLAGS 后面增加alsa的头文件目录(该目录在bulidroot/output那里例如)

-I/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/include

2.在LDFILGS 增加alsa的lib文件目录(和上面一样)

-L/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/staging/usr/lib

3.修改最上面的CC为bulidroot里面的gcc

/home/liefyuan/Liefyuan/cherry-pi/buildroot-2020.02.4/output/host/bin/arm-linux-gnueabihf-gcc

4.更改最后的install那里为前面建立的work目录

install ./InfoNES /home/liefyuan/Liefyuan/Nes/arm-nes-linux/linux/work

5.修改linux/InfoNES_System_Linux.cpp文件中的static int lcd_fb_display_px函数(调整spi屏幕的颜色):

static int lcd_fb_display_px(WORD color, int x, int y)
{
        unsigned char  *pen8;
        unsigned short *pen16;
        pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
        pen16 = (unsigned short *)pen8;
        *pen16 = color;

        return 0;
}

修改为:

static int lcd_fb_display_px(WORD color, int x, int y)
{
        unsigned char  *pen8;
        unsigned short *pen16;

        unsigned char r, g, b;
        r = ((color >> 10) & 0x1f);
        g = ((color >> 5) & 0x3f);
        b = (color & 0x1f);

        color = r<<11|g<<6|b;
        pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
        pen16 = (unsigned short *)pen8;
        *pen16 = color;

        return 0;
}

如果不改的话:
在这里插入图片描述

改了颜色就好一些:
在这里插入图片描述
6、最后一步编译

make
make install

生成的文件在work文件夹下:

liefyuan@ubuntu:~/Liefyuan/Nes/arm-nes-linux/linux/work$ ls
InfoNES

然后把这个InfoNES拷贝到开板上就可以了。

运行

打开声音:

tinymix set 1 63
tinymix set 2 1

打开游戏

./InfoNES hdl-chinese.nes

跑起来了!!
在这里插入图片描述

二、添加USB手柄:搞定了

来源:https://whycan.com/t_5139.html#p52283

linux kernel 里面编译:

linux menuconfig
     > Device Drivers > Input device support
     	<*>   Joystick interface
      	[x]   Joysticks/Gamepads  --->
     > Device Drivers > HID support > Special HID drivers
      	<*> DragonRise Inc. game controller

重新烧录内核后,插上游戏手柄:/dev/input下出现了js0设备节点

# ls /dev/input
event0  event1  js0

设备节点出来了,但是游戏手柄按键按着没有反应!

写一个用户空间代码测试一下手柄键值:

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>

typedef unsigned int __u32;
typedef short __s16;
typedef unsigned char __u8;

struct js_event {
    __u32 time;     /* event timestamp in milliseconds */
    __s16 value;    /* value */
    __u8 type;      /* event type */
    __u8 number;    /* axis/button number */
};

#define JS_EVENT_BUTTON         0x01    /* button pressed/released */
#define JS_EVENT_AXIS           0x02    /* joystick moved */
#define JS_EVENT_INIT           0x80    /* initial state of device */

int main() {
    int fd = open("/dev/input/js0", O_RDONLY);
    struct js_event e;
    while(1) {
        read(fd, &e, sizeof(e));
        int type = JS_EVENT_BUTTON | JS_EVENT_INIT;
        switch(e.type) {
            case JS_EVENT_AXIS:
                printf("axis number: %d, value: %d, time: %d\n", e.number, e.value, e.time);
                break;
            case JS_EVENT_BUTTON:
                printf("btn: number: %d, value: %d, time: %d\n", e.number, e.value, e.time);
                break;
        }
    }
    close(fd);
    return 0;
}

编译:

arm-linux-gnueabihf-gcc test.c -o joytest

拷贝到开发板上:

sudo cp joytest /media/liefyuan/rootfs/opt/

测试:
在这里插入图片描述

游戏手柄按键读出的键值
L1btn: number: 4, value: 1, time: 198640
btn: number: 4, value: 0, time: 198850
L2btn: number: 6, value: 1, time: 221840
btn: number: 6, value: 0, time: 222000
R1btn: number: 5, value: 1, time: 255670
btn: number: 5, value: 0, time: 255840
R2btn: number: 7, value: 1, time: 257390
btn: number: 7, value: 0, time: 257470
左方向键上axis number: 1, value: -32767, time: 51680
axis number: 1, value: 0, time: 51840
左方向键下axis number: 1, value: 32767, time: 99770
axis number: 1, value: 0, time: 99900
左方向键左axis number: 0, value: -32767, time: 132060
axis number: 0, value: 0, time: 132150
左方向键右axis number: 0, value: 32767, time: 156420
axis number: 0, value: 0, time: 156510
SELECT键btn: number: 8, value: 1, time: 312440
btn: number: 8, value: 0, time: 312600
START键btn: number: 9, value: 1, time: 313560
btn: number: 9, value: 0, time: 313730
右边数字键1btn: number: 0, value: 1, time: 460600
btn: number: 0, value: 0, time: 460770
右边数字键2btn: number: 1, value: 1, time: 461560
btn: number: 1, value: 0, time: 461730
右边数字键3btn: number: 2, value: 1, time: 463040
btn: number: 2, value: 0, time: 463200
右边数字键4btn: number: 3, value: 1, time: 463790
btn: number: 3, value: 0, time: 463920

查看一下它的写法:
/linux/joypad_input.cpp

...
static int USBjoypadGet(void)
{
	/**
	 * FC手柄 bit 键位对应关系 真实手柄中有一个定时器,处理 连A  连B 
	 * 0  1   2       3       4    5      6     7
	 * A  B   Select  Start  Up   Down   Left  Right
	 */
	//因为 USB 手柄每次只能读到一位键值 所以要有静态变量保存上一次的值
	static unsigned char joypad = 0;
	struct js_event e;
	if(0 < read (USBjoypad_fd, &e, sizeof(e)))
	{
		if(0x2 == e.type)
		{
			/*
			上:
			value:0x8001 type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(0x8001 == e.value && 0x5 == e.number)
			{
				joypad |= 1<<4;
			}
			
			/*下:
			value:0x7fff type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(0x7fff == e.value && 0x5 == e.number)
			{
				joypad |= 1<<5;
			}
			//松开
			if(0x0 == e.value && 0x5 == e.number)
			{
				joypad &= ~(1<<4 | 1<<5);
			}
			
			/*左:
			value:0x8001 type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(0x8001 == e.value && 0x4 == e.number)
			{
				joypad |= 1<<6;
			}
			
			/*右:
			value:0x7fff type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(0x7fff == e.value && 0x4 == e.number)
			{
				joypad |= 1<<7;
			}
			//松开
			if(0x0 == e.value && 0x4 == e.number)
			{
				joypad &= ~(1<<6 | 1<<7);
			}
		}

		if(0x1 == e.type)
		{
			/*选择:
			value:0x1 type:0x1 number:0xa
			value:0x0 type:0x1 number:0xa
			*/
			if(0x1 == e.value && 0xa == e.number)
			{
				joypad |= 1<<2;
			}
			if(0x0 == e.value && 0xa == e.number)
			{
				joypad &= ~(1<<2);
			}
			
			/*开始:
			value:0x1 type:0x1 number:0xb
			value:0x0 type:0x1 number:0xb
			*/
			if(0x1 == e.value && 0xb == e.number)
			{
				joypad |= 1<<3;
			}
			if(0x0 == e.value && 0xb == e.number)
			{
				joypad &= ~(1<<3);
			}

			/*A
			value:0x1 type:0x1 number:0x0
			value:0x0 type:0x1 number:0x0
			*/
			if(0x1 == e.value && 0x0 == e.number)
			{
				joypad |= 1<<0;
			}
			if(0x0 == e.value && 0x0 == e.number)
			{
				joypad &= ~(1<<0);
			}

			/*B
			value:0x1 type:0x1 number:0x1
			value:0x0 type:0x1 number:0x1
			*/
			if(0x1 == e.value && 0x1 == e.number)
			{
				joypad |= 1<<1;
			}
			if(0x0 == e.value && 0x1 == e.number)
			{
				joypad &= ~(1<<1);
			}

			/*X
			value:0x1 type:0x1 number:0x3
			value:0x0 type:0x1 number:0x3
			*/
			if(0x1 == e.value && 0x3 == e.number)
			{
				joypad |= 1<<0;
			}
			if(0x0 == e.value && 0x3 == e.number)
			{
				joypad &= ~(1<<0);
			}

			/*Y
			value:0x1 type:0x1 number:0x4
			value:0x0 type:0x1 number:0x4
		 	*/
		 	if(0x1 == e.value && 0x4 == e.number)
			{
				joypad |= 1<<1;
			}
			if(0x0 == e.value && 0x4 == e.number)
			{
				joypad &= ~(1<<1);
			}
		}
		return joypad;
	}
	return -1;
}

调试了一下:

# ./InfoNES Tankwar.nes
/dev/input/js0 dev node ok!
fb width:800 height:480
type: 129, axis number: 0, value: 0, time: -214620
type: 129, axis number: 1, value: 0, time: -214620
type: 129, axis number: 2, value: 0, time: -214620
type: 129, axis number: 3, value: 0, time: -214620
type: 129, axis number: 4, value: 0, time: -214620
type: 129, axis number: 5, value: 0, time: -214620
type: 129, axis number: 6, value: 0, time: -214620
type: 129, axis number: 7, value: 0, time: -214620
type: 129, axis number: 8, value: 0, time: -214620
type: 129, axis number: 9, value: 0, time: -214620
type: 129, axis number: 10, value: 0, time: -214620
type: 129, axis number: 11, value: 0, time: -214620
type: 130, axis number: 0, value: 0, time: -214620
type: 130, axis number: 1, value: 0, time: -214620
type: 130, axis number: 2, value: 0, time: -214620
type: 130, axis number: 3, value: 0, time: -214620
type: 130, axis number: 4, value: 0, time: -214620
type: 130, axis number: 5, value: 0, time: -214620
type: 2, axis number: 1, value: 32767, time: -209470
type: 2, axis number: 1, value: 0, time: -209300
type: 2, axis number: 1, value: 32767, time: -209090
type: 2, axis number: 1, value: 0, time: -208960
type: 2, axis number: 1, value: 32767, time: -208840
type: 2, axis number: 1, value: 0, time: -208710
type: 2, axis number: 1, value: 32769, time: -208380
type: 2, axis number: 1, value: 0, time: -208210
type: 1, axis number: 7, value: 1, time: -206910
type: 1, axis number: 7, value: 0, time: -206780
type: 1, axis number: 7, value: 1, time: -206610
type: 1, axis number: 7, value: 0, time: -206570
type: 1, axis number: 7, value: 1, time: -206400
type: 1, axis number: 7, value: 0, time: -206320
type: 1, axis number: 6, value: 1, time: -206280
type: 1, axis number: 6, value: 0, time: -206070
type: 1, axis number: 6, value: 1, time: -205990
type: 1, axis number: 6, value: 0, time: -205860
type: 1, axis number: 4, value: 1, time: -205610
type: 1, axis number: 4, value: 0, time: -205480
type: 1, axis number: 4, value: 1, time: -205350
type: 1, axis number: 4, value: 0, time: -205230

按键是可以获得键值的!!

看了一下逻辑,是键值没有对上

改一下:/linux/joypad_input.cpp文件的这个函数就可以适配我的游戏手柄了

static int USBjoypadGet(void)
{
	/**
	 * FC joypad bitmap 1Byte==8bits
	 * 0  1   2       3       4    5      6     7
	 * A  B   Select  Start  Up   Down   Left  Right
	 */
	//USB joypad every time can read 1 bit, so,need static var save last time value
	static unsigned char joypad = 0;
	struct js_event e;
	if(0 < read (USBjoypad_fd, &e, sizeof(e)))
	{
		//printf("type: %d, axis number: %d, value: %d, time: %d\n", e.type, e.number, e.value, e.time);
		if(0x2 == e.type) // axis
		{
			/*
			up:
			value:0x8001 type:0x2 number:0x1
			value:0x0 type:0x2 number:0x1
			*/
			if(0x8001 == e.value && 0x1 == e.number)
			{
				joypad |= 1<<4;
			}
			
			/*down
			value:0x7fff type:0x2 number:0x1
			value:0x0 type:0x2 number:0x1
			*/
			if(0x7fff == e.value && 0x1 == e.number)
			{
				joypad |= 1<<5;
			}
			//release
			if(0x0 == e.value && 0x1 == e.number)
			{
				joypad &= ~(1<<4 | 1<<5);
			}
			
			/*left
			value:0x8001 type:0x2 number:0x0
			value:0x0 type:0x2 number:0x0
			*/
			if(0x8001 == e.value && 0x0 == e.number)
			{
				joypad |= 1<<6;
			}
			
			/*right
			value:0x7fff type:0x2 number:0x0
			value:0x0 type:0x2 number:0x0
			*/
			if(0x7fff == e.value && 0x0 == e.number)
			{
				joypad |= 1<<7;
			}
			//release
			if(0x0 == e.value && 0x0 == e.number)
			{
				joypad &= ~(1<<6 | 1<<7);
			}
		}

		if(0x1 == e.type) // btn
		{
			/*select
			value:0x1 type:0x1 number:0x8
			value:0x0 type:0x1 number:0x8
			*/
			if(0x1 == e.value && 0x8 == e.number)
			{
				joypad |= 1<<2;
			}
			if(0x0 == e.value && 0x8 == e.number)
			{
				joypad &= ~(1<<2);
			}
			
			/*start
			value:0x1 type:0x1 number:0x9
			value:0x0 type:0x1 number:0x9
			*/
			if(0x1 == e.value && 0x9 == e.number)
			{
				joypad |= 1<<3;
			}
			if(0x0 == e.value && 0x9 == e.number)
			{
				joypad &= ~(1<<3);
			}

			/*A
			value:0x1 type:0x1 number:0x0
			value:0x0 type:0x1 number:0x0
			*/
			if(0x1 == e.value && 0x0 == e.number)
			{
				joypad |= 1<<0;
			}
			if(0x0 == e.value && 0x0 == e.number)
			{
				joypad &= ~(1<<0);
			}

			/*B
			value:0x1 type:0x1 number:0x1
			value:0x0 type:0x1 number:0x1
			*/
			if(0x1 == e.value && 0x1 == e.number)
			{
				joypad |= 1<<1;
			}
			if(0x0 == e.value && 0x1 == e.number)
			{
				joypad &= ~(1<<1);
			}

			/*X
			value:0x1 type:0x1 number:0x2
			value:0x0 type:0x1 number:0x2
			*/
			if(0x1 == e.value && 0x2 == e.number)
			{
				joypad |= 1<<0;
			}
			if(0x0 == e.value && 0x2 == e.number)
			{
				joypad &= ~(1<<0);
			}

			/*Y
			value:0x1 type:0x1 number:0x3
			value:0x0 type:0x1 number:0x3
		 	*/
		 	if(0x1 == e.value && 0x3 == e.number)
			{
				joypad |= 1<<1;
			}
			if(0x0 == e.value && 0x3 == e.number)
			{
				joypad &= ~(1<<1);
			}
		}
		//printf("joypad-value: 0x%02x\n", joypad);
		return joypad;
	}
	return -1;
}

Nice,手柄可以了!完成!

在这里插入图片描述

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值