Usando un Arduino para emular un registro de turno CD4021 para controlar una NES [duplicado]

2

Es probable que esto sea algo tonto cuando puedo esperar a que lleguen mis CD4021 (74HC165Ns) y evitarme la molestia, pero siento que esto se puede hacer y simplemente me estoy perdiendo algo. He estudiado detenidamente toda la documentación que puedo encontrar en la web sobre el protocolo del controlador de NES y cómo emular un registro de desplazamiento de salida en serie y salida de 8 bits de paralelo, pero parece que no logro que funcione correctamente. . Estoy usando interrupciones en el latch y las señales de reloj de la NES y bombeo los bits utilizando la manipulación del puerto, por lo que es un poco feo. Esta es también mi primera vez escribiendo algo similar. Puede que me esté equivocando.

¿Puede alguien decirme qué podría estar haciendo mal? Aquí hay algunos documentos sobre el protocolo NES: enlace y el protocolo SNES: enlace (más detallado pero ligeramente diferente, no estoy seguro en cuál confiar).

Aquí está mi código como está ahora:

#include <Arduino.h>

#define plPin PIND
#define latchPin 2
#define latchShift 2
#define dataPort PORTB
#define dataPin 8
#define dataShift 0
#define dataMask (B00000001 << dataShift)

byte origButtons = B11111111; // Set each bit low (0) to push button.
volatile byte buttons;
volatile byte bit_num = 0;

void setup() {
  pinMode(dataPin, OUTPUT);
  pinMode(latchPin, INPUT);
  dataPort = (dataPort & ~dataMask) | (B00000000 << dataShift);
  attachInterrupt(0, latch, CHANGE);
  attachInterrupt(1, pulse, RISING);
  delay(1);
}

void loop() {

}

void latch() {
  // Check the state of the latch pin to see if we're rising (1) or falling (0).
  if ((plPin & (1 << latchShift)) != 0) {
    // Start pulled high.
    dataPort = (dataPort & ~dataMask) | (B00000001 << dataShift);
  } else {
    // Pull low if A button is pressed at fall of latch pulse.
    dataPort = (dataPort & ~dataMask) | ((buttons >> bit_num) & B00000001) << dataShift;
    bit_num++;
  }
}

void pulse() {
  // On the rising edge of the clock pulse, check for the state of the next button.
  // If the button is pressed, pull (or stay) low. Otherwise, pull high.
  //
  // Bit Math
  // --------------
  // Example values:
  // dataPort: 11111111
  // buttons: 11001100 (1 = HIGH/not pressed - 0 = LOW/pressed)
  // bit_num: 3
  // Reverse the dataMask (result: 11111011).
  // AND that result to the current value of dataPort (result: 11111011).
  // Shift buttons to the right by bit_num (result: 00011001).
  // AND 00000001 to that result so the least significant digit is the value of the current button (result: 00000001).
  // Shift that result by the data pin's position (result: 00000100).
  // OR that with the result from ANDing the reverse of the data mask and the current value of dataPort - see 4 lines up (result: 11111111).
  // Final result: button 3 not pressed.
  if (bit_num == 7) {
    // On the last pulse in a sequence, spit out the last button, wait until it has been sampled by the CPU, and reset the pin to the default low.
    dataPort = (dataPort & ~dataMask) | ((buttons >> bit_num) & B00000001) << dataShift;
    delayMicroseconds(12);
    dataPort = (dataPort & ~dataMask) | (B00000000 << dataShift);
    bit_num = 0;
  } else {
    // Otherwise, just spit out the current button and increment the offset.
    dataPort = (dataPort & ~dataMask) | ((buttons >> bit_num) & B00000001) << dataShift;
    bit_num++;
  }
}
    
pregunta Joshua Whitley

2 respuestas

1

Se compilará lo siguiente. Y debe hacer lo que el SPI esclavo como se discutió anteriormente: Cabe destacar que en una UNO w / 328 que gran parte de los puertos de ancho de bytes no tienen los 8 pines disponibles.

// Note that Port B has the SPI and Port D has the UART so start testing with C[0..5]
// where C[6,7] will likely be zero. Once working then later move to Port D which has
// all 8 bits, but without any debug on the uart.
void setup (void)
{
  pinMode(MISO, OUTPUT); // have to send on master in, *slave out*
  SPCR |= _BV(SPE);      // turn on SPI in slave mode
  SPCR |= _BV(SPIE);     // turn on interrupts
  attachInterrupt(0, latch, FALLING); //pin 2 on UNO, could be other modes...
  // may need to tweak the SPI mode to match chips. Something for later
}  // end of setup

void latch() {
  SPDR = PINC; // grab Port C input and place it for upcoming shift.
}

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  // ISR will occur after 8 bit shift out of prior contents of SPDR 
  // by Master SCLK with SS low
  SPDR = SPDR; // read moSI and write it out on next miSO for cascading.
}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{
  // don't really need to do anything.
}  // end of loop
    
respondido por el mpflaga
1

Lo hice aquí, pero para SNES (16 bits). El mismo código exacto funcionará para NES, ya que NES solo leerá los primeros 8 bits. ¿Alguien tiene código para emular un registro de desplazamiento de entrada de 16 bits con un ATtiny2313?

    
respondido por el joeforker

Lea otras preguntas en las etiquetas