www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Hilfe bei Assembler Program


Autor: Malte Struebert (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

erstmal kurz zur Vorgeschichte, ich baue gerade ein Anzeigeinstrument 
welches verschiedene Analogwerte einliest und diese dann auf 2 (1x3 7 
Segment und 1x2 7 Segement) anzeigen ausgiebt. Zudem soll über eine 
Status LED jeweils angezeigt werden welcher AD Kanal gerade auf dem 
jeweiligen Display dargestellt wird.

Es können so immer zwei werte Parallel angezeigt werden. Das wechseln 
der Kanäle soll über einen Taster erfolgen.

Ich hab jetzt gestern mal etwas rumexperimentiert und es funktioniert 
auch schon eingermassen. Es ist aber mein erstes ASM Programm mit dem 
AVR und mein erstes AVR Projekt überhaupt, deshalb glaube ich das ich 
sicher einiges noch eleganter lösen könnte.

Die Status LED habe ich mangels IO Ports über Logik Gatter kodiert. 
Wobei zwei IO Pins geschaltet werden, das dritte Bit wird vom aktuellen 
7 Segment Auswahlpin übernommen und durch ein 3fach NOR Gatter geleitet. 
Dadurch unterscheide ich zwischen der ersten und der zweiten Anzeige.

Den Code habe ich beigefügt, währe cool wenn sich das jemand mal ansehen 
könnte und verbesserungsvorschläge machen könnte. Besondere Probleme hab 
ich noch mit dem Taster und dessen Auswertung.

Gruß
Malte.

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ziemlich spaghetti, oder? :-)
Ein Programm schreibt man nicht direkt am Computer, sondern macht sich 
zumindest auf einem Blatt Papier einen groben PAP.
Das ergibt dann im Idealfall ein lineares Hauptprogramm in einer 
Endlosschleife, die nacheinander alle Unterfunktionen aufruft und sich 
dann ggf. eine Weile schlafen legt, um dann von vorn zu beginnen.
Also
1. Initialisierung des Controllers/Peripherie/RAM/SP
2. Main loop
   call Wandler lesen
   call Sensoren linearisieren
   call Umrechnen in Siebensegmentcode
   call Ausgabe
   wait
   goto main loop
Und wenn du es ganz schön machen willst, übergibst du alle Parameter an 
die Unterprogramme in einem Datenstack, ebenso die Rückgabewerte. Das 
ist erstmal mehr Aufwand, zwingt aber zu eiserner Disziplin und macht 
die Module weiterverwendbar. Im Lauf der Zeit sammelt sich eine schöne 
Anzahl von Routinen, die dann problemlos ohne Änderungen in anderen 
Projekten weiterverwendbar sind. Gute Vorplanung spart min. die Hälfte 
der Programmierzeit/Fehlersuche.
Trotzdem: Hut ab, wenn es dein erstes Projekt ist und es funktioniert.

Autor: Malte Struebert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

sorry das der Code so runtergeschrieben ist... mach ich normal nicht 
so... Programmiere normal in Hochsprachen und hab daher nicht so viel 
erfahrung mit Assembler code...

Kannst du nochmal genau beschreiben wie du die Parameterübergabe 
abhandlen würdest? Wenn ich das richtig verstanden habe meinst du ich 
soll alle benötigten Parameter vor dem Aufruf der Subfunktion in den 
Stack Pushen und durch die Funktion dann wieder rausholen (POP xyz) ?!? 
Bisher habe ich die parameterübergabe immer über vorher definierte 
Register bzw. speicherinhalte deren Adresse ich via Register übergeben 
habe gelöst. Aber die Stack Methode leuchtet ein das sie sinnvoller ist, 
weil universeller.

Nur noch mal zur sicherheit das ich das Prinzip richtig verstanden habe.

Eine Frage hab ich trotzdem noch, was mache ich mit der Funktion für den 
Schalter? Wie reagiere ich darauf, er soll ja nicht wenn ich ihn z.B. 2 
Sek. lang gedrückt halte, dauernd den Wert hochzählen, sondern nur 
einmal. Hat da vieleicht jemand ne Beispielfunktion o.ä.?

Gruß
Malte.

Autor: Frankl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ein Status Bit setzen (Boolean). Der Schalter verriegelt sich selbst. 
Erst nach dem Loslassen setzt er das ST Bit zurück.

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Also ich kann absolut nichts Spaghetti finden.

Der Programmierstil ist astrein, schön jede Funktion mit Header, so 
wünscht man sichs.

Aber wenn Du schon Hochsprachen programmiert hast, sollte man das ja 
auch erwarten können.

Die Parameterübergabe in Registern ist auch voll o.k., macht doch auch 
jeder C-Compiler so.

Unnütz zu Pushen kostet nur wertvollen Flash und der ist bei den kleinen 
AVRs (1...4kWorte) verdammt knapp.
Pushen muß man wirklich nur das, was man auch später noch benötigt.


Funktional habe ich mir den Kode noch nicht näher angesehen.
Trotzdem mal einige Ideen, wie ich sowas machen würde:

Die 5 7-S-Anzeigen würde ich im Multiplexbetrieb ansteuern (8+5=13 
Portpins, Schaltplan anbei).
Die Tasten würde ich entprellen.

Dazu nehme ich immer einen Timerinterrupt als zentrales Arbeitspferd für 
alles zeitabhängige.
D.h. der würde die Multiplexausgabe und das Entprellen übernehmen.
Zum Entprellen von bis zu 8 Tasten haben ich hier schon mal was 
geschrieben:

http://www.mikrocontroller.net/forum/read-1-18592.html

http://www.mikrocontroller.net/attachment.php/1878...


Eine Frage zu Deinem Interrupthandler. Kann es sein, daß du die noch 
anderweitig verwendeten Register sowie das SREG nicht sicherst ?

Ist aber unüblich, die komplette Mainloop unter Interruptsperre 
auszuführen. Da könnten leicht Interrupts verloren gehen.

Besser ist daher, die Interrupts so zu schreiben, daß das Main an 
beliebiger Stelle unterbrochen werden kann.


Peter

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
über den normalen Stack geht es glaube ich nicht, zumindest wird das 
sehr aufwändig, und mit Interrupts gibts auch Probleme.
Aber du hast ja 3 Indexregister, ich habe immer das y-Register benutzt.
Du definierst dir einen Datenstack, irgendwo in der Mitte des RAM, wo du 
den hinlegst, hängt von der RAM-Größe, Stackbedarf und Variablenmenge 
ab. Der "normale" Stack wächst vom RAM-Ende nach unten, die Variablen 
beginnen am RAM-Anfang. Mußt natürlich aufpassen, daß sich die Bereiche 
nicht überschreiben, dann gibts i.a. einen Absturz.
Nehmen wir mal einen 2313 als Beispiel: SP=0xDF, y=0x7F
Parameterübergabe:
st -y, r11
st -y, r10
Damit hast du 2 Byte im Stack abgelegt, können natürlich mehr sein.

Im UP verfährst du analog, ein direkter Zugriff auf das Parameterarray 
ist auch mit den den LDD-Befehlen möglich. Scheint alles erstmal 
verwirrend, wenn man es aber verstanden hat, geht es fast von allein.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@crazy horse,

der Aufrufer muß also "st -y, r11" machen und der Aufgerufene dann 
wieder "ld r11, y+" um damit arbeiten zu können.

Aber wozu soll das denn gut sein ?
Es kostet doch nur 2 unnütze Instruktionen für jedes Datenbyte.


Peter

Autor: thkaiser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich möchte die Sache mit dem Stack einsehen bei größeren Parametern 
(z.B. Strings), aber ich nutze die vom Atmel zur Verfügung gestellten 32 
Register weidlich aus. Bei Prozessoren wie 6502 o.ä. muß man mit den 
Registern geizen - aber warum sollte man das beim Atmel tun? Es kommt 
schlußendlich auch auf die Hardware an. Wenn ich einen MCS-51 mit 
externem RAM verwende, haue ich da auch alles rein, bevor ich ein 
Register verschwende.

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der Vorteil ist einfach erklärt: die Routine wird unabhängig vom 
jeweiligen Programm und kann ohne Änderungen und erneute 
Prüfung/Fehlersuche in anderen Programmen weiterverwendet werden und es 
gibt keinen Registerkuddelmuddel. Der Preis dafür ist einmal etwas mehr 
Arbeit und etwas längere Laufzeit. Ich habe nicht gesagt, daß man daß so 
machen muss - man kann.
Natürlich benutze ich auch direkte Registerübergaben, besonders bei 
kleinen, speziellen Programmen, die in einem Rutsch geschrieben werden.
Mein allgemeiner Ansatz:
R0 reserviert für LPM
R1 reserviert als sreg_bak
R2-R9 oft benutzte Variablen im Hauptprogramm
R9-R17 temporäre Register für Unterprogramme, können dort frei verwendet 
werden und brauchen nicht gesichert werden
R18-R25 wie R2-R9
R26-R31 reseviert
Das System halte ich ein und kann jederzeit ausgetestete Routinen 
einbinden, ohne mich um irgendeine Anpassung derselben kümmern zu 
müssen. Und die dann eingesparte Zeit und Fehlersuche ist es mir allemal 
wert, die paar Byte Code und ein paar Takte Laufzeit zu opfern. Wie 
gesagt, es muß keiner so machen, bei mir hat es sich bewährt.  Sicher 
ist es nichts für einen, der alle halbe Jahre mal einen MC programmiert

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.