Forum: Mikrocontroller und Digitale Elektronik Attiny als schieberegister


von Daniel J. (theend)


Angehängte Dateien:

Lesenswert?

Hallo, ich habe eine Super nintendo und möchte gerne einen Controller 
Simulieren.

Auf dem Bild im Anhang sieht man wie die Supernintendo mit dem 
controller Kommuniziert.

Was auf dem Bild falsch dargestellt ist, das Signal "Data" ist zwischen 
den Abfragen immer LOW, und wird mit dem start bit "Latch" auf high 
gesetzt.

Das heißt mein ATtiny (13 und 2313 zur verfügung) muss:
Latch und Data = low
Clock = high

1. Warten bis Latch high
2. Data high
3. 12 µs warten
4. die nächsten 12 µs, je nach dem low wenn taste gedrückt, oder high 
wenn nicht.
5. zum schluss Data wieder low.

Clock kann ich normalerweiße ignorieren oder? Der ist nur dafür, das im 
Schieberegister die zahlen geschoben werden.

Ich habe schon vieles versucht, eine Schleife um auf Latch = high zu 
warten, bitwait auch schon usw. Waitus ist zu ungenau, und laut Bascom 
bei 4mhz das mindeste 5us, arbeite aber mit 1mhz, noch (habe mich nocht 
nicht wirklich mit den Fusebits auseinander gesetzt. "!NOP" habe ich 
auch schon versucht, klappt auch nicht.
Wenn ich meine Versuche am SNES anstecke, werden "Start und Select" 
erkannt. Ich kann allerdings nicht sagen, ob einfach nur alle Tasten 
erkannt werden, oder nur Start und Select.

Ich habe leider keinen Externen Quarz.

Wie kann ich das leicht in BASCOM bewerkstelligen?

von Fallobst (Gast)


Lesenswert?

Daniel J. schrieb:
> Wie kann ich das leicht in BASCOM bewerkstelligen?

Indem man die Peripherie, hier USI als Slave, nutzt. Ob das Bascom 
unterstützt weiß ich nicht. Aber mit dem Datenblatt ist das selbst von 
Hand nicht schwer.

von Karl H. (kbuchegg)


Lesenswert?

Daniel J. schrieb:

> 1. Warten bis Latch high
> 2. Data high
> 3. 12 µs warten
> 4. die nächsten 12 µs, je nach dem low wenn taste gedrückt, oder high
> wenn nicht.
> 5. zum schluss Data wieder low.

Das ist ganz großer Mist.

Das ganze 'Protokoll' ist vollständig in Form der jeweiligen 
Schaltflanken definiert. Es gibt keinen Grund, warum du da jetzt 
irgendwelche windigen Zeitsteuerungen einbauen musst.

> Clock kann ich normalerweiße ignorieren oder? Der ist nur dafür, das im
> Schieberegister die zahlen geschoben werden.

Clock ist dein Signal, wann du das nächste Datenbit auf den Ausgang 
legen sollst. Sieh dir das Diagramm an, daraus geht eindeutig hervor, 
wann welche Aktion bei welchem Flankenwechsel auf einem der beiden 
Eingangsleitungen passieren soll.

> Wie kann ich das leicht in BASCOM bewerkstelligen?

Indem du es vernünftig machst.

Vergiss die 12µs. Die sind nur dazu da, damit es eine Obergrenze gibt, 
d.h. dein NS wird das Schieberegister nicht beliebig schnell austakten.

Wenn auf Clock die Schaltflanke Low->High kommt legst du das nächste Bit 
auf die Data-Leitung. Die fallende Schaltflanke ist der Zeitpunkt an dem 
das erledigt sein muss und interessiert dich nicht weiter.
Latch sagt dir, dass jetzt eine komplette Übertragungssequenz beginnt. 
Mit der fallenden Flanke von Latch (oder auch mit der steigenden) legst 
du das allererste Datenbit auf den Data Ausgang.


> und wird mit dem start bit "Latch"
Latch ist kein "Startbit", sondern das Signal an ein echtes 
Schieberegister doch bitte jetzt den Inhalt der externen Leitungen zu 
sichern und zum austakten bereit zu stellen.


Der ganze Ablauf wird einfach nur durch die entsprechenden Pegelwechsel 
gesteuert. Und der NES gibt den Takt vor. D.h. dein halbes Programm wird 
nur daraus bestehen, auf die jeweiligen Pegelwechsel zu warten oder 
diese Aufgabe der Hardware (USI) zu überlassen, wenn dein Tiny das kann. 
Problem mit der USI könnte höchstens sein, dass der NES ein 16-Bit 
Schieberegister voraussetzt und die USI nur 8-bittig ist.

von Daniel J. (Gast)


Lesenswert?

Usi sagt mir nichts, mal reinlesen

Wie genau soll ich auf die Veränderung von Clock Auslesen? Per bitwait?
Mit bitwait Hab ich's nämlich auch schon versucht.

von Karl H. (kbuchegg)


Lesenswert?

Daniel J. schrieb:
> Usi sagt mir nichts, mal reinlesen
>
> Wie genau soll ich auf die Veränderung von Clock Auslesen? Per bitwait?
> Mit bitwait Hab ich's nämlich auch schon versucht.

Na, dann zeig mal.

von Daniel J. (theend)


Lesenswert?

ungefähr so hatte ichs gemacht:
1
$regfile = "attiny13.dat"
2
$crystal = 1200000
3
$framesize = 10
4
$swstack = 10
5
$hwstack = 10
6
7
8
9
Config Pinb.2 = Input                                       'clock
10
Config Pinb.1 = Input                                       'Latch
11
Config Portb.0 = Output                                     'Data
12
Portb.1 = 1                                                 'latch Pullup Widerstand ein
13
Portb.2 = 1                                                 'clock Pullup Widerstand ein
14
Portb.0 = 0                                                 'data grundstellung, high = taste nicht gedrückt, low, taste gedrückt
15
16
17
Tosnes Alias Portb.0
18
Fromsnes Alias Pinb.1
19
Clock Alias Pinb.2
20
21
Dim A As Byte
22
23
Do
24
Bitwait Fromsnes , Set                                      'warte auf latch = high
25
Tosnes = 1                                                  'data = high
26
Bitwait Clock , Reset                                       'warte bis clock = low
27
Tosnes = 0                                                  'taste "B" gedrückt
28
Bitwait Clock , Set                                         'warte bis clock wieder high
29
Tosnes = 1                                                  'alle anderen tasten, high = nicht gedrückt
30
31
For A = 1 To 11                                             'Y, start, select, hoch, runter, links, rechts, A, X, L, R = nicht gedrückt
32
Bitwait Clock , Reset
33
Next A
34
35
Tosnes = 0                                                  'data grundstellung
36
37
38
Wait 5                                                      'alle 5 sekunden taste "B" drücken
39
Loop
40
41
End

Ich habe folgendes im internet gelesen:
> 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.

Bedeutet, das der CPU des Snes, die buttons bei jedem "low" des Clocks, 
die Buttons abruft. Jetzt weiß ich halt nicht, ob des ATtiny den ausgang 
so schnell auf "low" setzen kann, und somit dem CPU zuvorkommt.
Ich bin ratlos.

von Daniel J. (theend)


Lesenswert?

Es funktioniert zum teil.
Die Taste B wird gedrückt, allerdings nicht jede 5 Sekunden, sondern 
ununterbrochen.
Auch wundert es mich, das ich Vcc des ATtiny13 nicht mit strom versorgen 
muss, wieso?

von Karl H. (kbuchegg)


Lesenswert?

Daniel J. schrieb:

es im internet gelesen:
>> 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.
>
> Bedeutet, das der CPU des Snes, die buttons bei jedem "low" des Clocks,
> die Buttons abruft. Jetzt weiß ich halt nicht, ob des ATtiny den ausgang
> so schnell auf "low" setzen kann, und somit dem CPU zuvorkommt.
> Ich bin ratlos.

Für dich ist die 'raising edge', also der Übergang  low->high der 
zeitpunkt an dem du die Daten wechseln kannst. Wenn der clock seinen 
Übergang high->low macht, holt sich die NES dieses eine Bit. Zu dem 
Zeitpunkt muss es aber schon stehen! Ist ja kein Problem: Wenn der Clock 
auf high geht (bzw. gleich danach) kannst du gefahrlos das nächste Bit 
anlegen. Du musst nur damit fertig sein, bevor die nächste fallende 
Flanke kommt. Für dich als Lieferant sind nur die steigenden Flanken 
an Clock wichtig. Das ist der Zeitpunkt an dem dir die NES mitteilt: 
bitte jetzt das nächste Bit an die Datenleitung legen, ich warte noch 
ein wenig und wenn ich dann den Clock auf Low ziehe, dann hol ich mir 
den Zustand der Leitung.

Oder in deiner Grafik ganz oben:
Dein Zeitpunkt zum Wechseln der Bits ist jeweils der Anfang des 
Kästchens. Die NES holt sich dann das Bit jeweils in der Mitte des 
Kästchens.
Schau dir die Grafik an. Was passiert jeweils am Anfang jedes Kästchens? 
Das sind die Dinge auf die du einen bitwait ansetzen musst und wenn 
dieses Ereignis da ist, dann legst du schnell das Datenbit des gerade 
beginnenden Kästchens raus und wartest auf den Anfang des nächsten 
Kästchens.

von Karl H. (kbuchegg)


Lesenswert?

Daniel J. schrieb:

> Auch wundert es mich, das ich Vcc des ATtiny13 nicht mit strom versorgen
> muss, wieso?

Versorg ihn mit Strom.
Wenn nicht, dann 'versorgt' sich der Tiny über irgendwelche dubiose 
Kanäle aus den Portpins. Dazu sind die aber nicht gedacht.

von Karl H. (kbuchegg)


Lesenswert?

> Wait 5

da musst du dir was anderes einfallen lassen.

Wenn der Puls am Latch kommt, dann will die NES die Daten haben. Es 
liegt nicht an dir da zu warten. Puls an Latch bedeutet: Jetzt her mit 
den Daten.

Dein Programm ist nicht mehr länger gegenüber der NES das Programm 
welches das Sagen hat. Die NES hat das Sagen!

Und im Endeffekt wird man da auch keinen Bitwait nehmen, sondern das 
Ganze zb mittels Interrupt lösen. Aber eines nach dem anderen. Erst mal 
musst du den Mechanismus verstehen.

von Daniel J. (theend)


Lesenswert?

> Aber eines nach dem anderen. Erst mal
> musst du den Mechanismus verstehen.

Da muss ich dir recht eben, deswegen versuche ich das alles. Verstanden 
hab ich die Grafik mittlerweile, nur die umsetzung ist noch eine hürde 
:D.

Ich habe nun folgenden code, wenn vcc vom ATtiny nicht angeschlossen 
ist, funktioniert alles, Mario springt und läuft nach vorne, also "B + 
rechts" gedrückt. Wenn ich allerdings den ATtiny mit 5 volt versorge, 
läuft er nurnoch nach vorne, oder es passiert garnichts mehr. Ist mir 
unerklärlich.
Benötige ich den Pullup für den eingang? Beide snes liefert 5 volt und 
der ATtiny läuft auch mit 5 volt.
1
$regfile = "attiny13.dat"
2
$crystal = 1200000
3
$framesize = 10
4
$swstack = 10
5
$hwstack = 10
6
7
8
9
Config Pinb.2 = Input                                       'clock
10
Config Pinb.1 = Input                                       'Latch
11
Config Portb.0 = Output                                     'Data
12
Portb.1 = 1                                                 'latch Pullup Widerstand ein
13
Portb.2 = 1                                                 'clock Pullup Widerstand ein
14
Portb.0 = 0                                                 'data grundstellung, high = taste nicht gedrückt, low, taste gedrückt
15
16
17
Tosnes Alias Portb.0
18
Fromsnes Alias Pinb.1
19
Clock Alias Pinb.2
20
21
22
23
Do
24
Bitwait Fromsnes , Set                                      'warte auf latch = high
25
Tosnes = 1
26
Bitwait Fromsnes , Reset                                    'warte auf latch wieder low
27
Tosnes = 0                                                  'taste "B" gedrückt
28
Bitwait Clock , Reset                                       'warte bis clock  low
29
Bitwait Clock , Set                                         'warte bis clock wieder high
30
Tosnes = 1                                                  'alle anderen tasten bis auf "rechts" nicht gedrückt
31
32
33
Bitwait Clock , Reset                                       'warte bis clock wieder low
34
Bitwait Clock , Set                                         'warte bis clock wieder high
35
Bitwait Clock , Reset
36
Bitwait Clock , Set
37
Bitwait Clock , Reset
38
Bitwait Clock , Set
39
Bitwait Clock , Reset
40
Bitwait Clock , Set
41
Bitwait Clock , Reset
42
Bitwait Clock , Set
43
Bitwait Clock , Reset
44
Bitwait Clock , Set
45
46
Tosnes = 0                                                  'taste "rechts" gedrückt
47
Bitwait Clock , Reset
48
Bitwait Clock , Set
49
Tosnes = 1
50
Bitwait Clock , Reset
51
Bitwait Clock , Set
52
Bitwait Clock , Reset
53
Bitwait Clock , Set
54
Bitwait Clock , Reset
55
Bitwait Clock , Set
56
Bitwait Clock , Reset
57
Bitwait Clock , Set
58
59
60
61
62
Tosnes = 0                                                  'data grundstellung
63
64
65
Loop
66
67
End

Und das mit dem "wait 5" ist mir dann auch aufgefallen.
War ja wirklich dumm :D.

von Daniel J. (theend)


Lesenswert?

Kann es eventuell daran liegen, dass ich wirklich NUR den ATtiny ohne 
kondensator und 10k an RESET, an dem Super nintendo anschließe?

von Eumel (Gast)


Lesenswert?

Daniel J. schrieb:
> Kann es eventuell daran liegen, dass ich wirklich NUR den ATtiny ohne
> kondensator und 10k an RESET, an dem Super nintendo anschließe?

Deinen bisherigen Beiträgen nach ist das bestimmt nicht das einzige 
Problem. Allerdings solltest du diese beiden Dinge, vorallem den 
Abblockkondensator, noch einbauen. Alles andere ist Pfusch.

von Daniel J. (theend)


Lesenswert?

Eumel schrieb:
> Deinen bisherigen Beiträgen nach ist das bestimmt nicht das einzige
> Problem.

Was genau meinst du damit?

von Martin K. (maart)


Lesenswert?

Daniel J. schrieb:
> Eumel schrieb:
>> Deinen bisherigen Beiträgen nach ist das bestimmt nicht das einzige
>> Problem.
>
> Was genau meinst du damit?

Das er dich nicht als Hochbegabten einschätzt.


Ob der Resetwiderstand jetzt beim tiny13 unbedingt nötig ist steht im 
Datenblatt, allerdingst kostet so ein Ding auch keine 5 Euro (der Wert 
kann auch etwas von den 10k abweichen).
Ein Abblockkondensator sollte aber wirklich so dich wie möglich an den 
tiny13. Ohne könnte auch gehen, kann aber für lustige Überraschungen 
sorgen.

von Eumel (Gast)


Lesenswert?

Wenn du den Tiny NICHT in der Schaltung programmierst kannst du Reset 
auch direkt (ohne Widerstand) verdrahten. Der Widerstand ist ja 
eigentlich nur dafür da, um einen sicheren Pegel an dem Reset pin zu 
garantieren aber dem Programmer trotzdem zu ermöglichen Reset auf low zu 
ziehen. Ist der Widerstand zu klein kriegt der Programmer das nicht mehr 
hin und kann eventuell sogar beschädigt werdern.
Nochmal zum Abblockkondensator: Es kann ohne gehen muss es aber nicht. 
Dann funktioniert es z.b. manchmal oder manchmal nicht. Je nach 
Luftfeuchtigkeit und Hemdfarbe des Nachbarn.

von Daniel J. (Gast)


Lesenswert?

Programmieren tu ich außerhalb des Systems. Ich Versuchs dann mal mit 
dem Kondensator.

von Malte S. (maltest)


Lesenswert?

Der Code wird so sehr schnell unübersichtlich und extrem anfällig für 
Verzähler bei den bitwaits.

Überlegung:

Welche und v.a. wie viele Tasten gibt es?
Welche davon möchtest Du wann als gedrückt simulieren?

Man könnte darauf kommen, dass sich alle 16 Tasten als Bits einer 
16-Bit-Variablen darstellen lassen. Das ist Dein Schieberegister, das Du 
beginnend mit der falleden Flanke am Latch und dann weiter mit jeder 
steigenden Flanke am Clock Bitweise an den Ausgang gibst.

Zwischen dem letzten Impuls am Clock und der steigenden Flanke am Latch 
steht es Dir frei, diese Schieberegister-Variable mit einem neuen Wert 
zu füllen, wofür dann der Code verantwortlich ist, der die simulierten 
Tastendrücke generiert.

Immer wenn die entsprechenden Signale vom SNES kommen, musst Dein Device 
bereit sein, die Daten zu leifern. Daher ist es sinnvoll bzw. eigentlich 
erforderlich, das jeweils mit einem Interrupt zu machen:
Bei fallendem Latch: Schieberegister mit nächstem gewünschten 
Tastenzustand füllen (der schon bereitstand, nicht hier berechnen!*) und 
das erste Bit am Ausgang bereitstellen. Nächsten Wert anfordern 
(Flag-Variable).
Bei steigendem Clock: Schieberegister bitweise weiterschieben und das 
nächste Bit bereitstellen.

Dann musst Du Dich nicht mal mehr darum kümmern, wie viele Takte 
wirklich ankommen. Mit jedem Impuls am Latch wird das Ding 
synchronisiert.

*) Die Berechnung des nächsten Wertes kann dann in aller Ruhe in der 
Hauptschleife erfolgen. Nachdem der Latch-ISR das Flag gesetzt hat, das 
der Hauptschleife mitteilt, dass die nächste Tasteneingabe berechnet 
werden soll, kann diese das tun.

Dann brauchst Du irgendwelche Timing-Konstrukte nur noch z.B. zum 
zeitgesteuerten anlegen der gewünschten Tastendrücke.




Sooo, bis dahin inkl. der Interrupt-Geschichte wird es noch ein gutes 
Stück Weg sein. Aber ohne das wirst Du schnell merken, dass Deine 
Schleife immer wieder zu merkwürdigen Problemen führen wird, weil das 
Timing eben nicht hinkommt. Nur mit der Hauptschleife wird die Trennung 
zwischen Steuerung des virutellen Controllers und Weitergabe dessen 
Zustands an das SNES eine ziemlich unübersichtliche und zerbrechliche 
Angelegenheit.

Und versorge den Tiny sauber an VCC, die Schutzdioden an den Eingängen 
werden es Dir danken.

von Karl H. (kbuchegg)


Lesenswert?

Malte S. schrieb:

> Immer wenn die entsprechenden Signale vom SNES kommen, musst Dein Device
> bereit sein, die Daten zu leifern. Daher ist es sinnvoll bzw. eigentlich
> erforderlich, das jeweils mit einem Interrupt zu machen:
> Bei fallendem Latch: Schieberegister mit nächstem gewünschten
> Tastenzustand füllen (der schon bereitstand, nicht hier berechnen!*) und
> das erste Bit am Ausgang bereitstellen. Nächsten Wert anfordern
> (Flag-Variable).
> Bei steigendem Clock: Schieberegister bitweise weiterschieben und das
> nächste Bit bereitstellen.

Genau so würde ich das auch machen.
Nur mit dem einen kleinen Unterschied, dass ich für alle Tasten ein 
16-er Array nehmen würde, in der ISR einen globalen Index hochzähle 
(natürlich mit Prüfung) und den im Latch-Interrupt wieder auf 0 setze.

Dann kann jeder wie er lustig ist, im Array Tasten als gedrückt oder 
nicht gedrückt hinterlassen. Speicher hat der µC genug und zeitkritisch 
ist das auch alles nicht.


> Sooo, bis dahin inkl. der Interrupt-Geschichte wird es noch ein gutes
> Stück Weg sein. Aber ohne das wirst Du schnell merken, dass Deine
> Schleife immer wieder zu merkwürdigen Problemen führen wird, weil das
> Timing eben nicht hinkommt. Nur mit der Hauptschleife wird die Trennung
> zwischen Steuerung des virutellen Controllers und Weitergabe dessen
> Zustands an das SNES eine ziemlich unübersichtliche und zerbrechliche
> Angelegenheit.

Das auf jeden Fall.
Aber es erklärt mit seinem momentanen Programm nicht, warum alles steht, 
wenn der µC selbst mit Strom versorgt wird.
Kann es sein, dass die SNES mit 3.3V Pegeln arbeitet und daher 
Pegelwandler notwendig sind, wenn der µC auf 5V läuft?

von Daniel J. (theend)


Lesenswert?

@Malte S.

Vielen dank für deine Hilfe, mein Code oben war natürlich nur zum testen 
und sollte natürlich nicht der entgültige code sein.

@Karl Heinz Buchegger
Das snes liefert 5 volt, ich weiß allerdings nicht ob Latch, Data, und 
Clock mit 3,3 volt arbeiten, daran habe ich noch nicht gedacht, da ich 
davon ausgegangen bin, das wenn der Controller 5 Volt bekommt, auch 5 
Volt zurückkommen.

@all
Ich wollte eigentlich sowas realisieren wie einen Bot, so das Mario 
praktisch z.B. das erste Land automatisch durchspielt.

von Daniel J. (theend)


Lesenswert?

So, bin schon ein ganzes stück weiter, das problem war, das ich bei 
jeder abfrage taste "B und Rechts" gedrückt habe, somit läuft er 
natürlich nur nach rechts, und mario springt nur einmal. Weil wenn man 
die Taste "B" gedrückt hält, er eben nur einmal springt.

So nun wollte ich auf Variablen setzen, die später von einer SD karte 
kommen. Da habe ich eine Schleife mit abfrage:
1
If N = 0 And B = 1 Or N = 1 And Y = 1 Or N = 2 And Sel = 1 Or N = 3 And Sta = 1 Or N = 4 And Ho = 1 Or N = 5 And Run = 1 Or N = 6 And Lin = 1 Or N = 7 And Re = 1 Or N = 8 And A = 1 Or N = 9 And X = 1 Or N = 10 And L = 1 Or N = 11 And R = 1 Then
2
Tosnes = 0
3
End If
Allerdings nimmt er die nicht an, ist der Takt mit 9,6mhz zu langsam ?

Ich habe zuvor jede abfrage in eine "if-abfrage" gesetzt. Bei 1.2 mhz 
kam beim Snes nur wirres zeug raus. Ich ging davon aus, das der Tiny bei 
1,2 mhz zu langsam war und habe den Teiler von 8 deaktiviert. Nun hüpft 
mario, aber er läuft anstelle nach rechts, nach links. Klammere ich alle 
abfragen bis auf taste "B" und "rechts" aus, funktioniert es so. 
Entweder es verschiebt sich irgendwo, es werden mehrere "Pfeiltasten" 
gedrückt, und die Taste "links" gewinnt oder der atTiny13v ist zu 
langsam. (9,6mhz maximal, mit externem quarz maximal 10mhz).
Ich würds ja mit 16mhz testen, allerdings habe ich nur den attiny13V 
hier.

von Malte S. (maltest)


Lesenswert?

Keine Ahnung, wie die Vorangsregeln der Operatoren And und Or bei BASIC 
sind, ich würde in jedem Fall Klammern empfehlen.
Kann mir aber gut vorstellen, dass das nicht innerhalb eines Taktes 
auszuwerten geht.
Warum so kompliziert?

Du kannst auf der SD-Karte einfach 16-Bit-Werte speichern:
0x0000 = nichts gedrückt
0x0001 = B gedrückt
0x0005 = B und Sel gedrückt
etc.

Dann musst du den Ausgabewert nur im ersten Takt je nach Wert des ersten 
(untersten) Bit setzen, im zweiten Takt je nach Wert des zweiten Bit 
etc:
1
Tosnes = !(keys & (1 << N));

Sorry, müsstest du halt von C nach BASIC übersetzen. Da die variable 
Schiebeoperation auf dem AVR auch nicht gerade das Gelbe vom Ei ist, 
besser:
1
uint16_t current = 1; /* Maske für das aktuelle Bit */
2
uint16_t keys = 0; /* Aktuell gedrückte Tasten */
3
4
/* Zum Senden des nächsten Bits: */
5
Tosnes = !(keys & current);
6
current <<= 1;
7
8
/* Nach 16 Bits ist Schluss, von vorne beginnen: */
9
if (!current) current = 1;

Parallel dazu muss keys immer entsprechend der gerade zu drückenden 
Tasten gesetzt werden.
Auf der SD-Karte muss dann neben dem jeweiligen Wert noch stehen, wann 
das zu geschehen hat, z.B. in ms seit Start.
Ob du nun direkt immer den Wert aller Tasten speicherst:
<Zeitstempel> <Wert aller Tasten ab hiert>
oder die Änderungen zum vorangegangenen Zustand:
<Zeitstempel> <Taste(n)> <drücken/lösen>
und das dann entsprechend in keys überführst ist deine Sache. Hat beides 
seine Vor- und Nachteile.

von Daniel J. (Gast)


Lesenswert?

Gut, dein Code versteh ich überhaupt nicht :D.
Wie bekomme ich aus 0&0005 "B und Sel"?

von Malte S. (maltest)


Lesenswert?

Du hast 16 Tasten. Die lassen sich perfekt in einem 16 -Bit-Wert 
ablegen, jedes Bit represäntiert den Wert einer Taste:
1
? ? ? ? R L X A R L R H S S Y B
2
                e i u o t e
3
                  n n   a l
4
-------------------------------
5
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = &h0000, alle Bits 0, nichts gedrückt
6
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 = &h0001, Bit für "B" gesetzt: B gedrückt.
7
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 = &h0005, Bits für "Sel" und "B" gesetzt: Sel und B gedrückt.

(&h ist in BASIC dasselbe wie 0x in C-Ähnlichen)
Die Darstellung ist spiegelverkehrt zum Diagramm im ersten Post. 
Andersrum geht natürlich auch, dann musst du die Maske andersrum 
schieben.

Um den Zustand einer einzelnen Taste zu erfahren, z.B. zwecks Weitergabe 
an das SNES, muss der Gesamtwert mit der passenden Maske "verundet" 
werden:
1
  ? ? ? ? R L X A R L R H S S Y B
2
                  e i u o t e
3
                    n n   a l
4
  -------------------------------
5
  0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 = &h0005, Bits für "Sel" und "B" gesetzt: 
6
7
& 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 = Maske für "Sel"
8
= ===============================
9
  0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 = Ja, das Bit ist gesetzt, die Taste gedrückt.

Das macht der Code oben:
1
Tosnes = !(keys & current);
current enthält die Maske zur aktuell vom SNES abgefragten Taste. (keys 
& current) ist ungleich null, wenn das entsprechende Bit in keys gesetzt 
ist. Durch die logische Negation (!) wird Tosnes 0, wenn das so ist. Ist 
das Bit nicht gesetzt, wird Tosnes 1.
Ausführlicher in Pseudo-Code:
1
if (keys and current) <> 0 then
2
  Tosnes := 0
3
else
4
  Tosnes := 1

Dann wird current (die Maske) um eins nach links verschoben, um beim 
nächsten Mal das nächsthöhere Bit, also den Wert für die nächste Taste 
zu untersuchen:
1
current <<= 1;

Bitmanipulation

Auf diese Weiste kannst du alle 16 Tasten in einer einzigen Variable 
speichern und das ganze in sehr viel weniger Taktzyklen abarbeiten als 
mit einzelnen Variablen und spezifischen Abfragen. Außerdem spart es 
eine Menge Speicher und Tipparbeit, da der ganze Code jetzt überhaupt 
nichts mehr über die Funktion oder Namen der einzelnen Tasten wissen 
muss. Es gibt nur noch einzelne Bits.

Zugegeben, das Beispiel in meinem letzten Post war etwas sehr knapp. 
Hoffe, jetzt wird es etwas klarer.

von Daniel J. (theend)


Lesenswert?

Sehr gut beschrieben, verstehe es gut.
So werde ich das dann auch mal versuchen. Mein code hat bisher eh schon 
888bytes beansprucht, von 1kb verfügbaren. Mit SD Karten lesen habe ich 
bisher auch noch nichts gemacht. Aber ich denke da wird der Platz dann 
schon sehr knapp :D.
vllt Weich ich auch auf nen anderen aus.

Was aber genau bedeutet eiuote nnal ?

Malte S. schrieb:
> e i u o t e
>                     n n   a l

von Malte S. (maltest)


Lesenswert?

:)

Das gehörte zu den Zeilen darüber:

R L R ...
e i u ...
  n n ...

Als Spaltenüberschriften von oben nach unten Re, Lin, Run entsprechend 
deinen Variablennamen.

von Daniel J. (theend)


Lesenswert?

Malte S. schrieb:
> Als Spaltenüberschriften von oben nach unten Re, Lin, Run entsprechend
> deinen Variablennamen.

arg ich Idiot :D
Danke

von Daniel J. (theend)


Lesenswert?

Kann ich mein vorhaben auch irgendwie anders realisieren?
Ohne die PORT's ein und aus zu schalten, also zb per SPI oder UART ka.
Ich kenn mich mit den verschienenen schnittstellen nicht sonderlich aus.

von Malte S. (maltest)


Lesenswert?

Hmm, als SPI Slave könnte evtl. gehen. Latch an SS, Clock an SCK und 
Data an MISO. Geht das Latch nur runter, wenn auch Daten abgefragt 
werden (Clock)? Probier's halt aus. Im Datenblatt deiner Controller 
steht, wie das geht. Hint: Der Tiny13 hat kein serielles Interface bzw. 
nur eines zum Programmieren, nicht für das Programm nutzbar. Diese 
Variante würde den 13er also ausschließen.
UART fällt aus, da du keine Start/Stop-Bits hast.

von Daniel J. (theend)


Lesenswert?

Hätte jetzt auch den Attiny85 zur verfügung, oder 2313.
Ich habe nur bisher garnicht mit SPI gearbeitet, und wäre für einen 
kleinen Codeschnipsel in bascom dankbar

von Malte S. (maltest)


Lesenswert?

öhm... habe zwar noch nie was mit bascom gemacht, aber es gibt da so ne 
Seite...https://www.google.de/?q=bascom+spi+slave
SCNR ;)

Der 85er ist im Zweifelsfall der Controller der Wahl, wenn du die 
Portzahl des 2313 nicht brauchst.
Allerdings...du schriebst was von SD-Karte. Damit dürfte das USI als 
Master belegt sein, oder? Also doch eher der 2313 mit USART im SPI-Modus 
als Master für die SD. und das USI als SPI-Slave zum SNES.

Ob's das Wert ist weiß nicht. Das bisschen Pingewackel ist eigentlich 
auch in Software nicht die Welt.

von Daniel J. (theend)


Lesenswert?

War nur irgendwie stutzig, weil ich nicht wusste ob ich MISO und MOSI 
brauche. Aber jetzt weiß ichs, vielen dank

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.