Forum: Mikrocontroller und Digitale Elektronik Probleme mit "call"-Befehl in Assembler


von Tobias Gläser (Gast)


Lesenswert?

Hi.

Ich Programmiere grad was größeres in Assembler.
Plötzlich habe ich nun ein Problem mit einem Call / Ret Befehl!

Nach dem Befehl jnb P1.1,prog2 springt er ja unten zu "prog2" (Wenn
das Bit auf 0 ist). "prog2: call pro2" Dieser Befehl springt ja dann
zu meinem Programm. Am Ende dieses Programmes habe ich "ret" stehen.

Problem dabei: Er springt nach dem ret nicht in die Zeile des
Call-Befehles zurück sondern Ôô springt zu meiner Startsprungmarke!

Ich benutze Keil µV3 und den Controller Infineon 80c535 N

Das seltsame ist, dass bei jedem call- und ret-Befehl alles gut
funktioniert. Es werden manche Unterprogramme noch min20 mal aufgerufen
und es geht immer. nur hier nun nicht. was könnte das für Ursachen
haben?
1
Start:      ; Startsprungmarke, Anfang des Programmes
2
  jnb P1.1,prog2  ; Springt wenn P1.1 auf 0 gesetzt zu prog2
3
  call pro1  ; Aufruf von Programm 1
4
  jmp Start  ; Sprung zurück zum Programmstart
5
star1:  jnb P1.2,prog3  ; Springt wenn P1.2 auf 0 gesetzt zu prog3
6
  jnb P1.3,prog4  ; Springt wenn P1.3 auf 0 gesetzt zu prog4
7
  jnb P1.4,prog5  ; Springt wenn P1.4 auf 0 gesetzt zu prog5
8
  jnb P1.5,prog6  ; Springt wenn P1.5 auf 0 gesetzt zu prog6
9
  jnb P1.6,prog7  ; Springt wenn P1.6 auf 0 gesetzt zu prog7
10
  jnb P1.7,prog8  ; Springt wenn P1.7 auf 0 gesetzt zu prog8
11
  call pro1  ; Aufruf von Programm 1
12
  jmp star1  ; Sprung zurück zum Programmstart 1
13
14
prog2:  call pro2  ; Aufruf von Programm 2
15
  jmp star1  ; Sprung zurück zum Programmstart 1
16
prog3:  call pro3  ; Aufruf von Programm 3
17
  jmp star1  ; Sprung zurück zum Programmstart 1
18
prog4:  call pro4  ; Aufruf von Programm 4
19
  jmp star1  ; Sprung zurück zum Programmstart 1
20
prog5:  call pro5  ; Aufruf von Programm 5
21
  jmp star1  ; Sprung zurück zum Programmstart 1
22
prog6:  call pro6  ; Aufruf von Programm 6
23
  jmp star1  ; Sprung zurück zum Programmstart 1
24
prog7:  call pro7  ; Aufruf von Programm 7
25
  jmp star1  ; Sprung zurück zum Programmstart 1
26
prog8:  call pro8  ; Aufruf von Programm 8
27
  jmp star1  ; Sprung zurück zum Programmstart 1

von Tobias Gläser (Gast)


Lesenswert?

Oje Kann es auch daher kommen, dass ich ion den Jeweilig aufgerufenen
programmen den Call verschachtelt habe, also ein weiteres Unterprogramm
(z.B. ne Zeitschleife) aufrufe?

Das ist der Fall. Aber dann wird das Problem in allen Programmteilen
auftreten. bis jetzt kommts ja nicht weiter wie Prog 1 und 2.
Mein Prob dann is nur, wie komme ich zu meinen Programmen, wenn ein
einfacher jmp Befehl von der entfernung (Prog hat knapp 900 Zeilen)
nicht geht und ein Call-Befehl nicht verschachtelt werden kann?

MfG T-G-läser

von Tobias Gläser (Gast)


Lesenswert?

was sind ljmp, sjmp, ajmp ???

von peter dannegger (Gast)


Lesenswert?

Calls können sehr wohl verschachtelt sein, es muß nur zu jedem CALL ein
RET gehören.

Du wirst also irgendwo ein RET zuviel haben und das lädt dann den
Inhalt von R6,R7 in den PC (wenn SP auf 007h steht).


@Tobias,

das sind JMP-Befehle, je nach Sprungdistanz.


Peter

von Wolfram (Gast)


Lesenswert?

wo ist eigentlich deine Stackinitialisierung?

von Tobias Gläser (Gast)


Lesenswert?

Stackinitialisierung? wofür benötige ich diese? Und wie mache ich diese
mit reinem Assembler?

Ich habe nun das Programm bisschen abgeändert, da ich kein weiteres ret
gefunden habe (thx Peter).

Start:   jnb P1.1,prog2
         call loop
         mov P4,#01010101b
         mov P5,#01010101b
         call loop
         mov P4,#10101010b
         mov P5,#10101010b
         jmp Start
star1:   jnb P1.2,prog3
         jnb P1.3,prog4
         jnb P1.4,prog5
         jnb P1.5,prog6
         jnb P1.6,prog7
         jnb P1.7,prog8
         ljmp pro1
prog2:   ljmp pro2
prog3:   ljmp pro3
prog4:   ljmp pro4
prog5:   ljmp pro5
prog6:   ljmp pro6
prog7:   ljmp pro7
prog8:   ljmp pro8

Die Rücksprünge der Programme 1,3-8 erfolgen über "ljmp star1"
Der Rücksprung des Programmes 2 erfolgt über "ljmp Start"

Das funktioniert nun alles wie erwünscht =)

von Baitronic (Gast)


Lesenswert?

Autsch.

Das Thema solltest du dir zu Gemüte führen. Die Stackinitialisierung
legt fest wo im SRAM dein Stack liegt. Im Klartext: initialieren den
Stackpointer.

Steht auch hier:

http://www.mikrocontroller.net/articles/AVR_Checkliste

Gruß Andreas

von Tobias Gläser (Gast)


Lesenswert?

Ich glaube nun dass ich meine call und ret nicht richtig verschachteln
konnte, weil ich übergreifend in den Programmen den Stackpointer
benutzt habe.
Ich wusste nicht dass call ebenfalls die adr im Stack speichert. Habe
ich mir keine Gedanken darüber gemacht

MfG T-G-läser

von Stephan H. (stephan-)


Lesenswert?

@Baitronic,
schaut auch er über seinen Tellerrand, sieht er in der Überschrift
>>>>>  AVR Checkliste <<<<<

Wir reden hier von einem 8051 ér !!!
Der hat nach einschalten bereits 07h im SP !!!
Ohne Interrupts reicht das völlig !!!!!


............oh du schöner 51er !!!!

von Tobias Gläser (Gast)


Lesenswert?

Danke @ Wolfram und Baitronic

Jedoch ist mein internes RAM randvoll und ich hab ja nen ganz anderen
Controller-Typ.

kann ich auch eine Adresse im externen RAM bei ca. 4100h wählen? wenn
ja wie?

von Stephan H. (stephan-)


Lesenswert?

mit MOVx   zB. !! indirekt adressierter RAM  !!

von Tobias Gläser (Gast)


Lesenswert?

Hmmmm Macht Sinn @ Stephan.

Was hat es jedoch mit den genannten 07h auf sich?

Mein internes RAM is nun im mom von 0h bis 87h komplett belegt, jedoch
brauch ich davon sogar noch etwas mehr... Wied einer dieser Bereiche
etwa schon von einem anderem Teil des µ-Controllers verwendet oder habe
ich den Platz sicher frei?

Ich habe eben bisher nur in einer Simulation gearbeitet, da die
Zusatzplatinen meines µ-Controller-Boards noch nicht fertig sind.

von Pieter (Gast)


Lesenswert?

moin moin,

Tobias, Du solltest Dich unbedingt mit den Grundlagen des 8051
befassen. Direkte Probleme und Fragen zum nachlesen hast Du ja jede
Menge.
In Deinem Prog ist ein Call loop drin, das überschreibt den Inhalt von
RAM 8+9.
Wenn Du in die Doku zum 8051 siehst, den Stack kannst Du z.B. mit
mov sp,#160 weit nach hinten legen. In Deinem Prog kannst nun rumkallen
ohne unerklärliche Sachen zu bekommen.
Der 80C535 hat ein externes EPROM, da kann leich ein RAM mit
angefrickelt werden. Wie? Steht auch in der Doku.
Oder nimmst gleich einen mit interen FlashROM und XRAM z.B. 89C5152ED2,
89C5131A, 89C51RC2.

Na ja, vor 20 Jahren habe ich auch solche Fragen gestellt. Nur damals
gabs noch kein Internet. Da blieb nur der Gang in die nächste Bibliotek
und ein passendes Buch ausleihen....


Mit Gruß
Pieter

von Stephan H. (stephan-)


Lesenswert?

Ups !!!!
ab 80h fangen doch die SFR an !!!! Ab da gehts nur mit MOVx !!!
Nich das da noch was passiert !!

Was den SP angeht.... Wie gesagt der steht nach dem internen Reset den
die MCU macht immer auf 07H. Ab dort wird im RAM zB. das PSW bei einem
CALL abgelegt und nach RET wieder geholt. Aber auf zB 0Bh leigt der
Einsprung für Timer 0 Int. Daher legt man den SP so ab 20h aufwärts
sofern man mit ISR ( Interrupt Service Routine ) arbeitet.
Was machst du denn mit dem RAM ???
Ich glaube du hast na nen Denkfehler!
externes RAM.:

zB. MOV   DPTR,#4100h
    MOVX  A,@DPTR

alles klar ???

von Stephan H. (stephan-)


Lesenswert?

Oh hallo Pieter

sei gegrüßt. Meine ISR funzzt prima. !!

So denn

von peter dannegger (Gast)


Lesenswert?

"weil ich übergreifend in den Programmen den Stackpointer benutzt
habe."


Dafür gibts knallhart die rote Karte !

Als Anfänger darf man den Stackpointer nur ein einziges mal anfassen
und zwar bei der Initialisierung, danach gehört er ganz und gar der CPU
bis zum Abschalten !

Sinnvoll ist es bei 8052-ern den SP in den indirekten SRAM (080h..0FFh)
zu legen, minimal 16 Byte groß, also nicht über 0EFh.

Zum indirekten Zugriff auf Daten hat man schließlich seine 8
Pointerregister (R0,R1 in Bank 0..3).

Nachm Reset ist SP = 07h, d.h. ab 10h wird gepusht, solange man SP
nicht anders initialisiert.


Peter

von Stephan H. (stephan-)


Lesenswert?

@Peter,
Du bist ja grausam als Lehrer !!!! :-))

Aber vielleicht besser so als wenn sich gleich am Anfang Unarten
einschleichen. Wobei ich nicht in die oberen 128 gehen würde.
Wenn er mal nen anderen 8051 nimmt...... und nicht dran denkt...

von Pieter (Gast)


Lesenswert?

moin moin,

@Stephan
Du bist ja grausam als Lehrer !!!! :-))
... und aus "meinen" Azubis ist immer was geworden...
Mein USB-89C5131 läuft soweit auch schon.

Nachtrag zum RAM (und wieder mal ein Blick in die Doku...;-)

00..7F RAM direkt
80..FF SFR direkt UND 80..FF RAM indirekt mit @Rn

00..FFFF RAM extern mit movx
es gibt z.B. die RAM Zelle 80H gleich 3 mal unter der selben Adresse.
===========
StackPointer:
So wie der andere Peter sagt: EINMAL einstellen und vergessen.

>>Nachm Reset ist SP = 07h, d.h. ab 10h wird gepusht
Einspruch Euer Ehren, der 1. Push geht auf die 8.

Mit Gruß
Pieter

von Tobias Gläser (Gast)


Lesenswert?

uiuiuiuiuiui!!!!

Also erstma thx....!

Dad gibt nu riesen Arbeit glaub ich.

Es werden nämlich unmengen von Daten, die ich über einen AD-Wandler
einlese (Abstandssensor unlinear für ein Projekt) im Internen RAM
gespeichert. Ich benutze ein Board wo ein externes RAM dabei ist. da
habe ich sogar etwa 200h frei (4000h-41FFh).

Jedoch habe ich nun wohl noch ne ewigkeit zu tun, diese gesamten
Befehle im gesamten Prog (mittlerweile über 900 Zeilen) zu ersetzen
fg
    MOV   DPTR,#4000h ; Is ja nun frei bis 41FFh
    MOVX  A,@DPTR     ; Ram in Akku laden

und andersrum

    MOV   DPTR,#4000h ; Is ja nun frei bis 41FFh
    MOVX  @DPTR,A     ; Akku in Ram laden

oda wie? (und das sind jeweils auch 8 Bit?^^)

MfG T-G-läser

von Stephan H. (stephan-)


Lesenswert?

Hallo Pieter

Du hast doch gar keine rote gegeben !!!!

Hast Du nen Moment ??? Im progr. Logik Abteil ist jemand mit C code der
compiliert werden muß. Kannst Du ihm helfen ???
Habe keinen Compiler !!!

An meinem ED2 ist jetzt nen LTC1093 dran. Interesse ??
machs gut

von Pieter (Gast)


Lesenswert?

High Stephan

och nee, keine Rote Karte, Tobias soll ja am Ball bleiben und nicht
duschen gehen...
- LTC1093 macht "nur" 10Bit.
- 89C51ED gibs bei Angelika wieder als DIL40.

Derzeit einen Testaufbau:
1.Transverter 5/12 + Optokoppler für seriell
2.89C2051 zur Umsetzung
3. MAX186/LTC1446 auf einem DIL24 Modul
Das ganze Modul liefert potentialgetrennte 12Bit AD/DA mit -1/+5/+11V.

@Tobias

Tip:Zeilen ersetzen mit Copy&Paste
Unmengen an Daten und 512Byte RAM?
Bei einem Temperaturlogger (89C2051+DS18S20) habe ich die Daten (pro
Minute 2Byte) in ein 24C512 (64Kx8Bit) geschrieben. Reicht ein paar
Tage.

Mit Gruß
Pieter

von Tobias Gläser (Gast)


Lesenswert?

Morgen!

@ Pieter

Ich hab zwar net wiel Speicher (Nun schon mehr), aber es wird ja
dauerhaft gemessen, dann alle gespeichert und wo anders ausgegeben, in
der zeit wo das Alte schon wieder überschrieben wird. Also es ist nicht
so, dass ewig alles drin bleibt. 17Byte alleine sind es nur, die immer
bleiben. genau genommen 17Byte und ein nippel.

Thx für die Hilfe gestern!

MfG T-G-läser

von Tobias Gläser (Gast)


Lesenswert?

Noch etwas... Habe ja noch das Problem dass ich die Werte anders
auslese.hier ein kleines Beispiel
SPEICHERUNG
        mov P4,#00000000b
        mov P5,#01000000b
        call pause
        call ADmess
        mov 38h,a
VERARBEITUNG
m130:   call ADmess
        cjne a,38h,m112
m112:   jc m131
        mov P4,#00000000b
        mov P5,#01000000b
        jnc m122
MESSUNG
ADmess: clr mx0
        clr mx1
        clr mx2
        clr adm
        jb bsy,$
        mov DAPR,#0
        mov a,addat
        ret

geht das auch alles mit einem Register also so(??):
(.....)
        mov P4,#00000000b
        mov P5,#01000000b
        call pause
        call ADmess
        mov a,R1
        mov DPTR,#4000h
        movx @DPTR,a
(.....)
m130:   call ADmess
        mov DPTR,#4000h
        movx a,@DPTR
        cjne R1,a,m112 ;(geht glaub net... aber ka wie sonst. Ideen?)
m112:   jc m131
        mov P4,#00000000b
        mov P5,#01000000b
        jnc m122
(.....)
ADmess: clr mx0
        clr mx1
        clr mx2
        clr adm
        jb bsy,$
        mov DAPR,#0
        mov R1,addat
        ret
(.....)

Habts andere Ideen, Wie ich des machen kann? Werden halt nacheinander
viele gespeichert. in einem anderem prog diese dann verarbeitet....
also es muss vom Prinzip so bleiben, wie es nun ist.

MfG T-G-läser

von Tobias Gläser (Gast)


Lesenswert?

Sry für den dreifachpost...

Letzter Problembefehl:
        cjne a,20h,m112

Abänderung mit 2 Variablen (ERROR - nicht möglich):
        cjne R1,a,m112

Abänderung mit anderem Wert direkt (WARNIMG - unbekannt):
        cjne a,2020h,m112

Wie kann ich noch 2 Werte Vergleichen, Carry setzen oder löschen je
nachdem ob der Speicher größer/kleiner ist wie der Akku/Register
Habts ne Möglichkeit mit wenig Befehlen, so dass diese Funktion "cjne
a,2020h,m112" erfüllt wird?

von Stephan H. (stephan-)


Lesenswert?

@Tobias
      ( MOV R1,womit auch immer )
        mov P4,#00000000b
        mov P5,#01000000b
        call pause
        call ADmess
        mov a,R1
        mov DPTR,#4000h
        movx @DPTR,a

wenn R1 vorher den richtigen Wert hat sicher warum nicht.
CJNE @R1( oder R0 ), #data,reladdr ist auch richtig.
Allerdings scheint Deiner nicht zu verzweigen.


m130:   call ADmess
        mov DPTR,#4000h
        movx a,@DPTR
        cjne R1,a,m112 ;(geht glaub net... aber ka wie sonst. Ideen?)

Woher kommt R1 ?????? LADEN oder übergeben nicht vergessen !!!
Macht sich blöd wenn man nur Stücken hat.
Aber ich denke R1 hast Du schon an diesem Punkt.


CJNE  Compare Jump not Qual

Also ist Ergebnis gleich mache nächste Zeile Weiter.
Ist Ergebnis nicht gleich, springe zu XY
Dort kann man jetzt nach C fragen. Und somit Größer bzw. Kleiner
unterscheiden. zB. mit Jb C, XY
Du verzewigst nur nach m131 wenn R1 kleiner Akku .Wenns so sein soll.
o.k.

Sieht glaube ich gut aus auf die Schnelle.
Bin auf Arbeit.

von Stephan H. (stephan-)


Lesenswert?

das geht alles mit CJNE

Nur Akku läßt ein Vergleich mit "Zahlen" zu.
Vergleiche bei Registern wie R0 und R1 immer mit Akku.
Falls 2020h eine Speicherstelle ist, dann erst mit Movx a,@dptr
in den Akku rein.
Falls es ein Wert ist....... Sorry. 8 Nur Bit soweit ich weis.

Ne CJNE ist schon genial.

http://www.8052.com/51cjne.phtml

von Tobias Gläser (Gast)


Lesenswert?

Woher kommt R1 ?????? LADEN oder übergeben nicht vergessen !!!

In Beiden Fällen gilt doch noch das Unterprogramm. Sowohl oben beim
Speichern, sowie unten bei der Ausgabe. Es ist ja immer ein "call
ADmess" vorhanden.

ADmess: clr mx0
        clr mx1
        clr mx2
        clr adm
        jb bsy,$
        mov DAPR,#0
        mov R1,addat
        ret

Daher mein R1 -> Also meine AD-Messung wird jedesmal neu im R1
zwischengespeichert.

Der Cjne geht leider nicht mit 2 Variablen. Aber habe eine neue Idee.

so âla:

(.....)
        mov P4,#00000000b
        mov P5,#01000000b
        call pause
        call ADmess
        mov a,R1         ;Messwert zum Speichern
        mov DPTR,#4000h  ;Adresse
        movx @DPTR,a     ;Akku in ext. RAM ablegen
(.....)
m130:   call ADmess      ;Messung in R1 speichern
        mov DPTR,#4000h  ;Adresse
        movx a,@DPTR     ;Alter Wert in Akku
        mov 0h,a         ;Akku auf 0h(oder was halt sicher frei ist)
        mov a,R1         ;Messwert in Akku
        cjne a,0h,m112   ;Alt+Neu vergleichen
m112:   jc m131
        mov P4,#00000000b
        mov P5,#01000000b
        jnc m122
(.....)
ADmess: clr mx0
        clr mx1
        clr mx2
        clr adm
        jb bsy,$
        mov DAPR,#0
        mov R1,addat
        ret
(.....)

Macht doch Sinn, oda nit?
Kann es leider nur hier im Geschäft nun net testen, aber so kann ich es
in Jeder Zeile dann leicht anwenden, Wobei das massig an zusätzlichen
Zeilen gibt.... Dazu kommt meine Begrenzung des Speichers die ich schon
fast erreicht hatte!!!

Nuja mal sehn evt kann man Teile gekürzt in ein unterprogramm
schmeißen.

Danke MfG T-G-läser

von Tobias Gläser (Gast)


Lesenswert?

Ich kann nun Leider nicht mehr Weiterprogrammieren hier, da ich in eine
andere Abteilung versetzt werde (Schaltschrankbau).

Von daher kann ich nur wieder nach Feierabend da sein um an den Problem
weiter zu machen.

Wenn jmd Interesse hat kann ich die Dateien ja auch irgendwo auf meinem
Server zur Verfügung stellen.

Allgemein Kann ich anbieten für Leute hier Dateien auf meinem Server
auf ewig anzubieten (gratis und ohne Werbung), wenn mir jmd ne kleine
Downloadseite machen kann. Ansonsten nur mit direkten links auf die
jeweiligen Dateien.

Bitte bei mir melden E-Mail oben, ansonsten auch ICQ: 236-690-456

Dankeschön und bis dann

MfG T-G-läser
www.tobias-glaeser.de
www.tobias-glaeser.de/Startseite/Index.html

von Tobias Gläser (Gast)


Lesenswert?

Öhm @ Stephan, Welches Byte im Internen RAM darf ich denn ohne Angst
benutzen? brauche halt 8Bit. Is genug

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.