Forum: Mikrocontroller und Digitale Elektronik Assembler-Programm


von Janis H. (janis06)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich bin gerade dabei eine Vakuumpumpe zu entwickeln und komm leider in 
meinem Programm nicht weiter..
Vielleicht könnt ihr mir ja weiterhelfen. Controller: AT89C51 Programm: 
Ride

Das Programm im Anhang soll wenn es fertig ist wie folgt funktionieren.
1. Keine Betätigung --> P2=00h
2. P1.1 wird ein mal betätigt --> P2=0F7h
3. Poti wird so gedreht, dass durch den Subtraktionsbefehl das Carry-Bit 
gesetzt wird --> P2=00h
4. Wird der Poti wieder zurückgedreht, sodass das Carry-Bit nicht mehr 
gesetzt ist --> P2=0F7h

Bis jetzt funktionieren die Punkte 1-3. Drehe ich das Poti und das 
Carry-Bit wird gesetzt, wird mir 00h an P2 angezeigt. Dreh ich jedoch 
wieder zurück bleibt 00h an P2 und es schalten nicht um auf 0F7h

Ich bin wirklich am verzweifeln, weil ich einfach nicht weiß, was falsch 
sein soll. Ist vielleicht etwas mit meinem push/pop Befehl falsch??
Wäre super wenn mir jemand helfen würde!

PS: Das Programm ist unten abgeschnitten. Steht aber nur noch die 
Warteschleife. Da bin ich mir sicher dass die richtig ist ;) Der Akku 
wird übrigens gezählt weil ich bei 01h im Akku die erste Leistungsstufe 
der Pumpe habe, bei 02h die zweite, 03h die dritte usw....Habe es 
versucht über Register zu machen, damit ich den Akku nicht 
retten/restaurieren muss für den "subb"-Befehl, funktioniert aber leider 
auch nicht. Er zählt zwar die Register hoch, aber Punkt 4 von oben (Wird 
der Poti wieder zurückgedreht, sodass das Carry-Bit nicht mehr gesetzt 
ist --> P2=0F7h) funktioniert immernoch nicht...


Grüße Janis06

von Michael K. (Gast)


Lesenswert?

Ich kann Dir mit Assembler zwar nicht helfen, aber einen Tip habe ich: 
Auf Quelltextschnipsel als Bild werden die wenigsten anspringen.

Besser ist es, wenn Du den Code in vollständiger und direkt verwendbarer 
Form als Text anhängst.

Mag sein, daß in diesem Fall ein Asm-Kenner drauf schaut und sagt, wo 
der Fehler liegt, aber für die Zukunft ist es besser, Code als Code zu 
liefern und nicht als Bild :)

Viel Erfolg,
42m

von Dietrich L. (dietrichl)


Lesenswert?

Was ich schon mal gefunden habe:

Beim Sprung bei <jc aus> gehst Du an <pop Acc> "vorbei", zumindest der 
Stack wird dann überlaufen.
Apropos: wo wird den Stack überhaupt initialisiert?

Gruß Dietrich

von Pieter (Gast)


Lesenswert?

moin,

das reinste Chaos...

-lade den Zahlenwert von Acc mal in R0, dann bleibt der so
-wo wird das Cy für SUBB gesetzt? Addiere 25 hat den selben Effekt wie 
SUBB 230 setzt aber kein CY vorraus.

>>Apropos: wo wird den Stack überhaupt initialisiert?

steht ohne Init auf Adr. 7.

MfG
Pieter

von Janis H. (janis06)


Lesenswert?

Erstmal danke an alle die sich die Mühe gemacht haben sich das ganze 
anzuschauen!

> -lade den Zahlenwert von Acc mal in R0, dann bleibt der so

R0 verwende ich schon in der Warteschleife. Habe es aber gestern schon 
mit R3 versucht, was leider nichts gebracht hat...


> -wo wird das Cy für SUBB gesetzt? Addiere 25 hat den selben Effekt wie
   SUBB 230 setzt aber kein CY vorraus.

Das wird gesetzt wenn die Differenz kleiner als 0 ist. Sprich wenn ich 
220 einlese und 230 abziehe habe ich theoretisch -10, wodurch das CY 
gesetzt wird.
Bin jetzt am überlegen wie ich es mit dem ADD Befehl machen könnte. Gibt 
es einen Befehl der abfrägt, ob z.B Acc kleiner oder größer als 350 ist?

von Pieter (Gast)


Lesenswert?

>> Sprich wenn ich
220 einlese und 230 abziehe habe ich theoretisch -10,

RTFM:  SUBB A,n ->  A = A-n-CY

Für A-n ist vorher CY auf 0 zu setzen. (CLR C)

Oder Du benutzt CJNE...
Oder diese Macro:
;--------------------------------------
;Compare And Jump Less
CJL    MACRO  Register, Value, Target
    CJNE  Register, Value, @@1
@@1:    JC  Target
    ENDM
;--------------------------------------


>>Acc kleiner oder größer als 350

das ist jetzt ULK.
Wertebereich Accu ist 0..255.

von Wilhelm F. (Gast)


Lesenswert?

Janis H. schrieb:

> Ist vielleicht etwas mit meinem push/pop Befehl falsch??

Könnte gut sein. Oben im ersten Block wird ja der Akku einmal gepusht, 
und bei Carry weg gesprungen, in diesem Fall nicht mehr zurück gepopt. 
Dort erhöht sich der Stack dann jeweils immer um 1, bis er irgendwann 
über läuft. Er läuft dann in die untere Registerbank hinein. Da im 
Programm Register verwendet werden, könnten diese bei Stacküberlauf 
verändert werden.

Vertausch doch einfach mal die beiden Befehle, setze "pop acc" vor "jc 
aus". Das Carry-Flag bleibt dadurch auch erhalten.

von Janis H. (janis06)


Lesenswert?

> Für A-n ist vorher CY auf 0 zu setzen. (CLR C)

Habe ich mittlerweile eingefügt. Bringt aber nichts...


>>>Acc kleiner oder größer als 350
>
> das ist jetzt ULK.
> Wertebereich Accu ist 0..255.

Hast natürlich recht ;) Frag mich auch gerade warum ich das geschrieben 
habe!?! Nehm einfach die 230 :)

So sieht mein Listing mittlerweile aus:

------------------------------------------------------

include reg51.inc

extern code Ain0
code at 0
             mov A,#00h

  loop1:    jb P1.1,hoch
            jb P1.0,runter
            cjne A,#01h,weiter1
            mov P2,#0F7h
            push Acc
            lcall Ain0
            subb A,#230d
            jc aus
            pop Acc
            mov P2,#0F7h
            ljmp loop1

 weiter1:   mov P2,#00h
            sjmp loop1

 hoch:      inc A
            lcall wait1
            ljmp loop1

runter:     dec A
            lcall wait1
            ljmp loop1

aus:        pop Acc
            clr c
            acall wait1
            mov P2,#00h
            sjmp loop1

wait1:      mov R2,#16
halt2:      mov R1,#250
halt1:      mov R0,#250
halt0:      djnz R0, halt0
            djnz R1, halt1
            djnz R2, halt2
            ret


             end

---------------------------------------------------


Leider geht der oben genannte Punkt 3 nun auch nicht mehr. Das muss an 
dem pop Acc Befehlt im UP "aus" liegen. Kann es sein dass ich nur einen 
pop Befehl benutzen darf. Habe das aus folgendem Grund gemacht: Wenn ich 
bei "jc aus" in das UP "aus" springe wird der Akku nicht mehr 
restauriert, was nicht sein darf, weil wir in der letzten Zeile von UP 
"aus" wieder in "loop1" springen und dann immernoch den Wert von der 
Subtraktion im Akku hätten

von Janis H. (janis06)


Lesenswert?

> Vertausch doch einfach mal die beiden Befehle, setze "pop acc" vor "jc
> aus". Das Carry-Flag bleibt dadurch auch erhalten.


Danke für die Idee, aber das Carry scheint nicht erhalten zu bleiben. 
Habe es versucht und jetzt springt er nicht mehr in UP "aus"

von Dietrich L. (dietrichl)


Lesenswert?

Janis H. schrieb:
> code at 0
>              mov A,#00h
>
>   loop1:    jb P1.1,hoch
>             jb P1.0,runter
>             cjne A,#01h,weiter1

Wenn Du den Zustand 2 erreicht hast (Acc=1), wird P2 hier doch wieder 
sofort auf #0F7h gesetzt:
>             mov P2,#0F7h
>             push Acc
>             lcall Ain0
>             subb A,#230d

Dann wird nach dem Vergleich zwar wieder nach "aus" gesprungen:
>             jc aus
>             ....
>
> aus:        pop Acc
>             clr c

Aber dann wird erst gewartet:
>             acall wait1
...bis P2 gelöscht wird:
>             mov P2,#00h
>             sjmp loop1

Und mit loop1 kommst Du gleich wieder nach oben, wo P2 wieder auf #0F7h 
gesetzt wird (s.o.).

Ich glaube, Du solltest Dir mal ein Flussdiagramm malen. Dann ist besser 
zu überblicken, was wann passiert und wo was getan werden muss.

Übrigens zum Thema push/pop: neben der Funktion, die bestimmt, welche 
Daten gerettet und wieder hergestellt werden müssen, müssen auf "push"s 
immer genau so viele "pop"s folgen, sonst verzählt sich der 
Stackpointer. Die Folgen sind dann beliebig unkalkulierbar.

Gruß Dietrich

von Dietrich L. (dietrichl)


Lesenswert?

Janis H. schrieb:
> aus:        pop Acc
>             clr c

Übrigens: Das "clr c" sollte besser direkt vor "subb A,#230d" stehen. 
Dann
1. weiß man, wozu das gehört und warum es gemacht wird
2. ist man sicher, dass "carry" ggf. nicht irgendwo anders wieder 
gesetzt wird, wenn man an dem Programm "rumbastelt".

Gruß Dietrich

von Tim S. (Firma: Germany) (timex09)


Lesenswert?

lade dir mal avr head 
http://www.avr-asm-tutorial.net/avr_de/avr_head/avr_head.html runter.

Damit kannst du schöne ASM Dateien erstellen. Du behälst den überblick 
und andere können dir dann auch helfen!

ps immer schön ;was mach ich schreiben

von Wilhelm F. (Gast)


Lesenswert?

Janis H. schrieb:

> Danke für die Idee, aber das Carry scheint nicht erhalten zu bleiben.

Das kann ich mir nicht vorstellen. Carry wird nur verändert, wenn ein 
Befehl es ändert, und ich sehe dort an der Stelle keinen.

Anstatt mit push und pop auf dem Stack kann man den Akku aber auch in 
einem nicht verwendeten Register sichern, z.B. R3 bis R7, oder z.B. im 
B-Register, wenn dieses anderweitig im Programm nicht verwendet wird, 
oder in einer Variablen, die man bspw. accsav nennen kann. Das würde die 
Stackgeschichte ja zunächst mal beseitigen.



Dietrich L. schrieb:

> Übrigens: Das "clr c" sollte besser direkt vor "subb A,#230d" stehen.

Auf jeden Fall wird das Carry mit vom Akku subtrahiert. Man subtrahiert 
dann je nach Carry mal 230, und mal 231. Denn subb heißt sub with 
borrow, und borrow ist das Carry.



Dietrich L. schrieb:

> Ich glaube, Du solltest Dir mal ein Flussdiagramm malen.

Das auf jeden Fall. Es erleichtert die Fehlersuche bereits vor der 
Codeerstellung, und hilft auch, das Programm gut zu strukturieren, damit 
es kein Spaghetti-Code wird.

von Janis H. (janis06)


Lesenswert?

Moin,
so habe jetzt mal den Akku in R3 abgelegt und siehe da, es tut sich was. 
Aber es ist sehr komisch. Wenn ich P1.1 betätige bekomme ich an P2 wie 
schon die ganze Zeit mein 0F7h. Jetzt drehe ich an meinem Poti und 
erwarte eigentlich die die 00h an P2. Die kommen aber nicht. Wenn an P2 
00h liegen müssten meine LEDs eigentlich alle leuchten, da ich das 
Signal über einen HEF40106 invertiere. Das komische ist, dass nur eine 
LED leuchtet und die andere glimmen ganz leicht. Drehe ich das Poti 
zurück gehe die LEDs wieder aus, wie es eigentlich sein soll. Also von 
der Funktion geht es jetzt, nur habe ich das Problem, dass 7 von 8 LEDs 
nur glimmen wenn ich das carry setze. Normalerweise wird man jetzt 
denken, dass es der HEF40106 nicht packt, aber wenn ich resete leuchten 
ja auch alle...

Flussdiagramm hab ich mir mittlerweile auch gezeichnet :)

von Dietrich L. (dietrichl)


Lesenswert?

Janis H. schrieb:
> Moin,
> so habe jetzt mal ...

Wie ist denn jetzt Dein Programm?

Hast Du den von mir oben beschriebenen Fehler auch korrigiert? :

Dietrich L. schrieb:
> ...
> Aber dann wird erst gewartet:
>>             acall wait1
> ...bis P2 gelöscht wird:
>>             mov P2,#00h
>>             sjmp loop1
>
> Und mit loop1 kommst Du gleich wieder nach oben, wo P2 wieder auf #0F7h
> gesetzt wird (s.o.).

Wenn das noch so ist, können die LEDs durchaus glimmen, denn sie werden 
eingeschaltet (#00h) und ganz kurz danach alle außer D3 wieder 
ausgeschaltet (#F7h).

Zeig mal dein aktuelles Programm + Flußdiagramm.

Gruß Dietrich

von Janis H. (janis06)


Lesenswert?

DANKE,DANKE,DANKE!!!! Das habe ich total übersehen...

Hier mein akutelles Listing. Funktioniert jetzt einwandfrei :)
1
include reg51.inc
2
3
extern code Ain0
4
code at 0
5
             mov A,#00h
6
7
  loop1:    jb P1.1,hoch
8
            jb P1.0,runter
9
            cjne A,#01h,weiter1
10
            mov R3,A      
11
            mov A,#00h
12
            lcall wait1    
13
            mov P2,#0FFh
14
            lcall Ain0
15
            clr c
16
            subb A,#230d
17
            jc aus
18
            mov P2,#0FFh
19
            mov A,R3      
20
            ljmp loop1
21
22
 weiter1:   mov P2,#00h
23
            sjmp loop1
24
25
 hoch:      inc A
26
            lcall wait1
27
            ljmp loop1
28
29
runter:     dec A
30
            lcall wait1
31
            ljmp loop1
32
33
aus:        mov P2,#00h
34
            mov A,R3
35
            sjmp loop1
36
37
wait1:      mov R2,#8
38
halt2:      mov R1,#250
39
halt1:      mov R0,#250
40
halt0:      djnz R0, halt0
41
            djnz R1, halt1
42
            djnz R2, halt2
43
            ret
44
45
46
             end


Man sieht jetzt nur noch den LEDs an, dass sie kurz weggeschalten 
werden, aber damit kann ich leben. Ich zeichne dir auch noch schnell das 
aktuelle Flussdiagramm.

von Janis H. (janis06)


Angehängte Dateien:

Lesenswert?

So hier das Flussdiagramm. Mit was für einem Programm zeichnet ihr das 
normalerweise? Hab das bisher nur in der Schule gemacht und da haben 
wirs immer von Hand gemacht. Hoffe man kann alles auf dem Bild erkennen 
;)

Vielen Dank nochmal an alle die mir geholfen haben!

von EFA (Gast)


Lesenswert?

Verwende C. Freie Compiler gibts dafür ja für MCS-51. 
Softwareentwiccklung in Assembler (bis auf wenige Ausnahmen abgesehen, 
an denen es sich nicht vermeiden lässt) ist nicht mehr state of the art.

von Janis H. (janis06)


Lesenswert?

Da gebe ich dir vollkommen recht, ich bin aber leider noch nicht groß 
dazugekommen mir C anzueignen....

von Michael K. (Gast)


Lesenswert?

EFA schrieb:
> Verwende C. Freie Compiler gibts dafür ja für MCS-51.
> Softwareentwiccklung in Assembler (bis auf wenige Ausnahmen abgesehen,
> an denen es sich nicht vermeiden lässt) ist nicht mehr state of the art.

Mit dem Argument hätte 
http://www.mikrocontroller.net/articles/AVR-Tutorial aber auch keine 
Berechtigung mehr.

Wenn jemand, warum auch immer, etwas in Assembler lösen möchte - und sei 
es nur, um zu lernen - warum nicht?

Außerdem war ja die Frage nicht: Wie mache ich es besser in einer 
anderen Sprache? :)

Klar sind relativ hardwarenahe "Hoch"sprachen wie C in vielen Fällen 
besser, aber wenn jemand unbedingt ASM verwenden will sollte man ihn 
lassen.

42m

von Manuel X. (vophatec)


Lesenswert?

EFA schrieb:
> Verwende C. Freie Compiler gibts dafür ja für MCS-51.
> Softwareentwiccklung in Assembler (bis auf wenige Ausnahmen abgesehen,
> an denen es sich nicht vermeiden lässt) ist nicht mehr state of the art.


C auf einem 8051 macht eines nicht und das ist Spaß.

Warum sollte man Assembler nicht lernen ? Hat durchaus seine Vorteile 
bei gewissen Dingen.

:)

von EFA (Gast)


Lesenswert?

Ich sage nicht dass man Assembler nicht lernen sollte - aber für größere 
Projekte macht es eben keinen Sinn diese komplett in Assembler zu 
entwickeln.

Man wird bei jedem Projekt einen kleinen Assembler-Anteil haben, 
mindestens für die crt0 und teileweise fürs Exceptionhandling.

von Thomas T. (knibbel)


Lesenswert?

Janis H. schrieb:
> Hier mein akutelles Listing. Funktioniert jetzt einwandfrei :)

>  hoch:      inc A
>             lcall wait1
>             ljmp loop1
>
> runter:     dec A
>             lcall wait1
>             ljmp loop1
>

Dir ist bewusst, dass der Akku auch "überlaufen" oder "unterlaufen" 
kann? Also Du erhöhst ihn ständig und plötzlich ist er bei FF und danach 
bei 00 und es geht von vorne los. Vielleicht solltest du bei "hoch" und 
"runter" noch etwas Bereichsprüfung machen. Sollte dann ein Maximalwert 
erreicht sein, dann wird das "inc A" einfach übersprungen. Selbiges für 
Null und "dec A"...

Gruß,
Thomas

von Thomas T. (knibbel)


Lesenswert?

Janis H. schrieb:
> So hier das Flussdiagramm. Mit was für einem Programm zeichnet ihr das
> normalerweise? Hab das bisher nur in der Schule gemacht und da haben
> wirs immer von Hand gemacht. Hoffe man kann alles auf dem Bild erkennen
> ;)

Mit diesem "Flussdiagramm" beschreibst du ja nur dein Programm. Du 
solltest es etwas "problemorientierter" gestalten:

Nicht "P1.1" oder "P1.0", sondern "Taster 'hoch' gedrückt" und "Taster 
'runter' gedrückt".

Nicht "ACC + 1" und "ACC - 1", sondern nenne die Zählvariable beim 
Namen, viellicht "Geschwindigkeit + 1" oder ähnlich. Also das, was du 
mit dieser Variablen erreichen willst. Wie und wo diese Variable im 
Programm kodiert wird, also im Akku, Speicher oder Register, wird erst 
viel später entschieden. Selbiges gilt für die Ports im Absatz 
darüber...

Mit einem Flussdiagramm sollte man ein Problem in unterschiedlichen 
Programmiersprachen kodieren können. Bei deinem Diagramm kann ich noch 
nicht mal das Problem erkennen...

Gruß,
Thomas

von Dietrich L. (dietrichl)


Lesenswert?

Thomas T. schrieb:
> Mit diesem "Flussdiagramm" beschreibst du ja nur dein Programm. Du
> solltest es etwas "problemorientierter" gestalten:

Du hast ja im Prinzip recht, das sollte man als erstes machen.
Aber Janis hatte Probleme mit der Umsetzung in Assembler. Da ist seine 
Darstellung nicht schlecht. Hätte er das gleich so gemacht, hätte er 
einige Fehler selber entdeckt.

Gruß Dietrich

von Karl H. (kbuchegg)


Lesenswert?

Janis H. schrieb:
> So hier das Flussdiagramm. Mit was für einem Programm zeichnet ihr das
> normalerweise? Hab das bisher nur in der Schule gemacht und da haben
> wirs immer von Hand gemacht.


Nur um da einzuhaken:

Das ist völlig ok.
Ganz im Gegenteil. Du bist mit der Hand und Papier und Bleistift (und 
Radiergummi) um Größenordnungen schneller unterwegs (und auch bei 
Änderungen schneller) als mit jedem Programm! Für die ersten Entwürfe 
kannst du dir diese Ganzen Boxen rund um die Blöcke oder auch Abfragen 
sparen, die kann man auch in der endgültigen Version machen.

Aber es ist meistens ein Trugschluss, wenn man für derartige Dinge ein 
spezielles Programm benutzt, dass man dann schneller wäre. Oft genug 
erlebt: Durch den Einsatz solcher Programme konzentriert man sich nicht 
mehr auf die eigentlich zu leistende Arbeit, sondern vertrödelt seine 
Zeit damit Fonts umzustellen, Dinge farbig zu machen, Blöcke hin und her 
zu schieben damit es schön aussieht, etc. etc. Ich möchte keinem zu Nahe 
treten, aber sieh dir doch mal viele der 'Arbeiten' von BWL-ern oder 
Managern an. Das wichtigste ist immer, das alles bunt ist und möglichst 
viele Fonts benutzt werden. Da gibt es wunderbare 
Powerpoint-Präsentationen, die graphisch wunderbar gestaltet sind - aber 
der Inhalt ist ... nur heiße Luft oder so wischi waschi, dass selbst ein 
Grundschüler erkennen kann, dass der Vortragende selbst keine Ahnung hat 
und eigentlich nur Zeit schinden muss. Da ist mir jede Handskizze 
lieber. Die mag zwar nicht so schön aussehen, aber die inneren Werte 
stimmen.

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.