Ich habe zwei Register. In beiden befindet sich ein Wert zwischen null
und drei. Es sollen bestimmte Kombinationen erkannt werden:
1) R1 = 0 und R2 = 2 --> Unterprogramm A
2) R1 = 0 und R2 = 1 --> Unterprogramm B
3) R1 = 2 und R2 = 3 --> Unterprogramm A
4) R1 = 2 und R2 = 0 --> Unterprogramm B
.
.
.
Wie kann man das am besten Lösen? Der einfachste Weg wäre, eine Abfrage
mit ganz vielen Sprüngen zu erstellen. Gibt es eine elegantere und vor
allem platzsparendere Lösung?
So:
Funktionspointertabelle mit 16 Einträgen (denn soviele Kombinationen
kann es ja geben), als Index in die Tabelle R2 << 2 + R1 verwenden.
Der erste Eintrag entspricht R1 = 0 und R2 = 0, der zweite entspricht R1
= 1 und R2 = 0 etc.
Für jede Bitkombination von R1 und R2 wird in die
Funktionspointertabelle die Adresse der aufzurufenden Funktion
("Unterprogramm") eingetragen.
An Adresse X kommt eine lange Liste mit Sprüngen:
rjmp ProgA ; r1 = 0, r2= 0
rjmp ProgB ; r1 = 0, r2= 1
...
(16 Einträge insgesamt)
Dann ein jump an die Adresse (X + r1<<2 + r2)
Theoretisch gibt es nur 8 mögliche Kombinationen. Bezieht man alle
möglichen Störfälle ein, gibt es 16 mögliche.
Kann man bei dem 8051 wirklich so eine Tabelle anlegen? Das heißt doch
look up table oder?
Ich denke, Du suchst eine Sprungtabelle.
Falls es sich um einen (nicht zu kleinen und zu alten) AVR handelt, dann
bietet sich der indirekte Sprung mittels 'ijmp' an.
Dazu wird der Z-Pointer auf die Adresse mit der Sprungtabelle
positioniert, dann der Index draufaddiert, dann mit ijmp die Adresse
angesprungen, auf die der Z-Pointer zeigt. Dort steht dann die oben
bereits erwähnte Liste mit rjmp xyz - Einträgen.
Geht gut und recht schnell, nutze ich gerne bei größeren Menüdialogen.
...
Ist ein AT89S8252, so weit ich weiß, kennt er kein IJMP. Aber indirekte
Sprünge sollen mit z.B. JMP @A+DATAPOINTER
Ich bin leider noch nicht so weit, um das alles 100% zu verstehen.
Also ich stelle mir das so vor:
Man hat im Speicher z.B. 5 Adressen mit bestimmten Werten, welche man
zuvor auf den uC geladen hat. Das Programm spricht nacheinander diese
Adresse an und vergleicht sie mit einem Wert (z.B. im ACCU), wenn der
Wert übereinstimmt, wird eben ein Unterprogramm aufgerufen.
Man kann das entweder nacheinander für jeden Wert in der Tabelle machen
oder eine Art Schleife durch indirekte Sprünge Programmieren. Stimmt das
so?
Könnte mir bitte jemand ein kleines Beispiel mit einer Tabelle im
Flash-Speicher zeigen?
Danke euch soweit!
Das Programm verstehe ich noch nicht ganz.
mov a, r1
add a, acc
add a, acc ; * 4
orl a, r2
anl a, #0Fh ; table = 16 entries
Hier werden Werte aus R1 und R2 in ein register kopiert und
nebeneinander platziert: 0 | 0 | 0 | 0 | R1 | R1 | R2 | R2
------------------------------------------------------------------------
--
rl a ; * 2 (AJMP = 2 byte)
Hier werden die Bits gedreht: R2 | R2 | R1 | R1 | 0 | 0 | 0 | 0
------------------------------------------------------------------------
--
mov dptr, #tabelle
Die Adresse der Tabelle wird in den Datapointer geladen. Irgendwie
erkennt mein Assembler dptr nicht, ist wohl nicht in der Bibliothek
vorhanden. Welche Adresse hat der Datapointer?
------------------------------------------------------------------------
--
jmp @a+dptr
Relativsprung an die Adresse:
R2 | R2 | R1 | R1 | 0 | 0 | 0 | 0 | T | T | T | T | T | T | T | T
Oder sind die zwei Bytes vertauscht?
------------------------------------------------------------------------
--
tabelle:
ajmp ...
ajmp ...
Das ist ein Label im Speicher, wo die 16 Kombinationen in 16 Adressen
gespeichert sind. Warum kommt drunter ajmp?
------------------------------------------------------------------------
--
Klärt mich bitte auf.
Ach so, ich habe gedacht, der Befehl RL dreht das Register um die eigene
Achse. In Wirklichkeit wird es ja nur um eine Stelle verschoben.
Jetzt sollte es klappen, danke noch Mal.
Hm, ich sitze hier jetzt seit einer Stunde und kann den Fehler nicht
finden. Wahrscheinlich läuft irgendwo ein Register über, der uC hängt
sich auf, wenn SIG_A = 0 und SIG_B = 1 ist.
Maxim wrote:
> Vor Freude wuße ich erstmal gar nicht, wo ich die Datei suchen soll ...
Hallo Maxim,
habs mir durchgesehen, tut mir leid aber das wird und kann nie
funktionieren.
Wenn Du möchtest, poste ich hier ne Routine um nen Encoder auszulesen.
Die funktioniert schon in viele Geräten!
?????
Schade, dass mein Programm nicht funktioniert. Aber da habe ich mir wohl
zu viel für einen Einstieg vorgenommen.
Ich habe dein Programm durchgelesen und einen PAP erstellt. Mit der
Logik habe ich mich aber noch nicht beschäftigt, jedoch erahne ich, wie
es funktioniert. Bin heute zu müde, um da noch etwas zu machen.
Der PAP ist angehängt.
Danke für deine Hilfe.
Hallo Peter,
das funktioniert schon.
Aus leidlicher Erfahrung weiß ich aber, das wenn sich zwischen den
Auswertungen der beiden Signale der Phasenzustand ändert, eine
Fehlauswertung stattfindet. Dies kann auch passieren wenn ein höher
priorisierter Ínterrupt zwischen der Auswertung der beiden Signale
ausgeführt wird und die Distanz der Phasenauswertung verschiebt.
Deswegen sollte man, beide Signal zeitsynchron latchen.
Dirk Hofmann wrote:
> Aus leidlicher Erfahrung weiß ich aber, das wenn sich zwischen den> Auswertungen der beiden Signale der Phasenzustand ändert, eine> Fehlauswertung stattfindet. Dies kann auch passieren wenn ein höher> priorisierter Ínterrupt zwischen der Auswertung der beiden Signale> ausgeführt wird und die Distanz der Phasenauswertung verschiebt.
Ein nicht korrigierbarer Fehler kann erst dann auftreten, wenn
dazwischen 2 Phasenübergänge liegen, d.h. Du hast nen exorbitant langen
Interrupt dazwischen oder das Intervall des Timerinterrupts ist zu groß.
Man sollte also immer dem Encoder-Interrupt die höchste Priorität geben
und das Timerintervall kurz genug wählen.
Idealer Weise sollte die Timerinterruptfrequenz mindestens doppelt so
hoch wie die maximale Schrittfrequenz des Encoders sein, damit man auch
noch Zeit hat, Preller zu korrigieren.
Peter
P.S.:
Du hast das warscheinlich damit verwechselt, den gleichen Pin mehrmals
in der Routine abzufragen. Dann kann in der Tat sonstwas passieren, wenn
er sich genau zwischen 2 Abfragen ändert.
Man muß immer darauf achten, innerhalb eines Auswertezyklus asynchrone
Eingänge nur einmalig einzulesen und dann zwischenzuspeichern, wenn
deren Zustand nochmal benötigt wird.
Habe mich gerade hingesetzt und den PAP (da hat sich ein kleiner Fehler
eingeschliechen auf dem Bild ...) manuell abgelaufen. Habe den
Algorithmus weitgehend verstanden. Ich muss sagen, der ist ziemlich
raffiniert, im vergleich zum meinem ... ;-) Wie kommt man nur auf solche
"einfachen" Lösungen?
Hallo Peter,
mir ist das schon klar, mit Interruptpriorisierung.
Da Maxim gerade einsteigt, wollte ich auf diese Problematik hinweisen,
das daß nicht zur Frustration führt und zur Veranschaulichung.
Hab mal ne Frage an Dich. Hattest Du schon mal was mit Software JPEG
decodierung zu tun? Hab noch keine gute Beschreibung gefunden, hab zwar
das Buch von John Miano, aber der File Aufbau geht nicht direkt klar.
Maxim, wenn man ne Weile programmiert, erarbeitet man sich Viele
Problemlösungsstrategien systematisch, also immer weiter machen und dran
bleiben. Learning by doing sozusagen