Forum: Mikrocontroller und Digitale Elektronik Menü für LCDs in Assembler


von Stefan F. (stefan1987)


Angehängte Dateien:

Lesenswert?

Hallo

Ich bin gerade dabei eine Menüstruktur für mein LCD zu entwerfen.
Auf dem Bild sieht man welche Bildschirminhalte auf dem LCD dargestellt 
werden sollen, welche Funktionen die Taster haben sollen und wo Leds und 
LCD angeschlossen sind.
Ausserdem sieht man welche Werte die Register 4 und 5 haben sollen bei 
welchem Menübildschirm.

Meine erste Idee war mit CPI die Tasterwerte zu Vergleichen und dadurch 
die Bildschirminhalte zu wechseln. Allerdings wird das sehr viel Code.

Dann hatte ich noch eine Idee über Sprungtabellen, weiss aber nicht ob 
es das besser macht.

Ich habe öfters was über Arrays hier im Forum gelesen wenn es um Menüs 
ging, konnte allerdings nichts dazu finden wie man solche Arrays in 
Assembler definiert und diese benutzt. Geht das mit Assembler ?

Oder welches wäre die effizienteste Lösung für solch ein Problem ?

Ausserdem gibt es ja in den LCD routinen den Befehl einen String 
auszugeben.
Also die Sache mit .db text1 "............" ,0

gibts da eine Möglichkeit an dieser Stelle wo diese Strings dann 
ausgegeben werden
,also da wo die einzelnen texte in den Z-Pointer geladen werden zum 
beispiel eine Variable einzusetzen das man nicht für jeden Displayinhalt 
ein neues Unterprogram schreiben muss so wie diesses hier ?


          ldi ZL, LOW(text8*2)        ; Adresse des Strings in den
          ldi ZH, HIGH(text8*2)       ; Z-Pointer laden
          rcall lcd_flash_string_o    ; Unterprog. gibt String aus der
                                      ; durch Z-Pointer adres. wird

          ldi ZL, LOW(text9*2)        ; Adresse des Strings in den
          ldi ZH, HIGH(text9*2)       ; Z-Pointer laden
          rcall line2                 ; Zeile 2 im LCD oben
          rcall lcd_flash_string_o    ; Unterprog. gibt String aus der
                                      ; durch Z-Pointer adres. wird

          ldi ZL, LOW(text10*2)       ; Adresse des Strings in den
          ldi ZH, HIGH(text10*2)      ; Z-Pointer laden
          rcall lcd_flash_string_u    ; Unterprog. gibt String aus der
                                      ; durch Z-Pointer adres. wird

          ldi ZL, LOW(text11*2)       ; Adresse des Strings in den
          ldi ZH, HIGH(text11*2)      ; Z-Pointer laden
          rcall line4                 ; Zeile 4 im LCD unten
          rcall lcd_flash_string_u    ; Unterprog. gibt String aus der
                                      ; durch Z-Pointer adres. wird

          ret                         ; zurück




Vielen Dank schonmal

Grüße Stefan

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Schreib Dir eine Ausgaberoutine, die indizierte Texte ausgeben kann, 
also Texte, die über eine Sprungtabelle adressiert werden. Ein Beispiel 
ist im Anhang.

Der Aufruf erfolgt so:

printmenu:              ;Einsprung
 printt menutab,mp          ;neuen Menütext ausgeben

Die Texte sehen so aus:

menutab:
.dw mt0,mt1,mt2,mt3,mt4,mt5,mt6,mt7

mt0:    .db 4,"1-Abkuehlen    ",0,0
mt1:    .db 4,"2-Platinen     ",0,0
mt2:    .db 4,"3-Normalpapier ",0,0
mt3:    .db 4,"4-Fotopapier   ",0,0
mt4:    .db 4,"5-extra dick   ",0,0
mt5:    .db 4,"6-Reserve      ",0,0
mt6:    .db 4,"7-Reserve      ",0,0
mt7:    .db 4,"8-Reserve      ",0,0

Nur um die "4" zu erklären: Die LCD-Routine arbeitet mit 
Bildschirmspeicher im AVR-SRAM und unterstützt einige Steuerzeichen:

;----------------------------------------------------------------------
;  lcd_data       ;Übergibt das Byte (ASCII-Zeichen) im Register "tmp"
                  ;zur Textausgabe. Dabei sind folgende Steuerzeichen
                  ;möglich:
                  ;1:  Blinken ausschalten
                  ;2:  akt. Ausgabe-Position als Blinkanfang setzen
                  ;3:  akt. Ausgabe-Position als Blinkende setzen
                  ;4:  Bildschirm löschen
                  ;8:  Cursor home (ohne Löschen)
                  ;13: CR, Zeilenwechsel, Rest der Zeile wird gelöscht
;----------------------------------------------------------------------


...

von spess53 (Gast)


Lesenswert?

Hi

Da hast du dir was nettes vorgenommen. Wie gut bist du in Assembler?

>Meine erste Idee war mit CPI die Tasterwerte zu Vergleichen und dadurch
>die Bildschirminhalte zu wechseln. Allerdings wird das sehr viel Code.
>Dann hatte ich noch eine Idee über Sprungtabellen, weiss aber nicht ob
>es das besser macht.

Da würde ich Sprungtabellen vor ziehen.

>Ich habe öfters was über Arrays hier im Forum gelesen wenn es um Menüs
>ging, konnte allerdings nichts dazu finden wie man solche Arrays in
>Assembler definiert und diese benutzt. Geht das mit Assembler ?

abcd: .db 1,2,3,4,5,6,7,8

ist in Assembler das gleiche, wie in C ein Array. Allerdings werden für 
Menüs eher Arrays aus zusammengesetzten Datentypen (C:Struct, 
Pascal:record) verwendet. Geht aber in Assembler auch:

abcd:  .db 'asdefrgthzju'    ; Menütext
       .dw Tasten1           ; Tastaturhandler
       .dw verarb1           ; Verarbeitungsroutine
       ....

Wenn die Menütexte eine konstante Länge habe kannst du Offsets 
definieren um auf die einzelnen Werte zuzugreifen:

   .equ Text = 0
   .equ tasten = 14
   ....

Zugriff mit z.B.

   ldi ZL,low(abcd<<1)
   ldi,ZH,High(abcd<<1)

   adiw ZH:ZL,tasten

   lpm rxy,Z+
   lpm ZH,Z
   mov ZL,rxy
   icall          ; zugehörige Tastaturroutine aufrufen

Ich habe das nur mal angerissen. Es gibt nichts, was 'höhere' 
Programmiersprachen können, was mit Assembler nicht realisierbar ist.

MfG Spess



   ZL,X+tasten
   ldd ZH,

von Stefan F. (stefan1987)


Lesenswert?

Hallo,

danke für die schnellen Antworten :)

@Hannes:

Also wenn ich das richtig verstehe fasst du die einzelnen Textzeilen mit 
.dw zu einem "Paket" zusammen ?
und in pr_txt.inc ist das printt macro für die ausgabe solcher "Pakete" 
auf das LCD zuständig ?
Was hat denn das @ im Quelltext zu bedeuten ?
" ldi tmp,low(@0*2)          ;Basisadresse"

Und das Unterprogramm lcd_printf1 ist der normale Ausgabebefehl für 
Strings auf dem LCD oder?

@spess53

> Wie gut bist du in Assembler?
Bin eher ein Assembler Anfänger. Arbeite das Tutorial hier durch.
Blinklichter, Lauflichter, Sprungtabelle, LCD Textausgabe, Tasterabruf 
usw versteh ich ganz gut. PWM vom Prinziep her auch.

> Wenn die Menütexte eine konstante Länge habe kannst du Offsets
> definieren um auf die einzelnen Werte zuzugreifen:
Ja die Texte hab ich alle gleichlang gemacht und in menues.asm 
definiert.
Ich kann sie auch einzeln ohne Probleme auf dem LCD ausgeben.
Bin grad auf der Suche nach einer Lösung wie ich indizierte Texte ausgeb 
so wie Hannes das oben beschrieben hat, bzw versuch es zu verstehn. :)


danke nochmal :)

von spess53 (Gast)


Lesenswert?

HI

>Was hat denn das @ im Quelltext zu bedeuten ?
>" ldi tmp,low(@0*2)          ;Basisadresse"

Der Quelltext gehört zu einem Macro.

Dem Makroaufruf:
1
  printt Adresse, Index

werden zwei Parameter übergeben: Adresse -> @0
und                              Index   -> @1

ldi tmp,low(@0*2) wird zu ldi tmp,low(Adresse*2) erweitert.

MfG Spess

von Sepp (Gast)


Lesenswert?

Vorsicht bei der Definition mit ".dw", wegen der Reihenfolge
der Ablage der Werte. Bei .dw kommt das niederwertige Byte zuerst!

Bei Texten nimmst Du .db  "Dies ist ein Text",0x00
Ggf.noch eine Null am Textende weil es immer eine gerade Anzahl an 
Zeichen
geben muß, der Assembler mault aber wenn es nicht paßt.

Dann kannst Du mit einer einfachen Ausgaberoutine den Text ausgeben,
Textende/ausgabeende ist die Null.

von spess53 (Gast)


Lesenswert?

Hi

>der Assembler mault aber wenn es nicht paßt.

Der mault nicht nur, sondern er tut auch etwas. Nämlich das fehlende 
Byte zu ergänzen.

MfG Spess

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Stefan Friedrich schrieb:
> Hallo,
>
> danke für die schnellen Antworten :)
>
> @Hannes:
>
> Also wenn ich das richtig verstehe fasst du die einzelnen Textzeilen mit
> .dw zu einem "Paket" zusammen ?

Paket würde ich das nicht nennen, es sind einfach nur die Adressen, an 
denen die Texte beginnen. Natürlich nicht im Klartext (als Zahlenwert), 
sondern als Label. Somit kann der Assembler beim Assemblieren anstelle 
der Labels die Adressen einsetzen.

> und in pr_txt.inc ist das printt macro für die ausgabe solcher "Pakete"
> auf das LCD zuständig ?

Das Macro ist dafür zuständig, eine Routine aufzurufen, die den 
Z-Pointer auf die Adresse (mal 2, wegen LPM) des Textes positioniert und 
dann die Routine aufruft, die den Text an das LCD ausgibt.

> Was hat denn das @ im Quelltext zu bedeuten ?
> " ldi tmp,low(@0*2)          ;Basisadresse"

Damit werden die Parameter des Macros markiert. @0 ist der erste 
Parameter, @1 der zweite, aber das hat Spess ja schon erklärt.

>
> Und das Unterprogramm lcd_printf1 ist der normale Ausgabebefehl für
> Strings auf dem LCD oder?

Jaein...
lcd_printf (Print aus Flash) ist die normale Ausgaberoutine für Strings, 
die mit $0 beendet werden. Sie wird vom Macro printf aufgerufen.
Im Fall von indizierten Texten positioniert aber die Routine lcd_printt 
bereits den Z-Pointer, daher wird lcd_printf hinter der 
Pointer-Positionierung angesprungen, also bei lcd_printf1.

Da vor ".dw" gewarnt wurde:
Texte notiert man mit ".db", denn es handelt sich um Datenbytes. Die 
Adressen der Labels sind aber 16-Bit-Worte. Um sie korrekt als 
16-Bit-Zahl notieren zu können, müssen jeweils 2 Bytes (ein Word) dafür 
im Flash reserviert werden. Und genau dies macht ".dw". Siehe dazu auch 
den Hilfetext zu den Direktiven im AVR-Studio.

Um Dir das Analysieren der Routinen zu erleichtern, hänge ich mal das 
gesamte Programm an.

...

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.