Forum: Mikrocontroller und Digitale Elektronik Neuling: Latch Signal an Spielekonsole auslesen


von Thomas M. (sirius93)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
Ich bin ein ziemlicher Noob was das Arbeiten mit Microcontrollern 
angeht, deshalb versuche ich jetzt mal hier etwas Hilfe zu bekommen.
Zu meiner Ausrüstung und meinem Projekt: Ich habe einen Arduino Uno und 
möchte damit die Inputs meines Controllers an einer Spielekonsole 
„steuern“.
Genaugenommen möchte ich später ein Programm schreiben, dass bestimmte 
Inputs abarbeitet, aber so weit bin ich noch nicht. Es handelt sich um 
den Super Nintendo, da habe ich mir eine Verlängerung für den Controller 
beschafft und diese mit meiner Konsole und dem Arduino verbunden.
Jetzt ist es so, dass die Konsole alle 16ms ein Latch-Signal aussendet, 
nach welchem die Inputs vom Controller eingelesen werden. Habe dazu ein 
Bild beigelegt. Jetzt komme ich nicht weiter und habe einfach mal ohne 
großes überlegen nur Inputs an den Datenport geschickt, da passiert auch 
was, aber halt nichts Kontrolliertes. Dafür müsste ich das mit dem 
Latch-Signal timen. Das Problem ist, dass auch, wenn ich versuche das 
Latch-Signal nur auszulesen ich gar keins wahrnehmen kann. Dazu habe ich 
einfach den Latch-Port mit nem Arduino-Port verbunden und lese dauerhaft 
den Zustand des Ports aus. Da gibt es aber keine Veränderungen. Ich habe 
es auch schon mit Widerständen versucht, da habe ich genauso wenig 
Erfolg. Ich kann einfach nichts auslesen.
Falls irgendjemand schon mal sowas in der Richtung gemacht hat und mir 
bei diesem Anfangsproblem helfen kann, wäre ich schon mal sehr dankbar 
:)

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Vielleicht ist das Signal ein open collector Pin, so dass ein 
Pullup-Widerstand nach 5V angeschlossen werden muss. Ist nur eine 
Vermutung...

von Luther B. (luther-blissett)


Lesenswert?

Kannst du mal posten, wie du das ausliest? Auf dem Diagramm sieht man, 
dass das Latch-Signal 12µS lang ist. Wenn du, wovon ich mal wegen Noob 
ausgehe, pollst, dann muss deine Routine also öfter als alle 12µS 
abfragen, ob das Signal da ist. Wenn du langsamer liest, dann kommt nur 
Quatsch.

von Thomas M. (sirius93)


Lesenswert?

Klar. Ja, das dachte ich mir auch, deswegen habe ich es einfach mal so 
geschrieben: Da kommt dann dauerhaft 0 raus, aber es müsste doch, 
unabhängig davon wie oft oder wie schnell, ab und zu eine 1 ausgegeben 
werden oder irre ich mich da schon? Wie gesagt, ich hab nur in Paar 
Einsteigerprojekte nachgebaut, ansonsten hab ich so gut wie keine 
Erfahrung. Ich kann nur Programmieren, also zumindest da sollte ich 
allein weiterkommen, sobald ich hier weitergekommen bin.

void loop() {
    Serial.println(digitalRead(LatchPin));
  }

von Stephan M. (multimeter90)


Lesenswert?

Und wie lange dauert die Ausführung von Serial.println()? Bzw wie viele 
Nullen kommen da so pro Sekunde?
Über welchen Zeitraum hast du dein Glück versucht eine 1 zu sehen?

Wahrscheinlich dauert println deutlich länger als 12µs und du erfasst 
nur aller 1ms mal einen Wert. Ob das dann eine 1/0 ist hängt vom Glück 
ab.

Btw: das Latch-Signal hat ja auch eine Häufigkeit von 1/17. also nicht 
wirklich häufig. Versuch dein doch mal Clock zu erkennen. Ist häufiger 
und du siehst ob du überhaupt etwas lesen kannst.

: Bearbeitet durch User
von Thomas M. (sirius93)


Lesenswert?

Selbst, wenn ich das in eine Bedingung packe funktioniert es nicht. Das 
ist ja das eigentliche Ziel. Wenn das Signal kommt warte ich 12µs und 
schicke dann zum Beispiel die Taste B zur Konsole, bzw. muss ich da noch 
mit dem Clock-Signal aufpassen...

von Bastello (Gast)


Lesenswert?

Hast du die anderen Leitungen (Clock und Data) auch angeschlossen, oder 
hängen die in der Luft?
Auch wäre ein Pinchange-Interrupt meiner Meinung nach eleganter, als den 
Pin die ganze Zeit zu pollen. Hast du schon mal was mit Interrupts 
gemacht?

von Luther B. (luther-blissett)


Lesenswert?

Probier mal:
1
void loop() {
2
    while(!digitalRead(LatchPin)) { /* warte auf 1 */}
3
    Serial.println(":)");
4
  }

von Thomas M. (sirius93)


Angehängte Dateien:

Lesenswert?

Luther B. schrieb:
> Probier mal:
>
1
> void loop() {
2
>     while(!digitalRead(LatchPin)) { /* warte auf 1 */}
3
>     Serial.println(":)");
4
>   }
5
>

Auch das gibt keine Ausgabe...
Ich weiß nicht genau was los ist, mit einem normalen Controller 
funktioniert es, also müsste es eigentlich gehen. Nach allem was ich 
gelesen hab, sollte da also ein Latch-Pulse alle 16,67ms (60Hz) 
geschickt werden.

"Every 16.67ms (or about 60Hz), the SNES CPU sends out a 12us wide, 
positive
going data latch pulse on pin 3." - Pin 3 ist der Latch-Pin.

Also entweder mache ich was grundlegend falsch oder ich hab das nicht 
verstanden. Die anderen Pins sind natürlich verbunden. Ich habe hier 
nochmal den Aufbau mit angehängt. Ich kann ja über den Datenpin auch 
einfach Daten schicken auf welche die Konsole dann reagiert, deswegen 
weiß ich auch nicht, warum ich das Signal nicht einmal wahrnehmen kann.

von Dauergast (Gast)


Lesenswert?

Arduino DigitalRead ist fürchterlich langsam - google bitte mal "arduino 
fastread". Wenn Du die von der Konsole angegeben Zeiten einhalten muß, 
dürfte das relevant sein (ich kenne aus der Praxis nur den 
entgegengesetzten Weg, darum kann ich nicht mehr dazu sagen, aber 
vielleicht hilft's ja schon :-)

von Thomas M. (sirius93)


Lesenswert?

Ok, ich werd da mal nachschauen, danke dafür. Könnte natürlich die 
Erklärung sein. Eine Frage noch: Was heißt den "fürchterlich" langsam?

von Luther B. (luther-blissett)


Lesenswert?

digitalRead() braucht etwa 1µS. Dabei muss eigentlich nur aus dem 
Register gelesen werden, was ~0.1µS dauern sollte. digitalWrite() ist 
noch langsamer.

von Max D. (max_d)


Lesenswert?

Luther B. schrieb:
> Dabei muss eigentlich nur aus dem
> Register gelesen werden

Das Problem ist, dass Arduino die Pins nicht in PORTs aufgeteilt hat 
sondern einfach als D0 bis Dx durchnummeriert hat und damit der read 
erstmal aus der Nummer die Port-Adresse berechnen muss, dann den wert 
holen und dann maskieren. Das dauert schon bischen, dann kommt noch der 
overhead für die calls dazu usw.

von Bastello (Gast)


Lesenswert?

Mann kann doch auch in der Arduino IDE den Pin in "normalem" C abfragen, 
oder?
1
void loop()
2
{
3
  if(PIND & (1 << PIND3)) //Wenn PinD3 gesetzt ist
4
  {
5
    Serial.println("Latch");
6
  }
7
}

von Luther B. (luther-blissett)


Lesenswert?

Max D. schrieb:
> Luther B. schrieb:
>> Dabei muss eigentlich nur aus dem
>> Register gelesen werden
>
> Das Problem ist, dass Arduino die Pins nicht in PORTs aufgeteilt hat
> sondern einfach als D0 bis Dx durchnummeriert hat und damit der read
> erstmal aus der Nummer die Port-Adresse berechnen muss, dann den wert
> holen und dann maskieren. Das dauert schon bischen, dann kommt noch der
> overhead für die calls dazu usw.

Nein, das Problem ist, dass sich bei Arduino niemand richtig Gedanken 
gemacht hat. Die Nummer des Pins den du lesen willst ist praktisch immer 
zur Kompilierzeit bekannt. In diesem Fall kann auch zur Kompilierzeit 
bestimmt werden, welches Bit aus welchem Register gelesen werden muss - 
das ist ja genau das was digitalReadFast macht:

https://github.com/watterott/Arduino-Libs/blob/master/digitalWriteFast/digitalWriteFast.h

von Luther B. (luther-blissett)


Lesenswert?

Bastello schrieb:
> Mann kann doch auch in der Arduino IDE den Pin in "normalem" C
> abfragen,
> oder?
> void loop()
> {
>   if(PIND & (1 << PIND3)) //Wenn PinD3 gesetzt ist
>   {
>     Serial.println("Latch");
>   }
> }

Das funktioniert SO aber nur auf dem einen Arduino XYZ, auf dem Arduino 
ABC ist das wieder woanders. Eine (Zero-Cose) Mindestabstraktion muss 
schon rein.

von Bastello (Gast)


Lesenswert?

Aber der TO hat ja geschrieben, dass er einen UNO hat. Und mit eben 
diesem sollte es so klappen.

von Thomas M. (sirius93)


Lesenswert?

void loop()
{
  if(PINB & (1 << PINB1))
  {
    Serial.println("Latch");
  }
}

Ich hab das jetzt so geschrieben, nachdem ich gecheckt habe, wie es auf 
dem AtMega328 geregelt ist.
Auch hier funktioniert es nicht.

von Bastello (Gast)


Lesenswert?

Laut dieser Übersicht:
http://foros.giltesa.com/otros/arduino/fc/docs/pinout/uno.jpg
sollte Pin3 PIND3 sein, nicht PINB1.
Oder hast du das Latch-Signal jetzt an Pin9?

von Thomas M. (sirius93)


Lesenswert?

Ja, ist an Pin9

von xXx (Gast)


Lesenswert?

Haeng doch mal den Controller parallel, ob du dann den Latch siehst.

von Stephan M. (multimeter90)


Lesenswert?

Ist der Pin auch ein Eingang?
Hast du ein Oszi zum Anschauen ob das Signal physikalisch vorhanden ist?
12µs (und nicht µSiemens) aller 16,67ms ist nicht wirklich oft. Wenn 
dein Uno nicht genau diese 12µs abpasst, hat er den Latch verpasst. 
Versuch es doch lieber gleich mit einem Interrupt. Den wirst du am Ende 
eh verwenden müssen, mach dir also gleich die Arbeit. Damit ersparst du 
dir hier Arbeit.

von Heizer (Gast)


Lesenswert?

Wer produziert den eigentlich den Clock?
Die Konsole oder der Joystick?

Ich tippe mal auf die Konsole, da wird bestimmt durch das Latchsignal 
ein Schieberegister parallel geladen und dann rausgeschoben.
Wenn das so ist brauchst du das Latchsignal eh nicht unbedingt. Dein MC 
braucht dann nur auf den Clock zu hören. Was dann aber unbedingt 
interruptgesteuert passieren sollte.

von Thomas M. (sirius93)


Lesenswert?

Der Pin ist ein Eingang, ja. Ich bekomme auch Signale, bei bsp.
void loop()
{
  if(PINB & (1 << PINB1))
  {
    Serial.println("Latch");
  }
}
wenn ich die Konsole anschalte. So ca. 2-3 Sekunden lang. Allerdings 
bekomme ich die auch bei digitalRead. Ich weiß nicht genau, was die 
Konsole da macht.
Oszilloskop habe ich leider keins.
Mit Interrupt werde ich es mal versuchen.

Ich nehme an, dass die Konsole sowohl Clock als auch Latch produziert.
Das Latchsignal brauche ich insofern, da ich mich ja orientieren muss. 
Wenn ich später die Befehle rausschicke, muss ich ja wissen, wann das 
letzte Latchsignal kam um den richtigen Button zu "drücken".
Hier mal ein Auszug:

"
Every 16.67ms (or about 60Hz), the SNES CPU sends out a 12us wide, 
positive
going data latch pulse on pin 3. This instructs the ICs in the 
controller
to latch the state of all buttons internally. Six microsenconds after 
the
fall of the data latch pulse, the CPU sends out 16 data clock pulses on
pin 2. These are 50% duty cycle with 12us per full cycle. The 
controllers
serially shift the latched button states out pin 4 on every rising edge
of the clock, and the CPU samples the data on every falling edge.

Each button on the controller is assigned a specific id which 
corresponds
to the clock cycle during which that button's state will be reported."

Ich hab das schon mal gelesen, kann es nur gerade nicht finden, es war 
ein Schieberegister.

Wenn das so ist, werde ich das mal mit einem Interrupt versuchen und 
mich dann wieder hier melden.

Danke schonmal an alle, die mir bis hierhin Tipps gegeben haben.

von Bastello (Gast)


Lesenswert?

Ich sehe gerade, dass in dem Diagram Data auf High liegt und nur beim 
entsprechenden Signal für 12 µs auf low geht. Vielleicht ignoriert dein 
SNES deinen "Controller", weil Data während der initialisierung nicht 
auf High liegt?

von c-hater (Gast)


Lesenswert?

Thomas M. schrieb:

> Zu meiner Ausrüstung und meinem Projekt: Ich habe einen Arduino Uno

Schon geloosed. Jedenfalls dann, wenn du das Arduino-Software-Framework 
verwendest. Das ist sowas von extrem ineffizient, daß es einfach nicht 
in der Lage ist, auch nur die bloße Erkennung eines 12µs langen Pulses 
zu garantieren, geschweige denn die phasenrichtige Einspeisung eines 
Signals über mehrere Zyklen des durch den Puls definierten 12µs-Taktes.

Arduino-Software ist völliger Dreck. Dagegen ist selbst pure C schon die 
blanke Erleuchtung. Das Optimum (für das konkrete Problem alleine 
allerdings noch längst nicht zwingend erforderlich) ist natürlich, wie 
immer, pure Assembler.

von Thomas M. (sirius93)


Lesenswert?

Tja, Assembler kann ich nicht.
Ich sehe solangsam, dass ich anscheinend mit dem Arduino nur schwer oder 
nicht, eben jene 12µs abfragen kann. Was würdest du denn vorschlagen, 
ausgehend von meinem Projekt?

von Bastello (Gast)


Lesenswert?

Der Arduino UNO ist nicht das Problem. Eher Arduino als "Sprache" und 
die Herangehensweise.
Wenn du den Arduino in C programmierst und Interrupts statt Polling 
benutzt, sollte das schon klappen.
Wenn du bei den Arduino-Libs bleiben willst, brauchst du einen 
leistungsfähigeren Arduino, bei dem es dann nicht auf ein paar 
verplemperte Takte ankommt. Interrupts würde ich in dem Fall aber 
trotzdem empfehlen.

von Frank G. (frank_g53)


Lesenswert?

Knut B. schrieb:
> Pullup-Widerstand nach 5V angeschlossen

Ist der Port.pin auch als Eingang geschaltet?
In arduino ist es glaube ich pin.mode(pinnr,Input)

von Thomas M. (sirius93)


Lesenswert?

Das ganze sieht so aus, natürlich war der pin im richtigen Modus.
1
int ClockPin  = 4;
2
int DataPin   = 8; 
3
volatile int LatchPin = 0; //Arduino Digital Pin 2
4
5
void setup() {
6
  Serial.begin(57600);
7
  pinMode(ClockPin,INPUT);
8
  pinMode(DataPin,OUTPUT);
9
  pinMode(LatchPin,INPUT);
10
  attachInterrupt(0,switchf,CHANGE);
11
  
12
}
13
14
void loop()
15
{
16
   if(LatchPin){
17
   Serial.println(":)");
18
   }
19
}
20
21
22
23
void switchf(){
24
 LatchPin = !LatchPin;
25
}

Hab mal Change benutzt, da ich ja nicht weiß, was genau passiert, bzw. 
es mir ja erstmal egal ist, was passiert, ich will ja nur rausfinden 
wann das Signal kommt. Aber auch hier bekomme ich keine Ausgabe. println 
müsste ja jetzt auch funktionieren, da das Programm davor ja nicht 
weitermacht, bzw. ich es ja nur ausführe, wenn sich der Zustand am Pin 2 
geändert hat.

: Bearbeitet durch User
von xXx (Gast)


Lesenswert?

Dein Interrupt-Code hat das gleiche Problem wie alle Varianten vorher, 
auch hier kannst du das Signal verpassen. Dein switchf() kopiert nur den 
Pin-Status in eine Variable um, die du dann wieder mit grossen Delais 
aus loop() abfragst.

Mal abgesehen davon, dass du LatchPin zwei Mal fuer verschiedene Sachen 
benutzt und die Pins durcheinander gebracht hast.

 Mach das so:
1
void setup() {
2
  Serial.begin(57600);
3
4
  pinMode(9,INPUT);
5
}
6
7
void loop()
8
{
9
  while( true)
10
  {
11
    if(PINB & (1 << PINB1))
12
    {
13
      Serial.println("Latch");
14
    }
15
  }
16
}

Wenn das nicht geht:

 * Probiere es mit dem Controller parallel zum Arduino
 * Schicke aussagekraeftige Bilder deines Versuchsaufbaus

von Thomas M. (sirius93)


Angehängte Dateien:

Lesenswert?

Ich verstehe nicht ganz, was der Unterschied deiner Variante zum 
ursprünglichen ist, also dem hier:
1
void loop()
2
{
3
  if(PINB & (1 << PINB1))
4
  {
5
    Serial.println("Latch");
6
  }
7
}

Bei deinem Code habe ich doch nur eine zusätzliche Dauerschleife, die 
nicht unterbrochen wird? Funktioniert aber auch mit dieser Variante 
nicht.

Habe keine Kamera da, aber der Versuchsaufbau ist momentan nur, dass ich 
den Controller vom Kabel entfernt habe und die im Bild gezeigten Kabel 
mit den Ports verbunden habe. Dabei habe ich vorerst nur Latch,Clock und 
Data verbunden. Dazwischen ist momentan nichts, keine Widerstände oder 
sonstiges, da es auch so nicht funktioniert hat. Controller hängt also 
keiner mehr dran.

Wie meinst du das denn, ich soll den Controller paralell zum Arduino 
anschließen?

: Bearbeitet durch User
von Bastello (Gast)


Lesenswert?

dast du mal versucht, den Data-Pin auf High zu stellen? Vielleicht 
schickt der SNES nur das Signal raus, wenn er meint, dass auch ein 
Controller am Port hängt und laut deinem Bild aus dem ersten Posting ist 
Data aktive Low, also standardmäßig high und beim Signal low.

von gatsby (Gast)


Lesenswert?

Hallo Thomas,

wo bitte ist dein GND ??

Ich hoffe, nur vergessen zu zeichnen.

Gruß
gatsby

von Thomas M. (sirius93)


Lesenswert?

Ja, den Data-Pin auf High zu stellen habe ich auch mit im Code, auch da 
funktioniert es nicht.

GND liegt natürlich am GND-Port vom Arduino, den habe ich nur vergessen 
zu zeichnen^^.

von Luther B. (luther-blissett)


Lesenswert?

Bevor das hier weitergeht, kannst du bitte bestätigen, dass in deinem 
Aufbau der Controller gleichzeitig noch an einer SNES hängt, auf der ein 
Spiel läuft, welches aktuell mit dem Controller gesteuert werden kann 
und du mit dem Arduino nur Signale abgreifst?

von xXx (Gast)


Lesenswert?

Thomas M. schrieb:

> Bei deinem Code habe ich doch nur eine zusätzliche Dauerschleife, die
> nicht unterbrochen wird?

Exakt das: Eine Dauerschleife, die durch nichts unterbrochen wird, also 
maximal schnell laeuft und so auch keine Signale verpasst.

In deiner Variante sieht das so aus:

<Arduino-Framework macht irgendwas mit unbestimmter Dauer>

loop()
{
  ...
}

<Arduino-Framework macht irgendwas mit unbestimmter Dauer>

Wie viel Zeit wohl das Framework fuer sich selbst braucht und wie viele 
Signale du dabei verpasst...?

Noch besser waere natuerlich, gleich was ohne das Arduino-Framework zu 
machen, um diesen Unsicherheitsfaktor auszuschliessen.

> Wie meinst du das denn, ich soll den Controller paralell zum Arduino
> anschließen?

Controller mit einem Zwischenstecker an die Console anschliessen. An den 
Zwischenstecker den Arduino fummeln, so dass er Latch beobachten kann. 
Anhand eines Spiels beweisen, dass der Controller so funktioniert. Gibt 
der Arduino dann immer noch nichts aus, machst du irgendwas fundamental 
falsch, was du uns hier nicht zeigst.

Wenn du wirklich weiter kommen willst, musst du deine Versuche 
ordentlich dokumentiert - ein Bild zeigen, auf dem dein Versuchsaufbau 
erkennbar ist und den Code posten, der verwendet wurde. Bisher war jeder 
von dir gezeigt Code in diesem Thread falsch und es blieb stets unklar, 
was du ueberhaupt genau gemacht hast.

von Thomas M. (sirius93)


Angehängte Dateien:

Lesenswert?

So, jetzt hab ich mal umgebaut:

Ich habe jetzt den Controller mit angeschlossen und den Arduino paralell 
angeschlossen. Bild liegt oben bei. Ich bekomme mit folgendem Code:
1
int latchpin = 9;
2
int datapin = 8;
3
int clockpin = 7;
4
5
void setup() {
6
  Serial.begin(57600);
7
8
  pinMode(latchpin,INPUT);
9
  pinMode(datapin,INPUT);
10
  pinMode(clockpin,INPUT);
11
}
12
13
void loop()
14
{
15
  while( true)
16
  {
17
    if(PINB & (1 << PINB1))
18
    {
19
      Serial.println("Latch");
20
    }
21
  }
22
}

jetzt die Ausgabe "Latch". Ich kann den Controller auch benutzen und die 
Konsole reagiert darauf.

von Jan H. (jan_m_h)


Lesenswert?

Wenn es funktioniert, sobald ein Controller dran hängt, dann muss wohl 
der Controller der SNES zeigen, das er da ist. Ich vermute ebenfalls die 
Erkennung läuft über den High-Pegel an Data Out. Teste mal ohne 
Controller aber mit Data Out auf High Pegel

von Thomas M. (sirius93)


Lesenswert?

Das wurde ja schon öfter vorgeschlagen, habe ich auch probiert, das hat 
nicht funktioniert. Ich nehme mal an, dass der SNES anders erkennt, ob 
ein Controller angeschlossen ist.

von Jan H. (jan_m_h)


Lesenswert?

'tschuldigung hatte nicht mitbekommen, dass du das schon probiert hast.

von Thomas M. (sirius93)


Lesenswert?

Habe es aber auch glaube ich nicht geschrieben.
Eine Frage hätte ich vorerst noch. Es ist ja so, dass ich wissen muss, 
wann das Signal kommt oder aufhört, bei attachInterrupt kann ich als 
Parameter ja übergeben, ob der Interrupt ausgeführt werden soll bei 
CHANGE,HIGH,LOW, usw.
Kann ich das auch mit einer schnelleren Methode abfragen?

von Bastello (Gast)


Lesenswert?

lann lausch doch mal bei angeschlossenem Controller auf der 
Data-Leitung.

Ein Logic-Analyser wäre da schön... Gibt's für nen paar Euro bei eBay 
:-)

von Bastello (Gast)


Lesenswert?

Wie schneller? Die ISR wird sofort ausgeführt, wenn am entsprechenden 
Pin das entsprechende Ereignis auftritt.
Wenn du also auf einen Wechsel von Low auf High einstellst, wird die ISR 
immer genau dann gestartet, wenn dein Latch-Signal startet. Bei einem 
Wechsel von High auf low, wenn das Signal wieder vorbei ist.

von xXx (Gast)


Lesenswert?

Thomas M. schrieb:
> Das wurde ja schon öfter vorgeschlagen, habe ich auch probiert, das hat
> nicht funktioniert.

Wie hast du das gemacht? Per Pullup vom Controller oder wie? Kannst du 
bitte dafuer den Code zeigen?

von Thomas M. (sirius93)


Lesenswert?

Habe da den Daten-Pin als Output verwendet und im setup 
digitalWrite(datapin,HIGH) stehen gehabt.

von c-hater (Gast)


Lesenswert?

Bastello schrieb:

> Wie schneller? Die ISR wird sofort ausgeführt, wenn am entsprechenden
> Pin das entsprechende Ereignis auftritt.

Schön wäre es. Tatsächlich ist es aber so, dass eine ISR dann ausgeführt 
wird, wenn sie ausgeführt werden kann.

Beim AVR8 bedeutet das:

1) Das entsprechende IRQ-Flag muß gesetzt sein und das globale I-Flag
   muss gesetzt sein
2) die zweite Bedingung ist nicht gegeben, wenn
   a) eine andere ISR exclusiv werkelt
   b) irgendein cli/sei-Konstrukt im laufenden Code aktiv ist, also noch
      nicht das abschließende sei erreicht hat.
3) nicht wenigstens eine Instruktion in nichtexclusivem Code ausgeführt
   wurde, nachdem eine Interruptsperre wirksam war.

Der gesamte Problemkreis nennt sich: "variable Interuptlatenz". Solltest 
du dich ernsthaft mal drüber aufschlauen...

von Bastello (Gast)


Lesenswert?

Ist schon klar, dass es Fälle gibt, bei denen eine ISR nicht sofort 
ausgeführt wird. Das sollte aber hier nicht der Fall sein.

von Thomas M. (sirius93)


Lesenswert?

Das Problem ist aber, dass ich ja jetzt auf das latch-Signal warte und 
dann 12µs warte und dann den datenpin 12µs auf HIGH stelle um den B 
Knopf zu drücken. Jetzt sollte eigentlich immer das gleiche passieren, 
tut es aber nicht. Manchmal wird Start gedrückt, manchmal der R-Button. 
Also dachte ich, ich time das doch noch mit der Clock, nur kann ich auch 
diese nicht am Arduino abnehmen. Egal wie. Obwohl da was ist, weil wenn 
ich den Pin abziehe, kann ich mit dem Controller nicht mehr steuern.
1
int latchpin = 9;
2
int datapin = 8;
3
int clockpin = 7;
4
boolean clockstate;
5
void setup() {
6
  Serial.begin(57600);
7
8
  pinMode(latchpin,INPUT);
9
  pinMode(datapin,OUTPUT);
10
  pinMode(clockpin,INPUT);
11
  digitalWrite(datapin,HIGH);
12
}
13
14
void loop()
15
{
16
while(true)
17
  {
18
    if(!(PINB & (1 << PINB1)))
19
    {
20
      delayMicroseconds(12);
21
      digitalWrite(datapin,LOW);
22
      delayMicroseconds(12);
23
      digitalWrite(datapin,HIGH);
24
    } 
25
     if(!(PIND & (1 << PIND7)))
26
     {
27
      Serial.println("Clocklow");
28
     }
29
     else{
30
      Serial.println("Clockhigh");
31
     }
32
    }
33
  }

von Bastello (Gast)


Lesenswert?

Ich hab da gerade was gefunden:

http://assemblergames.com/l/threads/my-attempt-at-a-snes-bot-couple-of-questions.47983/

Da benutz einer einen RasPi, um den SNES zu steuern. Eigentlich ganz 
einfach. Zwei 4021 Schift Register un du brauchst dir um Timing gar 
keine Gedanken mehr zu machen. Du brauchst nicht mal die Levelshifter, 
die er noch hat, um die 3,3V des Raspi auf die 5V des SNES zu bekommen. 
Wenn du eine Taste drücken willst, einfach den Eingang des 
Shift-Registers schalten und gut ist.

von Thomas M. (sirius93)


Lesenswert?

Hab mir das mal durchgelesen.
Also ich brauch das hier?:
http://www.ebay.de/itm/2-x-CD4021BE-CMOS-8-Stage-Static-Shift-Register-RCA-DIP-16-2pcs-/161288467202?hash=item258d8ab302

Jetzt ist es aber so, dass der UNO nicht annähernd genug Eingänge hat. 
Was kann ich da denn machen?
Mit Shift-Registern kenne ich mich gar nicht aus, ich kenne mich ja 
sowieso schon kaum aus, aber ich nehme an, dass das sowieso mehr Arbeit 
in Anspruch nehmen wird als gedacht. Aber gut.

von Luther B. (luther-blissett)


Lesenswert?

Nein, der Hinweis von Bastello nutzt dir nichts. Der Pi kann nicht auf 
das Clock Signal reagieren, weil er unter einem nicht-Echtzeitfähigem OS 
läuft, der Arduino kann das sehr wohl. 3.3V <-> 5V Problem hast du auch 
nicht. Der Ard. braucht daher dieses Shift-Register nicht. Dein Problem 
lässt sich mit Programmierung lösen, deine Lernaufgabe besteht darin 
herauszufinden wie.

von Bastello (Gast)


Lesenswert?

Der Uno braucht für jede Taste, die du emulieren willst, einen Ausgang. 
Wenn ich mich nicht verzählt habe, sind das in der verlinkten Seite 13 
IOs. Das ist mit einem UNO machbar (der hat 14 Digitale IOs und 6 
Ananog-Pins, die du auch als digitale Outputs benutzen kannst).
Das mit den Schiebe-Registern ist nicht weiter wild. Das sind PiSo 
Register, also Parallel In Serial Out. Das heist, das was du auf der 
Input-Seite gleichzeitig eingibst, kommt auf der Output-Seite seriel 
raus.
Die beiden Register sind kaskadiert (also hintereinander geschaltet) und 
werden dann von der Kobsole getacktet. Da brauchst du dir um die 
Ansteuerung gar keine Gedanken zu machen.

von Bastello (Gast)


Lesenswert?

Sicherlich braucht man die beiden Shift-Register mit einem Arduino 
nicht, aber es macht die Sache für einen Anfänger um einiges einfacher, 
weil man sich um das Timing keine Gedanken machen muss.
Wenn man sich in Interrupts und Timer einarbeiten will, schafft man das 
auch ohne. Aber vielleicht nicht als erstes eigenes Projekt.

von Thomas M. (sirius93)


Lesenswert?

Wird sich zeigen, was besser funktioniert, hab mir die Shifter mal 
bestellt, die kosten ja nichts, ist sicher sowieso nicht verkehrt, wenn 
man welche hat.
Ich habe mal folgendes Programm laufen lassen:
1
void loop()
2
{
3
while(true)
4
  {
5
    if(!(PINB & (1 << PINB1)))
6
    {
7
      Serial.println(timer);
8
      timer = 0;
9
      delayMicroseconds(0);
10
      digitalWrite(datapin,LOW);
11
      delayMicroseconds(12);
12
      digitalWrite(datapin,HIGH);
13
    }
14
    timer++; 
15
    }
16
  }
Und mir ausgeben lassen, wann denn das latch-Signal auftritt. Ich 
bekomme hier ausgaben von 19536 bis 19557. Meine Frage: Ist das zu 
vernachlässigen?

Und da ich das Clocksignal nicht abgreifen kann: Hat noch jemand eine 
Idee, warum ich jetzt das Signal nicht abgreifen kann?

PS: Nochmals danke für eure Hilfe bis hierher :)

von Thomas M. (sirius93)


Lesenswert?

Es ist außerdem der Fall, dass der R-Knopf gedrückt wird, wenn die Clock 
nicht angeschlossen ist, aber der Controller oder das Programm ein 
Signal über Data schickt. Der R-Knopf ist der letzte Knopf, der vom SNES 
eingelesen wird. Soweit ich weiß sind alle Signale auch 5V Signale, also 
müsste das eigentlich genau wie beim Latch erkennbar sein.

von Thomas M. (sirius93)


Lesenswert?

Habe jetzt auch mal die Clock im Arduino abgegriffen und schicke sie 
durch einen Output am Arduino weiter zum SNES und nicht paralell dazu. 
Auch hier funktioniert noch alles. Habe mir auch das Signal anzeigen 
lassen, dass ich zur Konsole schicke, aber auch hier bekomme ich immer 
ein HIGH.

von Bastello (Gast)


Lesenswert?

So wie ich das aus deinem Bild vom ersten Post sehe, ist Data active 
Low. Also die ganze Zeit High und nur bei entsprechendem Signal für 12us 
low. Kann es sein, dass du das verpasst? Hast du versucht, es per 
Interrupt oder per Polling auszulesen?

von Heizer (Gast)


Lesenswert?

Thomas M. schrieb:
> Das Problem ist aber, dass ich ja jetzt auf das latch-Signal warte und
> dann 12µs warte und dann den datenpin 12µs auf HIGH stelle um den B
> Knopf zu drücken.

Das ganze mit dem Timing wird so nichts. Du must auf das Clocksignal 
Signal reagieren. Du must da die Clocks mit einem Interrupt zählen.

Kenn mich da nicht so aus mit den Adurinos, aber kann man die nicht auch 
mit normales C oder Assembler programmieren?

von Thomas M. (sirius93)


Lesenswert?

1
void loop()
2
{
3
while(true)
4
  {
5
    digitalWrite(clockout,digitalRead(clockpin));
6
//  Serial.println(digitalRead(clockout));
7
    if(!(PINB & (1 << PINB1)))
8
    {
9
 //   Serial.println(timer);
10
      timer = 0;
11
/*    delayMicroseconds(0);
12
      digitalWrite(datapin,LOW);
13
      delayMicroseconds(12);
14
      digitalWrite(datapin,HIGH);
15
    */}
16
    if(!(PINB & (1 << PINB0)))
17
    {
18
    Serial.println("Datahigh");
19
    }
20
    if((PINB & (1 << PINB0))){
21
      Serial.println("Datalow");
22
    }
23
    timer++; 
24
    }
25
  }

Hab mal hiermit geschaut.
Ab und zu kommt Datalow, auch bei keiner Eingabe. Eigentlich müsste das 
bei keiner Eingabe ja die ganze zeigt auf HIGH stehen, aber ich weiß 
natürlich auch nicht, was der SNES bei den nicht belegten Tasten für 
Data schickt. Allerdings bekomme ich auch immer nur einmal Datalow, egal 
ob ich eine Taste drücke oder nicht.
Habe auch getestet was passiert, wenn ich nur Augaben bekomme, wenn ich 
einen Knopf drücke.Auch da kommen die Ausgaben eher unregelmäßig. Wenn 
ich den B-Knopf die ganze Zeit gedrückt habe, sollte eigentlich 
regelmäßig Datalow ausgeben werden, wird es aber nicht. Womöglich 
verpasse ich auch hier immer mal wieder die 12µs in der ich den Knopf 
drücke.
1
void loop()
2
{
3
while(true)
4
  {
5
    digitalWrite(clockout,digitalRead(clockpin));
6
//  Serial.println(digitalRead(clockout));
7
    if(!(PINB & (1 << PINB1)))
8
    {
9
      delayMicroseconds(12);
10
      digitalWrite(datapin,LOW);
11
      delayMicroseconds(12);
12
      digitalWrite(datapin,HIGH);
13
    }
14
  }

Auch bei diesem Code verstehe ich nicht, warum nicht dauerhaft der 
B-Knopf gedrückt wird.

von Thomas M. (sirius93)


Lesenswert?

Heizer schrieb:
> Thomas M. schrieb:
>> Das Problem ist aber, dass ich ja jetzt auf das latch-Signal warte und
>> dann 12µs warte und dann den datenpin 12µs auf HIGH stelle um den B
>> Knopf zu drücken.
>
> Das ganze mit dem Timing wird so nichts. Du must auf das Clocksignal
> Signal reagieren. Du must da die Clocks mit einem Interrupt zählen.
>
> Kenn mich da nicht so aus mit den Adurinos, aber kann man die nicht auch
> mit normales C oder Assembler programmieren?

Stimmt, aber ich kann ja das Clocksignal nicht am Arduino abgreifen. Ja, 
C und Assembler sind beim Arduino möglich.

von Bastello (Gast)


Lesenswert?

Warum kannst du das Clock-Signal nicht abfreifen? Um das ohne 
dieSchiebe-Register zu machen, wäre das essentiell. Die Geschichte mit 
Delay zu lösen, wird nicht sicher klappen.
Der UNO hat zwei Interrupt-Pins.
An den einen würde ich das Latch-Signal legen, an den anderen die Clock.
Dann legst du zwei ISRs an. Eine beim Wechsel von High auf Low am Latch 
Pin und eine beim Wechsel von Low auf Hig beim Clock-Pin.
In der Latch-ISR stellst du einen Counter auf 0 und ggf. Data auf Low, 
falls du ein B senden willst.
In der Clock-ISR zählst du den Counter eins weiter und prüfst, ob du 
z.b. bei 1 ein Y senden willst. Dann Data auf Low. Ansonten auf High. 
Wenn der Counter auf >11 ist, Data auf High.
ISRs sollten zwar so wenig Code wie möglich enthalten, aber diese 
Abfragen dauern ja nicht lange.
Wenn du dir am Anfang noch ein Array anlegst mit deinen Tasten, kannst 
du den Counter gleich als Index für das Array nehmen, um abzufragen, ob 
die entsprechende Taste gedrück werden soll, oder nicht.

von Thomas M. (sirius93)


Lesenswert?

Das ist eine gute Frage...
1
int clockpin = 2;
2
int clockout = 6;
3
void setup() {
4
  Serial.begin(57600);
5
 attachInterrupt(0,clockfunction,CHANGE);
6
    pinMode(clockout,OUTPUT);
7
8
}
9
10
void loop() { 
11
  while(true){
12
   digitalWrite(clockout,digitalRead(2));
13
  }
14
}
15
16
void clockfunction(){
17
  Serial.println("Clockchange");
18
}

Hab mal ein neues Programm geschrieben um mit der Clock zu 
experimentieren. Aber auch hier bekomme ich keine Ausgabe. Ich kann 
einfach das Clocksignal nicht warnehmen, dass ist momentan mein Problem. 
Ich weiß nicht warum der Arduino kein Signal warnimmt, obwohl es da ist.

Deine Idee ist ziemlich genau das, was ich machen werde/würde.Dazu muss 
ich aber das Signal am Arduino abnehmen können, was ich nicht 
hinbekomme.

von Bastello (Gast)


Lesenswert?

Sehe ich das richtig, dass du das Clock-Signal durch den Arduino durch 
schleust? Also hängt der Arduino nicht parallel zum Controller, sondern 
in Reihe (Clock an Pin2 rein und an Pin6 raus?)

von Thomas M. (sirius93)


Lesenswert?

Ja habe ich vorhin mal getauscht, habe es jetzt wieder paralell. 
Funktioniert aber auch hier nicht.
1
void setup() {
2
  Serial.begin(57600);
3
 attachInterrupt(0,clockfunction,CHANGE);
4
5
}
6
7
void loop() { 
8
  while(true){
9
  }
10
}
11
12
void clockfunction(){
13
  Serial.println("Clockchange");
14
}

von Bastello (Gast)


Lesenswert?

Ein Clock-wechsel kommt alle 6us. Ich denke, da kommt das Serial.println 
nicht mit.
Das du das Clock-Signal durch den Arduino durch führen kannst, zeigt ja, 
das es erkannt wird.
Das ist übrigens genau das, was ich damit meinte, die ISR möglichst kurz 
zu halten. Das Serial.println ist zwar in der Arduino-IDE nur ein 
Befehl, braucht aber reichlich Systemtakte. So wird die ISR immer wieder 
aufgerufen, bevor sie überhaupt abgearbeitet wurde.

von Heizer (Gast)


Lesenswert?

Setze im Interrupt doch einfach nur ein Bit wenn ein Clock auftritt.
Im Main fragst du dieses Bit ab, sendest dann deinen Text und löscht das 
Bit.

Das wird dann zwar jede menge Clocks verpassen während du den Text 
sendest, aber das ist zum Probieren ja erstmal egal.

von Thomas M. (sirius93)


Lesenswert?

Das verstehe ich nicht. Das attachInterrupt(0, clockf, CHANGE) sorgt 
doch dafür, dass eben die clockf nur ausgeführt wird, wenn sich was am 
Pin ändert. Aber da tut sich ja nichts. Oder meinst du, die Funktion 
wird ausgeführt, aber so schnell, dass Serial.println nicht 
hinterherkommt?
In dem Fall weiß ich nicht, was ich machen könnte um das Signal 
warzunehmen.

von Bastello (Gast)


Lesenswert?

Entweder, wie Heizer schrieb, eine Variabel auf true setzen und im 
Main-Loop abfragen, ob true, dann Serial.println("clock") und die 
Variabel wieder auf false setzen. Dann erwischt du beim Testen nur jede 
x-tes Clock-Signal, oder in der ISR einen Ausgang, an dem eine LED hängt 
toggeln. Wenn die LED mit halber kraft leutet, ust das Clock-Signal da 
(Vorwiderstand nicht vergessen).

von Thomas M. (sirius93)


Lesenswert?

1
bool clockstate;
2
void setup() {
3
  Serial.begin(57600);
4
 attachInterrupt(0,clockfunction,CHANGE);
5
 pinMode(4,OUTPUT);
6
 pinMode(9,INPUT);
7
8
  
9
}
10
11
void loop() { 
12
  
13
  while(true){
14
    
15
      digitalWrite(4,LOW);
16
  }
17
}
18
void clockfunction(){
19
  digitalWrite(4,HIGH);
20
}

Hat weder mit dieser Methode noch mit der Variable funktioniert. Die 
Lampe leuchtet nicht. Die Lampe leuchtet nur, wenn ich keinen Ausgang 
vom Arduino nehme, sondern ich die Lampe paralell zur Clock schalte. 
Dann leuchtet sie, aber auch mit voller Helligkeit...

von Bastello (Gast)


Lesenswert?

attachInterrupt(0,clockfunction,CHANGE); pinMode(4,OUTPUT); 
pinMode(9,INPUT);

Probier mal so:
1
void setup(){
2
  pinMode(4, OUTPUT);
3
  pinMode(9, INPUT);
4
  attachInterrupt(0, clockfunction, CHANGE)
5
}
6
7
void loop(){
8
}
9
10
void clockfunction(){
11
  static bool toggle = true;
12
  digitalWrite(4, toggle);
13
  toggle = !toggle;
14
}

PS: gibt es bei Arduino keinen Befehl zum Toggeln?

von Thomas M. (sirius93)


Lesenswert?

Soweit ich weiß nicht, oder nur über Zusatzbibliotheken.
Habe deinen Code ausprobiert, auch der Funktioniert nicht.

von Bastello (Gast)


Lesenswert?

Grad gesehen, dass nur Pin2 und Pin3 als externe Interruptquelle 
funktionieren. Bau doch den Aufbau und das Programm mal entsprechend um 
(also Clock an Pin2).

von Thomas M. (sirius93)


Lesenswert?

Der attachInterrupt(0) ist Pin2 am Arduino. Das passt schon so, wie es 
bei dir der Fall war.

von Heizer (Gast)


Lesenswert?

Das Programm schon mal getestet wenn du den Clock per Hand simulierst?
Also z.B. 10k Widerstand gegen Plus und dann den Eingang mit einen Draht 
gegen GND tackten.

Die Konsole dann natürlich nicht anschliessen.

von Thomas M. (sirius93)


Lesenswert?

Ja das funktioniert.

von Thomas M. (sirius93)


Lesenswert?

So, hab jetzt einiges geschafft.
Da ich die Clock gestern immernoch nicht warnehmen konnte, habe ich 
einfach mal 2*1k Widerstände zwischen die Clock geschalten, jetzt kann 
ich sie abnehmen und dementsprechend mit untenstehendem Code Buttons 
drücken. Funktioniert nur nicht ganz. Das Problem ist, dass manchmal 
nicht der richtige Button gedrückt wird, sondern der nächste. Das heißt, 
drücke ich B, wie hier, dann wird alle paar frames auch mal ein Y 
gedrückt.
An meiner Schleife zum auslesen des Inputarrays liegt es nicht, 
funktioniert ohne auch noch nicht richtig. Also da scheint manchmal was 
mit dem Timing nicht zu stimmen.
Allerdings weiß ich nicht genau, warum das Timing manchmal nicht passt. 
Das Spiel läuft mit 50Hz und das passiert relativ oft pro Sekunde, dass 
der Button verpasst wird, egal welcher.


1
#define BTN_B 0
2
#define BTN_Y 1
3
#define BTN_SELECT 2
4
#define BTN_START 3
5
#define BTN_UP 4
6
#define BTN_DOWN 5
7
#define BTN_LEFT 6
8
#define BTN_RIGHT 7
9
#define BTN_A 8
10
#define BTN_X 9
11
#define BTN_L 10
12
#define BTN_R 11
13
14
15
int latchpin = 3;
16
int clockpin = 2;
17
int datapin = 8;
18
int switchpin = 9;
19
int state;
20
bool switchs = true;
21
unsigned long int clocks;
22
unsigned long int counter;
23
unsigned long int latches;
24
int input[] = {BTN_B};
25
26
27
28
29
void setup(){
30
  pinMode(datapin, OUTPUT);
31
  pinMode(switchpin,INPUT);
32
  attachInterrupt(0,clockfunction,RISING);
33
  attachInterrupt(1,latchfunction,FALLING);
34
  Serial.begin(57600);
35
  digitalWrite(datapin,HIGH);
36
  latches = 0;
37
  clocks = 0;
38
39
}
40
41
void loop(){
42
  Serial.println((sizeof(input) / sizeof(input[0])));
43
  while(true){  
44
45
  
46
  }
47
}
48
void clockfunction(){
49
  counter++;
50
  for(int j=0;j<(sizeof(input) / sizeof(input[0]));j++){
51
    if(input[j]==counter+1)
52
    {
53
      digitalWrite(datapin,LOW);
54
    }
55
    else{
56
      digitalWrite(datapin,HIGH);
57
    }
58
  }
59
  if(counter>11){
60
    digitalWrite(datapin,HIGH);
61
  }
62
}
63
void latchfunction(){
64
  counter = 0;
65
  for(int i = 0;i<(sizeof(input) / sizeof(input[0]));i++){
66
    if(input[0] == 0){
67
      digitalWrite(datapin,LOW);
68
    }
69
  }
70
}

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.