Esto es probablemente una tontería cuando puedo esperar a que lleguen mis CD4021 (74HC165N) y ahorrarme la molestia, pero siento que esto se puede hacer y simplemente me falta 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 entrada en serie y salida en paralelo de 8 bits, pero parece que no puedo hacer que funcione correctamente. . Estoy usando interrupciones en el pestillo y las señales de reloj de la NES y bombeando los bits usando la manipulación del puerto, así que es un poco feo. Esta es también la primera vez que escribo algo similar. Puede que me esté equivocando en el momento.
¿Alguien puede decirme qué puedo estar haciendo mal? Aquí hay alguna documentación sobre el protocolo NES: http://www.mit.edu/~tarvizo/nes-controller.html , y el protocolo SNES: http://www.repairfaq.org/REPAIR/F_SNES.html (más detallado pero ligeramente diferente, no estoy seguro en cuál confiar).
Aquí está mi código tal 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++;
}
}
Lo siguiente se compilará. Y debería hacer lo que el Slave SPI como se discutió anteriormente: Vale la pena señalar que en un UNO con 328, gran parte de los puertos de ancho de byte 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
Lo hice aquí, pero para SNES (16 bits). Exactamente el mismo código funcionará para NES, ya que NES solo leerá los primeros 8 bits. ¿Alguien tiene un código para emular un registro de desplazamiento de entrada de 16 bits con un ATtiny2313?
Ignacio Vázquez-Abrams
Josué Whitley
Ignacio Vázquez-Abrams
mpflaga
Josué Whitley
Ignacio Vázquez-Abrams
mpflaga
Ignacio Vázquez-Abrams
mpflaga
mpflaga
Josué Whitley
Josué Whitley