所有关于电路
项目

NES控制器接口与Arduino Uno

2016年4月29日经过Joseph Corleto.

了解NES控制器的数据协议,然后使用此知识轻松集成到Arduino Uno中。

任天堂娱乐系统,也被称为NES控制台,曾经是所有视频游戏系统的王。

是时候接管世界了。

如今,这些非常陈旧,只有最怀旧的游戏玩家会起来。对于那些已经搬到现代制度或只是试图跟上当天工作的人来说,NES已成为尘埃收藏家。但是,如果您用电子产品修补,NES可以在DIY世界中使用易于黑客控制器变得强大。NES控制器可以将灯光从灯光控制到机器人,甚至到您的世界末日设备 - 可能会转向您的想象力!对于这个项目,我们将不超过Arduino Uno和NES控制器来演示它对接口的简单。

BOM.

硬件:

  • Arduino Uno.
  • 面包板线跳线
  • NES控制器(原始或其他)
  • 面包板(可选)
  • NES延长线(可选)

软件:

  • Arduino IDE

理论

如果您打开NES控制器,您会发现它真的有多么简单和优雅。它由不超过移位寄存器和一些上拉电阻组成。具体地,它是一个平行的串联,短暂的PISO。在这些控制器内使用的移位寄存器是4021.虽然没有必要了解本项目中的Arduino代码,但可以找到典型版本的数据表这里对于好奇的读者。

对于更加好奇的读者,可以读取移位寄存器的理论和操作这里

下面可以在4021实现的方式。这是NES控制器如何在内部看的原理图。

如您所见,4021是一个8位寄存器,足以让所有八个按钮连接到它。每个按钮的一侧被绑定到地,而每个开关的另一端进入移位寄存器上的单独数据。为了在寄存器的数据输入上保留定义的状态,使用上拉电阻。这意味着什么时候没有按下按钮,移位寄存器将解释逻辑“1”。如果按下按钮,则移位寄存器将解释逻辑“0”。这很重要,因为这是用户输入首次出现的位置。

对于从数据行“抓取”输入的移位寄存器,它需要一个陈述要执行此操作的信号。这就是闩锁线是什么。通过低高低的锁存线过渡,坐在换档寄存器引脚上的按钮状态将被锁定到寄存器中。高度的持续时间可以很短,但是对于参考,NES协议将为大约12微秒进行此操作。锁存数据后,第一个按钮状态可在数据线上可用。每当时钟引脚以相同的方式脉冲时,数据线将滚动按钮状态。这意味着在锁存数据后,七次时钟将排出按钮状态的所有数据。在Arduino码中清楚地描述将串行发送的按钮的确切顺序。

要总结,Arduino代码必须执行以下操作:

  • 脉冲锁存线,使移位寄存器可以“抓住”数据。

  • 读取数据引脚并保存此按钮状态。

  • 脉冲时钟线+保存此按钮状态。

  • 重复步骤3六次。

  • 用这些数据做一些酷!

为了更好地了解NES控制器的建设,您可以随时打开它。虽然这是完全可选的,但它为您提供了更好的了解如何在产品设计和电子组装方面建立自己的产品和更好的经验。要启动拆卸,您需要使用小型菲利普斯头螺丝刀。控制器背面将有六个螺钉。

拧下他们时,要小心。这些螺钉在更便宜的一侧有点稍微,所以它们会轻松剥离。一定要找到螺丝刀,让您在转动螺钉时施加充足的压力。一旦螺钉出来,将控制器朝下的按钮。然后,轻轻抬起后侧。

您现在将公开PCB的一侧。特别是该PCB由酚醛制成,这在消费电子产品中是常见的,因为它可以更便宜。然而,作为备注,大多数优质的PCB由玻璃环氧树脂制成。除了PCB之外,您可以在滑动视线中看到4021 IC以及连接到电缆的电线。你必须钦佩简单的任天堂工程师在仍然是非常有用的同时,所有的IC。要查看PCB的另一侧,请轻轻抬起电路板。您可能会根据控制器已变得有多脏(有些非常脏!)取决于它的橡胶垫。如果是这种情况,请在将它们拉下没有损害,以便您可以检查PCB。如果您仔细观察迹线,您可以注意到它们是手绘的。因为CAD接管了这个行业,因此必须是一个非常艰苦的过程。 You might notice that there are no resistors on this side. But to the skilled eye, they are in plain sight. They are actually the black rectangles with the shiny green surface to them. These are carbon resistors that were directly printed on the PCB to save time and money. And since they are all the same value, it was probably the ideal solution at the time. The last thing to take away from the controller are the button contacts and the rubber button pads. These work by having the black, circular part of the rubber pad bridge a connection across the carbon deposited button contacts. Though it does not appear conductive, it is enough to register a logic high or low for the button states.

把它拉开

随着NES控制器的连接器端,该项目的接线很简单,易于探测面板电线。当然,如果您想要更安全的东西,建议购买NES控制器延长电缆,并将其剪切剪切,以便您可以轻松地从那里抓住电线。这样,您可以直接将其插入Arduino,同时具有安全连接和控制器端。

下面显示了如何使用此宝石。

如您所见,控制器只需要其中的7个引脚中的5个接口。两个用于电源(+ 5V和GND),一个用于锁存按钮状态(D2),一个用于时钟按钮状态(D3),以及用于读取按钮状态的串行数据(D4)。

Arduino Code.


此代码大量评论为描述状态的流程和操作顺序。在所有这些结束时,您将在串行监视器中看到弹出的按钮状态。串行监视器中的代码将为您清楚地了解如何将其界面到下一个世界末日设备无害的电子项目。这里的Arduino代码应该与理论部分相一致,它应该是一个彻底的逐步过程,但是,如果您需要更多的解释,请评论以下。如果您想要更快的回复,论坛也是一个非常好的提问。

/ * ================================================================================文件........... nes控制器测试代码目的。。。。。。。。To demonstrate how to interface to an NES controller Author......... Joseph Corleto E-mail......... corleto.joseph @ gmail.com Started........ 04/13/2016 Finished....... 04/14/2016 Updated........ --/--/---- ================================================================================ Notes ================================================================================ - The NES controller contains one 8-bit 4021 shift register inside. - This register takes parallel inputs and converts them into a serial output. - This code first latches the data and then shifts in the first bit on the data line. Then it clocks and shifts in on the data line until all bits are received. - What is debugged are the button states of the NES controller. - A logical "1" means the button is not pressed. A logical "0" means the button is pressed. - This code shifts the first bit of data into the LSB. - The order of shifting for the buttons is shown in the table below: Bit# | Button -------------- 0 | A -------------- 1 | B -------------- 2 | Select -------------- 3 | Start -------------- 4 | Up -------------- 5 | Down -------------- 6 | Left -------------- 7 | Right -------------- - The NES controller pinout is shown below (looking into controllers connector end): __________ / | / O 1 | 1 - Ground | | 2 - Clock | 7 O O 2 | 3 - Latch | | 4 - Data Out | 6 O O 3 | 5 - No Connection | | 6 - No Connection | 5 O O 4 | 7 - +5V |___________| - Please visit vs-visa.com to search for complete article! ================================================================================ Updates ================================================================================ */ //=============================================================================== // Header Files //=============================================================================== //=============================================================================== // Constants //=============================================================================== // Here we have a bunch of constants that will become clearer when we look at the // readNesController() function. Basically, we will use these contents to clear // a bit. These are chosen according to the table above. const int A_BUTTON = 0; const int B_BUTTON = 1; const int SELECT_BUTTON = 2; const int START_BUTTON = 3; const int UP_BUTTON = 4; const int DOWN_BUTTON = 5; const int LEFT_BUTTON = 6; const int RIGHT_BUTTON = 7; //=============================================================================== // Variables //=============================================================================== byte nesRegister = 0; // We will use this to hold current button states //=============================================================================== // Pin Declarations //=============================================================================== //Inputs: int nesData = 4; // The data pin for the NES controller //Outputs: int nesClock = 2; // The clock pin for the NES controller int nesLatch = 3; // The latch pin for the NES controller //=============================================================================== // Initialization //=============================================================================== void setup() { // Initialize serial port speed for the serial terminal Serial.begin(9600); // Set appropriate pins to inputs pinMode(nesData, INPUT); // Set appropriate pins to outputs pinMode(nesClock, OUTPUT); pinMode(nesLatch, OUTPUT); // Set initial states digitalWrite(nesClock, LOW); digitalWrite(nesLatch, LOW); } //=============================================================================== // Main //=============================================================================== void loop() { // This function call will return the states of all NES controller's register // in a nice 8 bit variable format. Remember to refer to the table and // constants above for which button maps where! nesRegister = readNesController(); // Slight delay before we debug what was pressed so we don't spam the // serial monitor. delay(180); // To give you an idea on how to use this data to control things for your // next project, look through the serial terminal code below. Basically, // just choose a bit to look at and decide what to do whether HIGH (not pushed) // or LOW (pushed). What is nice about this test code is that we mapped all // of the bits to the actual button name so no useless memorizing! if (bitRead(nesRegister, A_BUTTON) == 0) Serial.println("JUMP!"); if (bitRead(nesRegister, B_BUTTON) == 0) Serial.println("PUNCH!"); if (bitRead(nesRegister, START_BUTTON) == 0) Serial.println("DOOMSDAY ACTIVATED"); if (bitRead(nesRegister, SELECT_BUTTON) == 0) Serial.println("WHY DON'T YOU MAP SOMETHING HERE?"); if (bitRead(nesRegister, UP_BUTTON) == 0) Serial.println("...OR HERE?"); if (bitRead(nesRegister, DOWN_BUTTON) == 0) Serial.println("PLAY WITH THE CODE ALREADY!"); if (bitRead(nesRegister, LEFT_BUTTON) == 0) Serial.println("MAKE SOMETHING WITH THIS!"); if (bitRead(nesRegister, RIGHT_BUTTON) == 0) Serial.println("GOOD LUCK WITH YOUR PROJECT "); } //=============================================================================== // Functions //=============================================================================== /////////////////////// // readNesController // /////////////////////// byte readNesController() { // Pre-load a variable with all 1's which assumes all buttons are not // pressed. But while we cycle through the bits, if we detect a LOW, which is // a 0, we clear that bit. In the end, we find all the buttons states at once. int tempData = 255; // Quickly pulse the nesLatch pin so that the register grab what it see on // its parallel data pins. digitalWrite(nesLatch, HIGH); digitalWrite(nesLatch, LOW); // Upon latching, the first bit is available to look at, which is the state // of the A button. We see if it is low, and if it is, we clear out variable's // first bit to indicate this is so. if (digitalRead(nesData) == LOW) bitClear(tempData, A_BUTTON); // Clock the next bit which is the B button and determine its state just like // we did above. digitalWrite(nesClock, HIGH); digitalWrite(nesClock, LOW); if (digitalRead(nesData) == LOW) bitClear(tempData, B_BUTTON); // Now do this for the rest of them! // Select button digitalWrite(nesClock, HIGH); digitalWrite(nesClock, LOW); if (digitalRead(nesData) == LOW) bitClear(tempData, SELECT_BUTTON); // Start button digitalWrite(nesClock, HIGH); digitalWrite(nesClock, LOW); if (digitalRead(nesData) == LOW) bitClear(tempData, START_BUTTON); // Up button digitalWrite(nesClock, HIGH); digitalWrite(nesClock, LOW); if (digitalRead(nesData) == LOW) bitClear(tempData, UP_BUTTON); // Down button digitalWrite(nesClock, HIGH); digitalWrite(nesClock, LOW); if (digitalRead(nesData) == LOW) bitClear(tempData, DOWN_BUTTON); // Left button digitalWrite(nesClock, HIGH); digitalWrite(nesClock, LOW); if (digitalRead(nesData) == LOW) bitClear(tempData, LEFT_BUTTON); // Right button digitalWrite(nesClock, HIGH); digitalWrite(nesClock, LOW); if (digitalRead(nesData) == LOW) bitClear(tempData, RIGHT_BUTTON); // After all of this, we now have our variable all bundled up // with all of the NES button states.*/ return tempData; }

未来的想法

如果您喜欢这个项目并学习了如何良好地接口NES控制器,那么SNES控制器几乎是相同的想法,但具有更大的移位寄存器(16位而不是8位)。

快乐的黑客攻击!

nes_controller_test_code.zip.

为自己提供这个项目!得到bom。

9评论
  • G
    Gtilles. 2016年4月29日

    简单直截了当,迫不及待地试试。

    喜欢。 回复
  • D.
    daniel_gamerpro. 2016年6月13日

    作为识别的控制窗口?/ como hago funcionar el control con Windows Una Vez Pasado El Codigo Al Arduino ??

    喜欢。 回复