ARM Linux DIY(十二)NES 游戏
文章目录
- 前言
- 交叉编译工具链使能 C++
- nes 游戏模拟器移植
- 游戏手柄调试
前言
很多小伙伴为了不让自己的 V3s 吃灰,进而将其打造成游戏机。
我们 DIY 的板子具备屏幕、扬声器、USB Host(可以接游戏手柄),当然也要凑一凑热闹。
交叉编译工具链使能 C++
怎么突然讲到工具链了?
因为待会 nes 游戏模拟器编译需要用到 C++,所以就先提前讲一下

这里遇到了一个坑,编译 g++ 时,依赖一些库,这些库是我之前没有使能 g++ 时编的,现在使能 g++ 后需要重新编,不然 g++ 编译有问题,一开始我没发现这个问题,怎么编都有问题。
host-gcc-final-12.3.0/ 就是其中一个依赖,将这个目录手动删除,然后重新编译整个工程,g++ 就编译 OK 了。
nes 游戏模拟器移植
源码:https://github.com/nejidev/arm-NES-linux
step1:
修改交叉编译链
CC=/home/liyongjun/project/board/buildroot/DIY_V3S/host/bin/arm-buildroot-linux-gnueabihf-gcc
CCFLAGS += -I /home/liyongjun/project/board/buildroot/DIY_V3S/staging/usr/include
LDFILGS += -L /home/liyongjun/project/board/buildroot/DIY_V3S/staging/usr/lib
step2:
修改 InfoNES_System_Linux.cpp 文件中的 lcd_fb_display_px 函数 (调整 spi 屏幕的颜色)
static int lcd_fb_display_px(WORD color, int x, int y)
{
#if 0unsigned char *pen8;unsigned short *pen16;pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);pen16 = (unsigned short *)pen8;*pen16 = color;return 0;
#endifWORD *pen16;unsigned char r, g, b;r = ((color >> 10) & 0x1f);g = ((color >> 5) & 0x3f);b = (color & 0x1f);color = r<<11|g<<6|b;pen16 = (WORD *)(fb_mem + y*line_width + x*px_width);*pen16 = color;return 0;
}
step3:
下载游戏合集并解压,然后改名为游戏名为英文
链接:https://pan.baidu.com/s/16hIWwYQQEX9aOBDG1dVa0A
提取码:asdf
step4:
运行
root@v3s-diy:~/nes# ./InfoNES rom/218_hdl.nes
/dev/joypad dev not found
/dev/input/js0 dev not found
fb width:240 height:240

游戏手柄调试
插入游戏手柄
root@v3s-diy:~# ls /dev/input/
event0
root@v3s-diy:~#
[ 126.159751] usb 1-1.2: new low-speed USB device number 4 using ehci-platform
[ 126.421937] input: USB gamepad as /devices/platform/soc/1c1a000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:081F:E401.0002/input/input2
[ 126.435728] hid-generic 0003:081F:E401.0002: input: USB HID v1.10 Joystick [USB gamepad] on usb-1c1a000.usb-1.2/input0
root@v3s-diy:~# ls /dev/input/
event0 event1 js0
运行游戏
root@v3s-diy:~/nes# ./InfoNES rom/218_hdl.nes
/dev/joypad dev not found
fb width:240 height:240
发现游戏手柄按键没有反应
不过,监听 /dev/input/event1 发现按键是有事件产生的
root@v3s-diy:~/nes# hexdump /dev/input/event1
0000000 c086 0003 fa8b 000e 0004 0004 0003 0009
0000010 c086 0003 fa8b 000e 0001 0122 0001 0000
0000020 c086 0003 fa8b 000e 0000 0000 0000 0000
0000030 c087 0003 0a0b 0002 0004 0004 0003 0009
0000040 c087 0003 0a0b 0002 0001 0122 0000 0000
0000050 c087 0003 0a0b 0002 0000 0000 0000 0000
0000060 c087 0003 c80b 000c 0004 0004 0001 0009
0000070 c087 0003 c80b 000c 0001 0120 0001 0000
0000080 c087 0003 c80b 000c 0000 0000 0000 0000
0000090 c087 0003 19cb 000f 0004 0004 0001 0009
00000a0 c087 0003 19cb 000f 0001 0120 0000 0000
00000b0 c087 0003 19cb 000f 0000 0000 0000 0000
00000c0 c089 0003 114f 0006 0003 0000 00ff 0000
00000d0 c089 0003 114f 0006 0000 0000 0000 0000
00000e0 c089 0003 6309 0008 0003 0000 007f 0000
00000f0 c089 0003 6309 0008 0000 0000 0000 0000
那大概率是游戏手柄按键和模拟器设定不匹配
在获取按键值的地方加点打印,记录按键值
// arm-NES-linux/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))){
printf("e.type = 0x%x\t", e.type);
printf("e.value = 0x%x\t", e.value);
printf("e.number = 0x%x\n", e.number);if(0x2 == e.type){/*上:value:0x8001 type:0x2 number:0x5value:0x0 type:0x2 number:0x5*/if(0x8001 == e.value && 0x5 == e.number)
然后将各个按键值改正确
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))){
printf("e.type = 0x%x\t", e.type);
printf("e.value = 0x%x\t", e.value);
printf("e.number = 0x%x\n", e.number);if(0x2 == e.type){/* 上 */if(0x8001 == e.value && 0x1 == e.number){joypad |= 1<<4;}/* 下 */if(0x7fff == e.value && 0x1 == e.number){joypad |= 1<<5;}//松开if(0x0 == e.value && 0x1 == e.number){joypad &= ~(1<<4 | 1<<5);}/* 左 */if(0x8001 == e.value && 0x0 == e.number){joypad |= 1<<6;}/* 右 */if(0x7fff == e.value && 0x0 == e.number){joypad |= 1<<7;}//松开if(0x0 == e.value && 0x0 == e.number){joypad &= ~(1<<6 | 1<<7);}}if(0x1 == e.type){/* 选择 */if(0x1 == e.value && 0x8 == e.number){joypad |= 1<<2;}if(0x0 == e.value && 0x8 == e.number){joypad &= ~(1<<2);}/* 开始 */if(0x1 == e.value && 0x9 == e.number){joypad |= 1<<3;}if(0x0 == e.value && 0x9 == e.number){joypad &= ~(1<<3);}/* A */if(0x1 == e.value && 0x1 == e.number){joypad |= 1<<0;}if(0x0 == e.value && 0x1 == e.number){joypad &= ~(1<<0);}/* B */if(0x1 == e.value && 0x2 == e.number){joypad |= 1<<1;}if(0x0 == e.value && 0x2 == e.number){joypad &= ~(1<<1);}/* X */if(0x1 == e.value && 0x0 == e.number){joypad |= 1<<0;}if(0x0 == e.value && 0x0 == e.number){joypad &= ~(1<<0);}/* Y */if(0x1 == e.value && 0x3 == e.number){joypad |= 1<<1;}if(0x0 == e.value && 0x3 == e.number){joypad &= ~(1<<1);}}return joypad;}
printf("read failed!!!\n");return -1;
}
就可以愉快地玩游戏了

相关文章:
ARM Linux DIY(十二)NES 游戏
文章目录 前言交叉编译工具链使能 Cnes 游戏模拟器移植游戏手柄调试 前言 很多小伙伴为了不让自己的 V3s 吃灰,进而将其打造成游戏机。 我们 DIY 的板子具备屏幕、扬声器、USB Host(可以接游戏手柄),当然也要凑一凑热闹。 交叉编…...
MOEA算法的背景知识
MOEA算法 多目标进化算法优化MOEA工作原理举个例子 为什么单一策略可能会导致种群中的个体过于相似?种群在MOEA里面做什么?举例说明 多目标进化算法优化MOEA Multi-objective evolutionary algorithm optimization (MOEA) 多目标进化算法优化࿰…...
【rtp-benchmarks】读取本地文件基于uvgRtp实现多线程发送
input 文件做内存映射 : get_mem D:\XTRANS\soup\uvg-rtp-dev\rtp-benchmarks\util\util.cc 文件中读取chunksize 到 vector 里作为chunks 创建多个线程进行发送 std::vector<std::thread*> threads;...
fire-voc 火光 烟火 火灾 目标检测数据集
一年中最容易引发火灾的季节是在冬季,主要原因有这样几点。 1、秋冬季节,随着用火、用电、用气增加,加上天气干燥,棉花、木材 、衣物等物体内含有的水分也较低。2、秋冬季风力较大,一旦有火苗冒起就很容易随风蔓延,是火灾的高发期。3、春季也是火灾多发季节&#x…...
【力扣1462】课程表(拓扑排序+bitset优化到O(n))
题目描述: 你总共需要上 numCourses 门课,课程编号依次为 0 到 numCourses-1 。你会得到一个数组 prerequisite ,其中 prerequisites[i] [ai, bi] 表示如果你想选 bi 课程,你 必须 先选 ai 课程。 有的课会有直接的先修课程&am…...
【AI】机器学习——支持向量机(非线性及分析)
5. 支持向量机(线性SVM) 文章目录 5.4 非线性可分SVM5.4.1 非线性可分问题处理思路核技巧核函数特点 核函数作用于SVM 5.4.2 正定核函数由 K ( x , z ) K(x,z) K(x,z) 构造 H \mathcal{H} H 空间步骤 常用核函数 5.5 SVM参数求解算法5.6 SVM与线性模型关系 5.4 非线性可分SVM …...
2023-09-20 LeetCode每日一题(拿硬币)
2023-09-20每日一题 一、题目编号 LCP 06. 拿硬币二、题目链接 点击跳转到题目位置 三、题目描述 桌上有 n 堆力扣币,每堆的数量保存在数组 coins 中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。 示…...
Java21的新特性
Java语言特性系列 Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java18的新特性Java19的新特性Java20的新特性Java21的新特性Java22…...
测试-----selenuim webDriver
文章目录 1.页面导航2.元素定位3. 浏览器操作4.获取元素信息5. 鼠标的操作6. 键盘操作7. 元素等待8.下拉框9.弹出框10.滚动条11.frame处理12.验证码处理(cookie) 1.页面导航 首先是导入对应的包 :from selenium import webdriver然后实例化:driver web…...
21天学会C++:Day12----初始化列表
CSDN的uu们,大家好。这里是C入门的第十一讲。 座右铭:前路坎坷,披荆斩棘,扶摇直上。 博客主页: 姬如祎 收录专栏:C专题 目录 1. 初始化列表 1.1 引入 1.2 初始化列表 1.3 初始化列表的注意事项 1.…...
OpenAI开发系列(二):大语言模型发展史及Transformer架构详解
全文共1.8w余字,预计阅读时间约60分钟 | 满满干货,建议收藏! 一、介绍 在2020年秋季,GPT-3因其在社交媒体上病毒式的传播而引发了广泛关注。这款拥有超过1.75亿参数和每秒运行成本达到100万美元的大型语言模型(Large …...
Gson - 一个Java序列化/反序列化库
官网 GitHub - google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back 项目简介 一个Java序列化/反序列化库,用于将Java对象转换为JSON和返回JSON。 Gson is a Java library that can be used to convert Java…...
6-1 汉诺塔
汉诺(Hanoi)塔问题是一个经典的递归问题。 设有A、B、C三个塔座;开始时,在塔座A上有若干个圆盘,这些圆盘自下而上,由大到小地叠在一起。要求将塔座A上的圆盘移到塔座B上,并仍按同样顺序叠放。在…...
Linux之initd管理系统(海思、ZYNQ、复旦微)添加密码登录验证
设置root用户密码:passwd命令设置密码,即修改/etc/passwd文件 一、串口提示输入用户名密码方法 修改 /etc/inittab 方法一: 增加: ::askfirst:-/bin/login 注释: #::respawn:/sbin/getty -L ttyS000 115200 vt…...
怎么更改代理ip,代理ip如何切换使用?
我们要如何使用HTTP代理,对它进行切换使用呢? 如果你购买了青果网络的HTTP代理,可以在文档这边获取使用方法: 可以在这里调试: 也可以在这里选择key提取。 如果有的朋友们想利用利用python,每隔30秒使用API…...
【C++从0到王者】第三十三站:AVL树
文章目录 前言一、AVL 树的概念二、AVL树的实现1. AVL树的结点定义2. AVL树的插入之插入部分3. AVL树的插入之平衡因子的改变4. AVL树的插入之左旋5. AVL树的左旋抽象图6.AVL树的右旋抽象图7. AVL树的双旋8. AVL树的右左双旋9. AVL树的右左双旋的本质10. AVL树的左右双旋11. AV…...
手机机型响应式设置2
window.screen.height:屏幕高度 window.innerHeight:视口高度(去除浏览器头尾的高度) document.body.clientHeight:内容高度 vh:网页视口高度的1/100 vw:网页视口宽度的1/100 vmaxÿ…...
uni-app 之 解决u-button始终居中问题
uView中u-button始终居中问题如何解决的简单方法? 1:给该元素margin-right: 0;可以达到向右靠齐; 2:给该元素的父元素设置float: right image.png <u-button style"width: 50px; margin-left: 0;" plain"t…...
Python日期处理库:掌握时间的艺术
💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 日期和时间在计算机编程…...
JOSEF约瑟 智能电流继电器KWJL-20/L KWLD26 零序孔径45mm 柜内导轨式安装
KWJL-20智能电流继电器 零序互感器: KWLD80 KWLD45 KWLD26 KWJL-20 一、产品概述 KWJL-20系列智能剩余电流继电器(以下简称继电器)适用于交流电压至660V或更高的TN、TT、和IT系统,频率为50Hz。通过零序电流互感器检测出超过…...
【STM32HAL库实战】DAC精准输出0-3.3V可调电压与ADC自检闭环
1. DAC与ADC的基础原理 在嵌入式系统中,数字信号和模拟信号的相互转换是常见需求。STM32微控制器内置了DAC(数字模拟转换器)和ADC(模拟数字转换器)模块,让我们能够轻松实现这种转换。 DAC的作用是将数字量转…...
CLAP Zero-Shot Audio Classification Dashboard部署教程:HTTPS反向代理配置(Nginx)保障生产环境访问安全
CLAP Zero-Shot Audio Classification Dashboard部署教程:HTTPS反向代理配置(Nginx)保障生产环境访问安全 1. 为什么需要HTTPS反向代理 当你成功部署了CLAP音频分类应用后,可能会发现直接通过HTTP访问存在一些安全问题。在生产环…...
Qwen2.5-VL-3B视频识别实战:从环境搭建到显存优化的踩坑记录
Qwen2.5-VL-3B视频识别实战:从环境搭建到显存优化的全流程指南 当开发者第一次尝试用Qwen2.5-VL-3B处理视频内容时,往往会遇到各种预料之外的挑战。从依赖包缺失到显存爆炸,从环境配置到参数调试,每一步都可能成为阻碍项目推进的绊…...
【Python内存管理2026权威白皮书】:GIL演进、引用计数重构与GC智能调度三大突破性策略首次公开
第一章:Python智能体内存管理策略2026最新趋势全景概览随着大语言模型驱动的Python智能体(Agent)在生产环境中的深度部署,传统CPython内存管理机制正面临前所未有的挑战:动态工具调用、多轮推理缓存、跨Agent状态共享及…...
手把手教你用Swaks和Gophish绕过SPF,搭建自己的邮件钓鱼测试环境(附避坑指南)
企业级邮件安全测试实战:从SPF绕过到钓鱼环境搭建 邮件安全测试已成为企业安全防护体系中不可或缺的一环。据统计,超过90%的网络攻击始于钓鱼邮件,而其中近40%的成功攻击源于SPF配置不当或完全缺失。本文将系统性地介绍如何构建一个完整的邮件…...
避坑指南:Double DQN和Dueling DQN在TensorFlow 2.x中的5个常见实现错误
Double DQN与Dueling DQN在TensorFlow 2.x中的五大工程陷阱与解决方案 当你在深夜调试强化学习模型时,是否遇到过这种情况:训练曲线像过山车一样剧烈波动,明明采用了Double DQN或Dueling DQN这些改进算法,效果却比基础DQN还要差&a…...
别再让收款语音卡顿!UniApp + WebSocket 实现流畅支付播报的完整避坑指南
UniApp WebSocket 支付语音播报实战:从性能优化到高并发处理 在移动支付场景中,实时语音播报不仅是用户体验的关键环节,更是商户经营效率的重要保障。想象这样的场景:高峰时段,收银台前排队等待的顾客,收银…...
STM32姿态报警器设计:MPU6050与卡尔曼滤波实战
基于STM32的姿态翻转报警器设计与实现1. 项目概述1.1 系统架构本姿态翻转报警系统采用模块化设计,核心架构由STM32F103RCT6微控制器作为主控单元,通过I2C接口连接MPU6050惯性测量单元(IMU)传感器,实时采集设备的三轴加速度和三轴角速度数据。…...
SOONet效果展示:多查询并行定位——‘倒水’‘接电话’‘写笔记’三任务同步响应
SOONet效果展示:多查询并行定位——‘倒水’‘接电话’‘写笔记’三任务同步响应 1. 引言:当视频搜索变得像说话一样简单 想象一下,你有一段长达一小时的会议录像,现在需要快速找到“张三站起来发言”、“李四在白板上画图”以及…...
抖音批量下载终极指南:免费无水印视频一键获取
抖音批量下载终极指南:免费无水印视频一键获取 【免费下载链接】douyin-downloader 项目地址: https://gitcode.com/GitHub_Trending/do/douyin-downloader 你是否曾为保存喜欢的抖音视频而烦恼?面对心仪的内容创作者,想要收藏他们的…...
