Hi,
ich möchte eine Programm schreiben in dem ich 16 verschiedene
Unterprogramme gespeichert hab. Diese sollen in Abhänigkeit von einem
Wert im internen Speicher ausgewählt werden. Dieser Speicher wird dann
durch externe Interrupts inkrementiert oder dekrementiert. Und je nach
dem welchen Wert dieser Speicher hat, wird das dazugehörige
Unterprogramm aufgerufen.
Ich habe gehört da gibt es Tabellen oder Datenbanken dafür. Aber im
Forum bzw Google habe ich nichts brauchbares gefunden oder nicht
gesehen.
Kann mir jemand einen Tipp geben? Ich verlange keine Lösung ;)
Meine Utensilien:
- AT89C51
- Assembler, 8051
Vielen Dank
Zuwenig Infos... müssen die Unterprogramme ihre Daten behalten, oder
dürfen die Variablen durch die anderen UPs überschrieben werden?
Was sollen die UPs leisten können? Vielleicht gibts einen anderen Weg,
das gleiche zu erreichen als über mehrere "Programme". Ausserdem ist zu
beachten, dass ein 89x5_1_ nur 128Byte RAM hat, was der Sache etwas
entgegensteht...
Ralf
Hi Ralf, danke für deine Antwort!
es sollen 3 Register mit anderen Werten geladen werden. Diese Werte
stehen in den Unterprogrammen. Die darin stehenden Werte dürfen nicht
überschrieben werden. Ich kann auch mit 10 UPs oder weniger leben wenn
der Interne RAM nicht ausreicht. Daran hab ich garnicht gedacht. Danke.
Ich glaube der Ansatz ist nicht ganz richtig.
Noch eine andere Idee. Man könnte diese Werte irgendwo im Internen
Speicher ablegen und diese dann aufrufen.
> es sollen 3 Register mit anderen Werten geladen werden.
Okay.
> Diese Werte stehen in den Unterprogrammen. Die darin stehenden Werte> dürfen nicht überschrieben werden.
Dann stehen die Werte nicht in Unterprogrammen, sondern in
Wertetabellen!
Der externe Interrupt erhöht/dekrementiert eine Zählervariable, die die
Wertposition innerhalb der Tabelle angibt. Anhand der Position liest du
die entsprechenden Werte aus und schreibst sie in die Register.
Der Interrupt muss darauf achten, dass die Variable beim Inkrementieren
nicht größer als die Anzahl an Werten minus eins und beim Dekrementieren
von null automatisch gleich der Anzahl an Werten minus eins wird.
Ralf
Hi,
Die 3 Register müssen gleichzeitig mit neuen Werten beschrieben werden.
In der Wertetablle kann man, soweit ich weiss, nur 1 Wert Ablegen?
Ich hab mir das so gedacht.
mov R0 , 10h
mov R3 , 11h
mov R6 , 12h
10h-12h sind meine variablen Register die ich überschreiben möchte.
UT1:
mov 10h,#11h
mov 11h,#15h
mov 12h,#FFh
ret
Sobald das Unterprogramm UT1 aufgerufen wird, werden die 3 Register mit
den Werten geladen.
> In der Wertetablle kann man, soweit ich weiss, nur 1 Wert Ablegen?
An einer Adresse, ja -> logisch :)
An der nächsten Adresse, nächster Wert -> auch logisch
Und das erst gibt ja dann ne Tabelle...
Was das "3-Register/Werte-auf-einmal" betrifft, mach dir klar, dass du
doch einfach die Tabelle so sehen kannst, dass drei Werte einen
Datensatz bilden :)
Ralf
Du machst einfach in der Mainloop eine Statemachine und je nach Zustand
der Variable wird die entsprechende Funktion ausgeführt.
Mit externem Interrupt wirds knifflig (Prellen).
Deutlich besser und einfacher ist daher, mit Timerinterrupt entprellen
und dann die Variable bei Tastendruck hochzählen.
Die 16 Funktionen müssen natürlich mit der Mainloop zusammen compiliert
werden. Dein MC hat ja kein OS, welches DLLs nachladen kann.
Peter
Wie sieht denn sowas aus? Ich hab das noch nie gemacht und kanns mir
nicht vorstellen was du meinst.
Gibts da ein Beispiel oder ein Stichwort nach dem ich suchen kann?
Das mit der Entprellung ist kein Problem. Ich hab da schon etwas fertig
geschrieben.
Meinst du eine Abfrage? Würde das nicht zu lange dauern bis der richtige
Wert gefunden wurde?
> Meinst du eine Abfrage? Würde das nicht zu lange dauern bis der richtige> Wert gefunden wurde?
Wie könnte es sonst gehen? Die einzig andere Möglichkeit wäre gleich
eine Sprungtabelle, also eine Tabelle, in der die Adresse der Routinen
steht. In Abhängigkeit des Wertes wird die entsprechende Adresse geladen
und dann dorthin gesprungen.
Das kann sich schon mal lohnen, aber nicht in einem Projekt der
Größenordnung, wie du sie beschrieben hast :)
Du wirst da kaum einen Unterschied spüren.
Ralf
Wie Peter Dannegger geschrieben hat, fährst du mit einer Statusmaschine
am besten.
Ich habe dies mit einem AT89C51 kürzlich in etwa so programmiert. Ist
ziemlich einfach zu realisieren.
Wie Peter schon beschrieben hast brauchst du nur:
- Eine Statusmaschine mit einer Variable. Je nach dem was die Variable
für einen Wert hat, wird eine andere Funktion ausgeführt.
- Timerinterrupt in welchem du die Tasten einliest und entprellts. Je
nach dem was für eine Taste gedrückt wurde, wird die Variable von der
Statusmaschine dekrementiert oder inkrementiert.
gruss
quick and dirty...
als Unterprogramm aufrufen.
push acc
push dph
push dpl
mov dptr,#returnadresse
push dpl ; in den Kellerspeicher
push dph
mov a,programmauswahl
anl a,#00001111B
push b
mov b,a
add a,b ; * 2
add a,b ; * 3
pop b
mov dptr,#unterprogramme
jmp @a+dptr
unterprogramme:
jmp programm1
jmp programm2
; ... weitere unterprogramme
; ... mit RET beenden!
jmp programm16
returnaddresse:
pop dpl
pop dph
pop acc
ret
programm1:
ret
programm2:
ret
programm16:
ret