Forum: Mikrocontroller und Digitale Elektronik 240fache Verzweigung


von Maxim (maxim) Benutzerseite


Lesenswert?

Wie kann ich am besten eine 240fache Verzweigung realisieren?

Abhängig von einem Wert zwischen 10 und 250 soll jeweils an eine andere 
Stelle gesprungen werden.

Ich habe das jetzt mit CJNE gelöst. Der uC Prüft also im schlimmsten 
Fall 239 Mal, ob der Wert mit einer Konstante übereinstimmt und springt 
gegebenenfalls.

Das geht doch sicher effizienter, oder?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

OMG! Wer tipt sowas alles ein o.O
Nimm ne Sprungtabelle...
1
ldi ZL, LOW(jumptable*2)  ; Tabellenindex laden
2
ldi ZH, HIGH(jumptable*2) ; Tabellenindex laden
3
( subi wert, 10 )       ;"Startindex" anpassen
4
add ZL, wert            ;Wert aufadieren
5
sbc ZH, -1              ;Carry auf High
6
ijmp
7
back:
8
9
label1:
10
  code
11
  rjmp back
12
label2:
13
  code
14
  rjmp back
15
.
16
.
17
.
18
label250:
19
  code
20
  rjmp back
21
22
23
jumptable:
24
rjmp label1
25
rjmp label2
26
rjmap label3
27
.
28
.
29
.
30
rjmp label250

ist sehr viel schneller und braucht wahrscheinlich noch weniger code.
Wenn dein wert nicht bei 0 anfängt mußt du vorher noch 10 abziehen (hab 
ich mal in klammern angedeutet.)

Vorteil ist das du immer konstante Zeit brauchst für den Vergleich.
Nachteil: Der Prozessor muß inderekten Sprung unterstützen.

von zonendoedel (Gast)


Lesenswert?

Moin moin,

schmunzel...
wusste gar nicht das eine Sptungtabelle so aussieht.

>jumptable:
>rjmp label1
>rjmp label2
>rjmap label3
>.


Mal ein Beispiel mit dem MSP430:
In: R4

  clr  R5
ParCmd  cmp.b  #0,CmdTbl(R5)
  jz  NoCmd
  cmp.b  CmdTbl(R5),R4
  jz  FndCmd
  inc  R5
  jmp  ParCmd
FndCmd  rla  R5
  mov  CmdAdr(ACC),PC
NoCmd  bla
  bla

CmdTbl
  DB  08h,0dh,1bh,'A','C','+','-','0',0
  EVEN
CmdAdr
  DW  CmdBS,CmdCR,CmdESC,LtrA,LtrC,CmdPl,CmdMi,Cmd0
  EVEN

CmdBS
  bla
  bla

CmdCR
  bla
  bla

und so weiter...


Und wech...

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

zonendoedel wrote:
> Moin moin,
>
> schmunzel...
> wusste gar nicht das eine Sptungtabelle so aussieht.
>
>>jumptable:
>>rjmp label1
>>rjmp label2
>>rjmap label3
>>.
Tjoar hm... wieso nicht?
Ich mein ich habs jezt so ausm Gedächtnis hinprogrammiert und ist halt 
AVR ASM aber im Prinzip funktioniert das schon so...
Man kann natürlich auch eine Tabelle der Label anlegen, von der man die 
Adresse lädt, und dann mit IJMP... jeder wie er es mag.
Stand ja nicht dabei was nun genau er will welche Architektur, welcher 
proz...

Auf diese weise kann man aber auch in grenzen nen Fallthroug realisieren

rcall XYZ
rcall fallthrough
rjmp blabla

von zonendoedel (Gast)


Lesenswert?

Hmmm..

s/ACC/R5/

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Hab eben mal geschaut Wikipedia sagt z.B.:

"Dazu sind die Aufrufe (oder manchmal auch nur die nackten 
Funktionsadressen) mit konstanter Länge hintereinander wie in einer 
Tabelle im Speicher angeordnet. Sie bestehen typischerweise aus 
einfachen Sprungbefehlen an die Stelle im ROM oder innerhalb der 
Funktionsbibliothek"

Und die Interuptvektoren im AVR sind auch ne "Sprungtabelle"... also seh 
ich jezt grad nicht warum mein Ansatz so verkehrt ist?

von zonendoedel (Gast)


Lesenswert?

Moin moin @Läubi,

jojo, wie zu guten alten CP/M-C64-Zeiten.

Die Tabellenlösung ist halt ausgesprochen flexibel.
Die Interruptvektortabellen aktueller CPUs/MCUs arbeiten ja ähnlich.
Nur steinalte Design arbeiten da z.B. mit JMPs (8051...)

Aber jeder wie er mag...

von Allu (Gast)


Lesenswert?

Hallo Läubi,

an deiner Lösung ist nichts falsch. Die Auswertung mit einem berechneten 
Sprungziel finde ich für diese Aufgabenstellung optimal.

Man kann auch die Rückkehradresse auf dem Stack ablegen, die 
Zieladressen ohne Jmp untereinanderschreiben, Tabellenadresse berechnen 
und den Inhalt ebenfalls auf dem Stack ablegen. Jetzt das Zielprogramm 
mit einem ret anspringen und mit einem ret abschliessen. Dann stimmt der 
Stack wieder und das Programm wird an der vorgegebenen Rückkehradresse 
fortgesetzt.

Grüße Allu

von Joe (Gast)


Lesenswert?

Wahrscheinlich geht dieser Thread hier weiter ;-))

Beitrag "Indirekte Sprünge mit 8051"

er meint eine 8051 Typ und da kann man es z.B. so machen.

CMD:          mov a,command      ;
    rl a        ;ajmp = 2 Bytes
    mov dptr,#commands    ;pointer @ cmd
    jmp @a+dptr      ;execute commands
commands:  ajmp command_1      ;
    ajmp command_2      ;
    ajmp command_3            ;
    ajmp command_4            ;
.....
.....


Allerdings muß das Sprungziel innerhalb eines 2k Blocks liegen.

von Joe (Gast)


Lesenswert?

Ich liebe Tabs ;-))

von Maxim (maxim) Benutzerseite


Lesenswert?

Danke euch für die vielen Tipps!

Habe leider vergessen zu erwähnen, dass ich einen 8252 und Assembler 
nutze, aber das Prinzip ist ja das selbe.

Statt einer Sprungtabelle oder einer 240fachen Verzweigung könnte ich in 
meinem Programm den Wert auch durch "Timer = 1 / (3 * 10^-6 * R0)" 
berechnen, aber eine Sprungtabelle mit vorberechneten Werten ist in 
diesem Fall einfacher, oder?

von Joe (Gast)


Lesenswert?

Ja, so ist es.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Noch einfacher ist ein Array, also das Lesen von einer berechneten 
Adresse. Die Sprungtabelle ist unnötiger Aufwand.

von Maxim (maxim) Benutzerseite


Lesenswert?

Aber der Timer ist 16-bittig, kann ich ein 16-bittiges Array anlegen? Da 
muss ich halt immer zwei Bytes abspeichern und dann beim Sprung mit RL 
die Adresse anpassen?

von Maxim (maxim) Benutzerseite


Lesenswert?

VALUE001:  DB  513d

VALUE002:  DB  514d

VALUE003:  DB  516d

ist ja dasselbe wie:

VALUE001H:  DB  1d
VALUE001L:  DB  1d

VALUE002H:  DB  1d
VALUE002L:  DB  2d

VALUE003H:  DB  1d
VALUE003L:  DB  4d

oder?

von Joe (Gast)


Lesenswert?

So Andreas, wir warten ;-))

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Genau so. Die vielen Labels kannst du dir sparen, schreib einfach deine 
240 Werte hintereinander in den Speicher, dann kannst du dir die Adresse 
so ausrechnen:

adresse = (x - 10) * 2 + startadresse

von Maxim (maxim) Benutzerseite


Lesenswert?

Andreas Schwarz wrote:
> Genau so. Die vielen Labels kannst du dir sparen, schreib einfach deine
> 240 Werte hintereinander in den Speicher, dann kannst du dir die Adresse
> so ausrechnen:
>
> adresse = (x - 10) * 2 + startadresse

So wollte ich das auch machen. :-)

Habe ein kleines Testprogramm geschrieben. Leider funktioniert es nicht 
richtig. Habe den Debugger verwendet, aber bis jetzt nicht 
herausgefunden, wo der Fehler liegt.

1
INCLUDE  C:\RIDE\INC\51\ATMEL\REG8252.INC
2
3
MOV  P2, #0h
4
MOV  R0, #0h
5
6
LOOP:  JB  P3.3, WAIT_FOR_Z
7
  SJMP  GO_ON 
8
    
9
WAIT_FOR_Z:  JNB  P3.3, BUTTON_OK
10
    SJMP  WAIT_FOR_Z
11
        
12
BUTTON_OK:  INC  R0          ;Falls Taster betätigt, erhöhe R0 um 1
13
14
GO_ON:  MOV  DPTR, #TABELLE    ;Lade Adresse des Arrays in den Datenzeiger
15
    MOV  A, R0          
16
    RL    A                 ;Verschiebe Wert um eine Stelle nach links (gleich der Multiplikation mit 2)
17
    ADD  A, #1d        ;Addiere 1, um an das Low-Byte zu kommen
18
    MOVC  A, @A+DPTR      ;Kopiere Inhalt aus dem Array in den Akkumulator
19
    MOV  P2, A  
20
      
21
RET_GO_ON:  SJMP  LOOP
22
23
TABELLE:
24
      
25
VALUE001:  DB  513d  ;Low-Byte = 1
26
27
VALUE002:  DB  514d  ;Low-Byte = 2
28
29
VALUE003:  DB  516d  ;Low-Byte = 4
30
31
VALUE004:  DB  520d  ;Low-Byte = 8
32
       
33
VALUE005:  DB  528d  ;Low-Byte = 16
34
                    
35
END

Am Port P2 sind 8 LEDs angeschlossen. Mit diesem Programm sollte bei 
einem Tastendruck (Taster am P3.3) immer eine LED weitergeschaltet 
werden. Stattdessen leuchtet am Anfang die zweite, dann die vierte und 
bei einem weiteren Tastendruck die erste LED. Danach erscheinen alle 
möglichen Kombinationen, da der Datenzeiger scheinbar irgendwo auf den 
Code zeigt, weil das Array zu ende ist.

Ich werde jetzt noch weiter mit dem Debugger rumspielen, aber vielleicht 
sieht jemand den Fehler auf Anhieb?

update: Irgendwie werden die dezimalen Werte nur in einem Byte 
gespeichert. Der Assembler beachtet den High-Byte gar nicht. Das erklärt 
das Verhalten des uC. Ich benutze die kostenlose Version von RIDE 
6.10.15. Liegt es an dem Programm oder muss ich die Schreibweise 
irgendwie verändern, dass er z.B. die Zahl 513 automatisch in zwei Bytes 
ablegt?

von Maxim (maxim) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hier ein Screenshot vom Debugger.

von Peter D. (peda)


Lesenswert?

Für 16Bit mußt Du natürlich DW nehmen und nicht DB.

Und auch 2* MOVC um beide Bytes auszulesen (INC DPTR dazwischen).


Peter

von Peter D. (peda)


Lesenswert?

Also z.B. so hier:
1
  mov     dptr, #table
2
  mov     a, index
3
  add     a, acc
4
  jnc     _m1
5
  inc     dph        ;übertrag
6
_m1:
7
  mov     r7, a
8
  movc    a, @a+dptr
9
  inc     dptr
10
  xch     a, r7
11
  movc    a, @a+dptr
12
  ret                ;r7 = high, a = low byte
13
14
table:
15
       dw 1000
16
       dw 2000
17
usw.


Peter

von Maxim (maxim) Benutzerseite


Lesenswert?

JA, jetzt geht's. DANKE! :D

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.