Forum: Mikrocontroller und Digitale Elektronik Zwei Zahlen vergleichen und...


von Maxim (Gast)


Lesenswert?

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?

von Clemens E. (linuxhippy)


Lesenswert?

soweit ich weiß nicht, bei x86 glaub ich gibt jump-tables oder so.
So gesehen ists halb so tragisch, weil r1 ja entweder 0 oder 2 ist.

Mfg Clemens

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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.

von Jan (Gast)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

Wie geht die Reihe weiter?

Im Moment sieht es so aus:
Wenn Bit 1 in R2 gesetzt ist, dann kommt A zum Zug ansonsten B

von Maxim (Gast)


Lesenswert?

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?

von Hannes L. (hannes)


Lesenswert?

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.

...

von Maxim (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

1
mov a, r1
2
add a, acc
3
add a, acc      ; * 4
4
orl a, r2
5
anl a, #0Fh     ; table = 16 entries
6
rl a            ; * 2 (AJMP = 2 byte)
7
mov dptr, #tabelle
8
jmp @a+dptr
9
tabelle:
10
ajmp ...
11
ajmp ...
12
...


Peter

von Joe (Gast)


Lesenswert?

Peters Beispiel ist ok allerdings mußt du bei ajmp berücksichtigen das 
dass Sprungziel innerhalb eines 2k Segmentes liegt.

von Maxim (Gast)


Lesenswert?

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.

von Maxim (Gast)


Lesenswert?

Hey, last mich auf halber Strecke nicht hängen.

von Dirk H. (arm-dran)


Lesenswert?

Peter Dannegger wrote:

Ganz Einfach


>
1
> mov a, r1
2
3
R1 in den Akku
4
5
> add a, acc
6
7
Mit sich selbst addieren heiß also x 2
8
9
> add a, acc      ; * 4
10
11
Ergebnis noch mal mit sich addieren also nochmal x 2
12
Beiden Add Befehle ersetzen ein Multiplikation mit 4
13
14
> orl a, r2
15
16
den Wert aus R2 dazu ODERN (wie "addieren")
17
Vorraussetzung hier ist, daß der Wert aus R1 nie größer als 3
18
ist sonst gehts nicht
19
20
> anl a, #0Fh     ; table = 16 entries
21
22
die unteren 4 Bit ausfiltern, sodaß 16 Kombinationen übrig blieben
23
24
> rl a            ; * 2 (AJMP = 2 byte)
25
26
einmal nach links um auf eine 32Byte Tabelle zu erweitern
27
Wie oben geschrieben sind AJMp Befehle im auf eine 2KB Page beschränkt
28
Wenn Du Programmerweiterungen machst und den Sourcecode verschiebst
29
kann es Probleme geben
30
Um mit LJMP statt AJMP Befehlen zu arbeiten schreibst du statt RL A golgendes
31
32
mov  B,A
33
rl   A
34
add  A,B
35
36
dann hast du eine 3x16 Byte Tabelle
37
38
> mov dptr, #tabelle
39
40
Datenpointer an Tabellenanfang
41
42
> jmp @a+dptr
43
44
Zur Funktion springen
45
46
> tabelle:
47
> ajmp ...
48
> ajmp ...
49
> ...
50
>
>
>
> Peter

Gruß

Dirk

von Maxim (Gast)


Lesenswert?

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.

von Dirk H. (arm-dran)


Lesenswert?

Ja so ein Befehl wäre auch schön,

sowas hätte ein paar Leute hier im Forum echt glücklich gemacht

von Maxim (Gast)


Lesenswert?

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.
1
;Zweiter Versuch mit dem Drehimpulsencoder
2
3
include REG8252.INC
4
5
;Zuweisungen
6
SIG_A       EQU P3.3  
7
SIG_B       EQU P3.2  
8
LAST_STATE  EQU R6
9
10
;Resets
11
MOV  P2, #0
12
MOV  LAST_STATE, #0
13
14
;***************************************************************************************************
15
16
;Die Hauptschleife
17
LOOP:   ACALL CHECK_DIG_STATE
18
        SJMP  LOOP
19
20
;***************************************************************************************************
21
22
CHECK_DIG_STATE:  ACALL   READOUT_DIG      
23
      MOV  A, LAST_STATE
24
      MOV  B, #04h        
25
      MUL  AB
26
27
      ACALL   READOUT_DIG
28
      ORL  A, LAST_STATE
29
      ANL  A, #0Fh      
30
                    
31
      MOV  DPTR,  #TABLE
32
      JMP  @A+DPTR
33
34
;***************************************************************************************************
35
36
;Liest den Drehimpulsgeber aus und speichert den Zustand im Register LAST_STATE
37
38
READOUT_DIG: JB   SIG_A, A_TRUE
39
       SJMP A_FALSE
40
        
41
A_TRUE:      JB   SIG_B, STATE_2
42
       SJMP STATE_1
43
        
44
A_FALSE:     JB   SIG_B, STATE_3
45
       SJMP STATE_0
46
47
STATE_0: MOV  LAST_STATE, #0  ;SIG_A=0 and SIG_B=0
48
   RET
49
      
50
STATE_1: MOV  LAST_STATE, #1  ;SIG_A=1 and SIG_B=0
51
   RET
52
53
STATE_2: MOV  LAST_STATE, #2  ;SIG_A=1 and SIG_B=1
54
   RET
55
56
STATE_3: MOV  LAST_STATE, #3  ;SIG_A=0 and SIG_B=1
57
   RET
58
59
;***************************************************************************************************
60
61
TABLE:  SJMP  NOA
62
  SJMP  CW
63
  SJMP  ERR
64
  SJMP  CCW
65
  SJMP  CCW
66
  SJMP  NOA
67
  SJMP  CW
68
  SJMP  ERR
69
  SJMP  ERR
70
  SJMP  CCW
71
  SJMP  NOA
72
  SJMP  CW
73
  SJMP  CW
74
  SJMP  ERR
75
  SJMP  CCW
76
  SJMP  NOA
77
78
;***************************************************************************************************
79
80
NOA:    NOP
81
        RET
82
83
ERR:    NOP
84
  RET
85
86
CW:     SETB P2.7
87
  RET
88
    
89
CCW:    CLR  P2.7
90
  RET
91
92
END

von Dirk H. (arm-dran)


Lesenswert?

Hallo Maxim,

hänge den Sourcecode mal als Textdatei an,

ich korrigiere Ihn Dir.

Dirk

von Maxim (Gast)


Angehängte Dateien:

Lesenswert?

Vor Freude wuße ich erstmal gar nicht, wo ich die Datei suchen soll ...

von Dirk H. (arm-dran)


Lesenswert?

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!

?????

von Dirk H. (arm-dran)


Angehängte Dateien:

Lesenswert?

So, ich hab mal in den Anhang gelegt.

Viel Spaß damit.

Wenn es Fragen gibt, dann melde Dich.

Gruß

Dirk

von Maxim (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Hier mal die Assemblerversion meines Encoderprogramms.

Ich taste ihn im Timerinterrupt ab.


Peter

von Dirk H. (arm-dran)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Maxim (Gast)


Lesenswert?

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?

von Dirk H. (arm-dran)


Lesenswert?

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

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.