当前位置: 首页 > news >正文

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

文章目录

  • 一、前言
  • 二、下载、解压、更改配置,编译源码
    • 下载源码
    • 解压出来
    • 配置源码
    • 运行
  • 二、添加USB手柄:搞定了

一、前言

参考博客: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,手柄可以了!完成!

在这里插入图片描述

相关文章:

  • 查看笔记本电池健康度的两种方法和电池报告解析
  • 神经网络自适应pid控制器,基于神经网络的pid控制
  • Leetcode 1441. 用栈操作构建数组
  • 数据结构与算法分析之排序算法
  • 利用STM32CubeMX快速创建点灯带调试输出工程案例
  • new 和 delete 为什么要匹配使用
  • 00后表示真干不过,部门新来的00后测试员已把我卷崩溃,想离职了...
  • 3年测试在职,月薪还不足20K,惨遭裁员,用亲身经历给大家提个醒..
  • 【从小白到大白03】类和对象-下
  • [DAX] MAX函数 | MAXX函数
  • Pytorch实战 | 第4天:猴痘病识别
  • 【C ++基础】第五篇 类和对象 日期计算器
  • SpringBoot+Vue实现前后端分离大学信息及院校推荐网站
  • 编程初学者如何缓解迷茫和焦虑?墙裂推荐此文,助你赢在起跑线
  • [创业之路-42] 创业是只有一小部分人活下来的游戏,探究创业失败的20个主要原因与提高成功率
  • .pyc 想到的一些问题
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 2017-09-12 前端日报
  • AHK 中 = 和 == 等比较运算符的用法
  • Babel配置的不完全指南
  • C学习-枚举(九)
  • Javascript编码规范
  • leetcode讲解--894. All Possible Full Binary Trees
  • linux安装openssl、swoole等扩展的具体步骤
  • Phpstorm怎样批量删除空行?
  • SOFAMosn配置模型
  • uva 10370 Above Average
  • 代理模式
  • 飞驰在Mesos的涡轮引擎上
  • 简析gRPC client 连接管理
  • 前言-如何学习区块链
  • 浅谈Golang中select的用法
  • 实现菜单下拉伸展折叠效果demo
  • 微服务框架lagom
  • 学习HTTP相关知识笔记
  • 云大使推广中的常见热门问题
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)linux 命令大全
  • (转)mysql使用Navicat 导出和导入数据库
  • (转载)深入super,看Python如何解决钻石继承难题
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET 指南:抽象化实现的基类
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • @staticmethod和@classmethod的作用与区别
  • [ IO.File ] FileSystemWatcher
  • [52PJ] Java面向对象笔记(转自52 1510988116)
  • [Android Studio 权威教程]断点调试和高级调试
  • [Android]Android P(9) WIFI学习笔记 - 扫描 (1)
  • [docker] Docker容器服务更新与发现之consul
  • [Flex] PopUpButton系列 —— 控制弹出菜单的透明度、可用、可选择状态