Hallo,
ich programmiere schon länger an einem kleinen AVR-Projekt mit LCD- und
UART-Ausgaben (in Assembler, Mega16) und mit der Zeit sammlen sich auch
etliche Text-Strings für LCD-Ausaben bzw. Debug-Informationen via UART
an.
Momentan rufe ich jede einzelnen String mit einer Unterroutine aus dem
Hauptprogramm auf, wie zum Beispiel "rcall LCD_Select"
Die Unterroutine sieht dann wie folgt aus:
LCD_Select:
ldi ZL, LOW(text_Select*2) ; Adresse des Strings in den
ldi ZH, HIGH(text_Select*2) ; Z-Pointer laden
rcall lcd_flash_string
ret
text_Select: .db "-> Please Select ",0
Die Funktion "lcd_flash_string" stammt hier aus dem Tutorial und schiebt
den String einfach auf das LCD (siehe unten).
Das funktioniert so auch wunderbar, nur werden die Anzahl der
Textstrings im Laufe der Zeit immer mehr und das Programm wird so leider
unübersichtlich und kostet auch recht viel Speicherplatz. Ich habe dann
also für jeden Text einen seperaten Aufruf zum Setzen des Z-Pointers.
Mich würde es interessieren wie ihr solche Strings verwaltet, gibt es
spezielle Tricks? Vielleicht kann ich da noch was optimieren.
Es handelt sich hier nur um statischen Text, alle Variablen werden nur
bei Bedarf vom Programm einzeln ausgegeben.
Hier noch die "lcd_flash_string"-Routine:
lcd_flash_string:
push temp1
push ZH
push ZL
lcd_flash_string_1:
lpm temp1, Z+
cpi temp1, 0
breq lcd_flash_string_2
rcall lcd_data
rjmp lcd_flash_string_1
lcd_flash_string_2:
pop ZL
pop ZH
pop temp1
ret
Gruß Daniel
txt_out0:
;falls LCD muss hier die Adresse hin
ldi ZH,high(out0*2)
ldi ZL,low(out0*2)
rcall txt_out
ret
;Hier nur die Zeichenausgabe mit der Stoppbedingung
txt_out:
lpm temp1,z+ ;!!! muss der .db *2 genommen werden
cpi temp1,$ff
breq txt_out_end
rcall lcd_data ;z.b.: ldi ZH,high(out0*2)
rjmp txt_out
txt_out_end:
ret
;hier so wie du es auch hast über ne DB mit stoppbedingung
out0: .db " AVR-Atmega8 ",$ff
Okay, danke für die vielen Antworten.
Werde mir die Macro-Prorammierung mal näher anschauuen, damit habe ich
bis jetzt noch überhaupt keine Erfahrung.
Mich würde auch interessieren, ob ihr bei euren Projekte mit LCD-Ausgabe
auch so viele Text-Strings habt? Bis wieviel Zeichen schickt ihr die
Zeichen einzeln (nacheinander) zum LCD bzw. ab wieviel Zeichen verwendet
ihr einen kompletten String aus dem Flash? Habe momentan ca.
30verschiedene, konstante Textausgaben, die ich je nach Ereignis auf ein
2zeiliges Display ausgebe.Ich suche immernoch einen für mmich optimalen
Programmierstil, deswegen die Frage. Das ist zwar nur eine
Hobby-Basteiel aber man will sich ja auch verbessern :-)
Daniel schrieb:> ob ihr bei euren Projekte mit LCD-Ausgabe> auch so viele Text-Strings habt?
ja, datei is net vollständig was die prgrammierung des lcds angeht aber
so zu deiner frage
Daniel schrieb:> Bis wieviel Zeichen schickt ihr die> Zeichen einzeln (nacheinander) zum LCD bzw. ab wieviel Zeichen verwendet> ihr einen kompletten String aus dem Flash?
Ab 3 Zeichen hole ich es aus dem Flash, die Überlegung war wenn ich mich
recht erinnere: Flash-Adresse sind 2 Byte, also lohnt es sich ab >2
Zeichen nicht mehr einen char-Pointer zu übergeben und sich das RAM mit
dem String zu befüllen, sondern die Flash-Adresse.
Ob das so 1:1 von Assembler auf C übertragbar ist musst du wissen ;)
Klever, bei ungerader Anzahl der Bytes im String springt der IJMP auf
das letzte Wort im String, das ist jedoch durch das automatische Padding
des Assemblers 0x0000 und wird als NOP decodiert. Das spart die
Korrektur auf die nächste gerade Byteadresse, benötigt aber zwingend
0x00 als Ende-Marker.
Es geht immer noch einen Tick schlanker!
und schrieb:> wobei jeweils das erste Byte die Laenge des Strings bedeutet
Das wär mir zu umständlich, immer erst die Zeichen abzählen zu müssen.
Außerdem braucht man dann noch ein zusätzliches Register, um die Länge
zu vergleichen.
Die C-Entwickler waren nicht doof und haben sich schon was dabei
gedacht, einen String einfach mit 0 enden zu lassen.
Peter Dannegger schrieb:> Die C-Entwickler waren nicht doof und haben sich schon was dabei> gedacht, einen String einfach mit 0 enden zu lassen.
Da gehörte nun wirklich nicht viel dazu und sie waren auch nicht die
Ersten, die das so gemacht haben.
Der String direkt hinterm Aufruf ist elegant und bequem, aber nur, wenn
man den String nur einmal braucht. Ich habe meist eine Tabelle mit den
Anfangsadressen der Strings, so daß ich nur ein Byte brauche, um einen
String zu bezeichnen. Das zahlt sich aus, wenn komplexere
Datenstrukturen Strings benutzen.
Und gerade bei Strings fürs LCD kann es hilfreich sein, wenn die
Ausgabefunktion das erste Byte des Strings als Befehl statt Daten ans
Display schickt. Oft muß man sowieso vorher den Cursor positionieren,
das hat man dann mit nur einem zusätzlichen Byte erledigt.