×

Necroware的GamePort适配器开源分享

消耗积分:0 | 格式:zip | 大小:0.06 MB | 2023-06-07

李艺银

分享资料个


pYYBAGR_2WqAEWhMAACq0uqh-Vo600.png
poYBAGR_2W2AUVYDAACA74pWhxU744.png

描述

Necroware 的 GamePort 适配器

许多来自复古社区的人仍然保留着他们早期心爱的操纵杆和游戏手柄。这些设备经常在我们地下室的某个黑暗角落里度过它们的一生,出于怀旧的原因,我们不敢扔掉它们。它们让我们想起了我们的童年,我们在那里玩过我们的 Wing Commanders、X-Wings、Descents 和许多其他游戏。这些旧的游戏杆都是用来连接游戏端口的,通常是在声卡上。但到了 90 年代末和 2000 年初,游戏端口从我们的电脑上消失了,取而代之的是 USB,我们的旧游戏杆也消失在了过去。今天并不是每个人都拥有一台完整的复古 PC,许多人正在使用带有 DOSBox 的现代计算机来玩旧游戏,有时还使用现代 USB 游戏杆。但是不会 用我们当时使用的相同操纵杆玩旧游戏不是很好吗?这就是该适配器发挥作用的地方。它可用于将游戏端口操纵杆连接到 USB 端口。

GamePort 适配器视频:

第 1 部分:简介

第 2 部分:更新

它是如何工作的?

该适配器围绕 Arduino Pro Micro 构建,它使用与 Leonardo 相同的 ATmega32U4 微控制器。该微控制器具有内置 USB HID 功能,可用于构建 HID 输入设备,例如游戏杆。适配器本身超级简单,主要的脑力都花在了软件上。非常简单,它读取操纵杆状态并通过 USB 将数据发送到计算机,计算机认为它正在与 USB 操纵杆通信。

这个有什么特别之处?

已经有很多用于基本模拟游戏杆的游戏端口到 USB 适配器,而且据我所知,微软也在努力与 Sidewinder 游戏杆进行通信。但是没有适用于不同类型操纵杆的通用适配器。该适配器为各种模拟和数字操纵杆实现了多个驱动程序,并可选择在未来添加更多。

功能概述:

支持带有 2/4 按钮和 2/4 轴的通用模拟操纵杆

四个开关选择操纵杆类型

自动检测各种数字协议操纵杆

自动校准

极低的输入延迟

模拟和数字操纵杆有什么区别?

许多人称只有按钮的操纵杆或游戏手柄是数字的。这是对的,因为一个按钮要么被按下,要么没有被按下。两者之间不能有模拟值。然而,在这种情况下,数字意味着不同的东西。一个游戏端口包含 15 个引脚,其中 8 个用于操纵杆通信。4 个引脚用于按钮并承载开/关意义上的数字值,4 个引脚用于模拟轴,其提供介于 0V 和 5V 之间的电压。早期制造的操纵杆使用这种引出线。它们最多可以有 4 个按钮和 4 个轴,并且与 DOS 兼容。后来,在Windows 95/98 时代,许多操纵杆也被制作成可以插入游戏端口,但不限于4 个按钮和4 个轴。他们有很多更令人兴奋的功能,比如帽子开关和油门控制。但这是如何工作的呢?好吧,制造商实施了他们的驱动程序,以使用专有通信协议通过游戏端口与操纵杆通信。例如,通过将游戏端口的一个引脚用作时钟,将另一个引脚用作数据,可能性几乎是无限的。这种操纵杆也称为数字操纵杆,因为它们使用数字协议与 PC 通信。突然之间,许多功能成为可能,但这些功能的代价是失去了与 DOS 的兼容性。你不能只是将这样的操纵杆插入游戏端口并期望它在旧的 DOS 游戏中工作。插头是一样的,但信号完全不同。通过将游戏端口的一个引脚用作时钟,将另一个引脚用作数据,可能性几乎是无限的。这种操纵杆也称为数字操纵杆,因为它们使用数字协议与 PC 通信。突然之间,许多功能成为可能,但这些功能的代价是失去了与 DOS 的兼容性。你不能只是将这样的操纵杆插入游戏端口并期望它在旧的 DOS 游戏中工作。插头是一样的,但信号完全不同。通过将游戏端口的一个引脚用作时钟,将另一个引脚用作数据,可能性几乎是无限的。这种操纵杆也称为数字操纵杆,因为它们使用数字协议与 PC 通信。突然之间,许多功能成为可能,但这些功能的代价是失去了与 DOS 的兼容性。你不能只是将这样的操纵杆插入游戏端口并期望它在旧的 DOS 游戏中工作。插头是一样的,但信号完全不同。不要只是将这样的操纵杆插入游戏端口并期望它可以在旧的 DOS 游戏中运行。插头是一样的,但信号完全不同。不要只是将这样的操纵杆插入游戏端口并期望它可以在旧的 DOS 游戏中运行。插头是一样的,但信号完全不同。

该适配器支持哪些操纵杆?

当前,实现了以下驱动程序。要选择正确的驱动程序,您必须使用四个开关,如表中所示。未来开关可能会发生变化或扩展,请留意更新。

操纵杆模型按钮AxesHatSW1-4评论通用模拟2200000通用模拟4201000通用模拟43001003rd Axis is throttleGeneric Analog4401100CH FlightStick4410010Analog, DOS-compatibleCH F16 Combat Stick10310110Analog, DOS-compatibleThrustMaster43110 10Analog, DOS-compatibleSidewinder GamePad10201110Digital protocolSidewinder 3D Pro8411110Digital protocolSidewinder 3D Pro Plus9411110First version of Precision ProSidewinder Precision Pro9411110Digital protocolSidewinder FFB Pro9411110Digital, FFB not yet implementedSidewinder FFB Wheel8301110Digital,FFB 尚未实现Gravis GamePad Pro10200001Digital protocol (GrIP)Logitech WingMan Extreme6311001Digital protocol (ADI)Logitech CyberMan 28601001Digital protocol (ADI)

评论:

请注意不同系列的数字设备如何使用相同的开关。由于全数字通信,这是可能的。使用此方法,适配器会在知道它已连接到数字游戏杆时立即实施自动检测。

目前,只实现了列出的 Sidewinder 设备的驱动程序,因为我手头没有其他型号。Precision Pro 也可以在 USB 上本地工作,但仍然可以实现,因为我们可以。

Gravis 使用了他们的 GrIP 协议,该协议目前仅适用于 Gravis GamePad Pro,但目前还没有菊花链的可能性。

Logitech 使用的 ADI 协议的实施应该适用于支持该协议的所有设备。然而,目前只有列出的罗技设备经过测试。

测试了哪些操纵杆?

许多野外的操纵杆都使用相同的数字协议,或者向后兼容模拟操纵杆,因为它们在 DOS 时代使用过。以下列表包含其他人报告的到目前为止工作的所有设备:

Gravis Analog Pro(模拟)

Gravis PC GamePad(模拟)

Gravis GamePad Pro

QuickShot QS-123E“勇士5”(模拟)

QuickShot QS-201“超级战士”(模拟)

QuickShot QS-203“复仇者”(模拟)

响尾蛇游戏手柄

响尾蛇 3D Pro

响尾蛇 3D Pro Plus

Sidewinder Precision Pro

Sidewinder ForceFeedBack Pro

Sidewinder 力反馈轮

罗技 WingMan Extreme Digital

罗技 CyberMan 2

InterAct UltraRacer PC(模拟)

Sidewinder 3D Pro 可以在模拟和数字模式之间切换,在模拟模式下它可以模拟 ThrustMaster 和 CH FlightStick。这就是您在上表中看到它们的原因。不幸的是,我在现实中并没有那些操纵杆,所以可能是实现不太正确。

什么是自动校准?

旧的模拟操纵杆内部有电阻,指定为 100 kOhm。不幸的是,这些电阻要么磨损了,要么质量差,要么从一开始就错了。因此,大多数通用模拟操纵杆都有调整螺钉来校正操纵杆的中心点。此外,许多游戏在其设置中都有校准选项以重新调整操纵杆。使用 USB 和新的数字解决方案不再需要校准,并且完全在操纵杆和/或驱动器中实现。许多现代游戏不再提供重新校准操纵杆的选项。如果我们尝试通过此适配器使用旧的模拟摇杆玩此类较新的游戏,摇杆中心点将完全偏移。这就是适配器在内部实现自动校准并将已校正的值呈现给操作系统的原因。

注意:使用模拟操纵杆的硬性要求是在插入 USB 端口期间所有轴必须处于中间状态,因为所有后续校准都是基于初始状态进行的。

对实施的技术见解

代码有很好的文档记录,所以如果您对细节感兴趣,请随时查看驱动程序实现。所有的模拟操纵杆实际上都是一项简单的任务,但 Sidewinder 数字协议有点困难。已经有一些为 Arduino 制作的 Sidewinder 协议的实现。然而,它们大多只适用于 Sidewinder GamePad,并不是真正通用的。最后,我深受 Linux Sidewinder 驱动程序实现的启发。您在该项目中看到的代码是完全重写的,我只是将 Linux 驱动程序实现作为参考来了解其工作原理。Sidewinder 专利 US#5628686A 也有很大帮助,特别是在 Sidewinder 3D Pro 的数字和模拟模式之间切换。

与已经提到的用于 Arduino 实现的 Sidewinder 相反,这个不依赖于中断。此实现与 Linux 驱动程序的功能类似。它轮询端口并由于同步过程使很多事情变得更简单。最大的问题是 Sidwinder 设备发送数据的速度非常快,时钟脉冲只有 5us。不可能为此使用 Arduino 的 digitalRead(...) 函数。在 16MHz 的 Arduino Pro Micro 上每次调用大约 2.7us 太慢了。它根本不可能轮询 5us 脉冲,具有如此缓慢的功能,甚至不考虑对介于两者之间的数据进行处理。因此,出于这种需要,我自己的实现应运而生,在相同的硬件上,它的速度提高了 50%,每次调用只需要大约 1.6us。自定义 I/O 功能使得以 Sidewinder 操纵杆所需的速度读取数据成为可能。最好的部分是代码是用纯 C++ 编写的。它非常易于阅读和使用。没有宏,没有汇编器或任何肮脏的黑客,只有很多优化。

物料清单 (BOM)

硬件超级简单。要构建适配器,您需要该项目的 PCB 和以下部件:

PartQtyLCSC #Digikey #Mouser Electronics #CommentCONN11C77835609-5371-ND523-L77SDA15SA4CH4FDB15 母连接器R1..R44C17296513-MFR-25FTE52-100KCT-ND603-MFR-25FTE52-100K100 kOhm 电阻器SW11 C157812449-KG04ET-ND642-DS04TDIP-4开关U11C72120ED3051-5-ND649-DILB24P -223TLFDIP24 插座(可选)U11N/A1568-1060-ND474-DEV-12640Arduino Pro Micro(ATmega32U4 16MHz,5V),包括两个 12 针接头连接器,MicroUSB 版本(参见“已知问题”)

已知的问题

模拟操纵杆上的一些轴偏移

自动校准要求所有轴在初始化时都处于中心位置。请参阅有关自动校准的段落。

操纵杆不工作

确保您使用的是受支持的操纵杆之一或可以在传统模拟模式下工作的操纵杆

Arduino 上的 MicroUSB 端口不够稳定

请改用 Arduino 的 USB-C 版本。

或者始终将 MicroUSB 电缆连接到 Arduino MicroUSB 版本,以避免进一步磨损,并仅在电缆的远端进行插拔操作。

如何帮助项目?

最好的方法是实现更多的驱动程序。因为我只有上面提到的操纵杆,所以我不能贡献比目前包含的更多的东西。

 

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'Necroware的GamePort适配器开源分享',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);