Hallo, ich wollt ne variable deklarieren wie in c aber ich bekomm des einfach nicht hin. muss ich des mit nem Register machen?? folgend soll es aussehen: ldi temph, "Test Adresse" Wie lad ich den text in die variable damit ich se dann an das lcd dispaly übergeben kann?? Der Befehl zum übertragen sieht so aus: daten: .db $temph,0 Ich bin mir nicht sicher ob das $-Zeichen vorne dran sein muss oder ob ein anderes zeichen hin muss???
Wenn du c kannst, Assembler aber nicht, dann mach es doch in c. Ansonsten http://www.avr-asm-tutorial.net/avr_de/index.html Oliver
ja c kann ich eigentlich schon aber eben in asm steh ich grad auf dem schlauch!! Trotzdem danke für die antwort!
also versteh ich des richtig im asm kannst du so viele variablen definieren wie du register hast oder?? Das mit den Registern weis ich schon aber ich wollt nur wissen ob man auch ohne register variablen deklarieren kann aber ich glaub das geht nicht bzw. gibt keinen sinn!!
An das LCD Display kannst du nur zeichenweise Daten übergeben. D.h. deine Variable ist grundsätzlich ein Zeiger auf eine Zeichenkette. Nach und nach wird das Zeichen auf das dieser Zeiger zeigt an das LCD gegeben und der Zeiger wird auf die nächste Adresse gesetzt - eine Schleife bis zum Endezeichen (in C Nullbyte, in ASM im Prinzip egal, Nullbyte ist praktisch). Die Ausgabe ist im AVR Tutorial beim LCD erklärt... http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD#Ausgabe_eines_konstanten_Textes [ASM] text: .db "Test",0 ; Stringkonstante, durch eine 0 ; abgeschlossen [/ASM] Legt den Text unter der (16 BiT) Adresse (Label) text ab. Die Null dient später als Endezeichen. [ASM] ldi ZL, LOW(text*2) ; Adresse des Strings in den ldi ZH, HIGH(text*2) ; Z-Pointer laden [/ASM] Lädt das 16-Bit Z-Register mit obiger Anfangsadresse des Textes. Die beiden 8-Bit Hälften der 16-Bit Adresse werden auf die beiden 8 Bit Registerhälften verteilt. [ASM] lcd_flash_string_1: lpm temp1, Z+ ; Zeichen von Anfangsadresse (Z) ; nach temp1 schauffeln, Z um ; eins erhöhen cpi temp1, 0 ; Endezeichen (0) erreicht? breq lcd_flash_string_2 ; JA, dann Sprung zu ; lcd_flash_string_2 call lcd_data ; (NEIN), dann Zeichen ausgeben rjmp lcd_flash_string_1 ; Sprung zum nächsten Zeichen holen lcd_flash_string_2: [/ASM]
> also versteh ich des richtig im asm kannst du so viele variablen > definieren wie du register hast oder?? Das mit den Registern weis ich > schon aber ich wollt nur wissen ob man auch ohne register variablen > deklarieren kann aber ich glaub das geht nicht bzw. gibt keinen sinn!! Du definierst dir mit z.B. .def temp1 = r16 nur einen neuen Namen temp1 für das Register r16. Das kann die Lesbarkeit deines Quelltextes erhöhen. Wenn dir die Register als Speicherplatz für Variablen ausgehen, kannst du die Variablen auch im Speicher (RAM) anlegen. Im obigen Fall kann man text als eine (konstante ;-) Variable ansehen. Speicherzugriffe sind langsamer als Registerzugriffe, deshalb arbeitet man - vereinfacht - so lang es geht mit Registern.
> Speicherzugriffe sind langsamer als Registerzugriffe, deshalb arbeitet > man - vereinfacht - so lang es geht mit Registern. ...Und nur in Registern kann man Daten auch bearbeiten (berechnen). Deshalb müssen alle Daten, mit denen eine Operation durchgeführt werden soll, in Register geladen werden. Im SRAM kann man Daten "nur" speichern.
Ah ok ich versteh! jetzt nur nochmal zu meinem Porblem wie kann ich dann folgendes realisieren: cpi menu_cnt, 0x01 ldi temph, "Menuepkt 1" cpi menu_cnt, 0x02 ldi temph, "Menuepkt 2" cpi menu_cnt, 0x03 ldi temph, "Menuepkt 3" also ich geb über taster ein signal rein das mit hochzählt und dann soll im lcd display der passende Text stehen. Mein gedanke war der dass ich dann hier die daten in die variable speicher und an das unterprog weitergeb. also wie oben schon geschrieben mit daten: .db $temph, 0 Also quasi wenn menu_cnt 0x01 ist dann soll im display menuepkt 1 stehn und so weiter.
> ldi temph, "Menuepkt 1"
Das hat so keinen Zweck. Dir fehlen die absoluten Assembler-Grundlagen.
In ein 8-Bit-Register kannst Du keinen Textstring legen. Da passt nur
ein einziges ASCII-Zeichen rein. Wenn Du mit .db eine Tabelle im
Programmspeicher angelegt hast, dann kannst Du mit lpm auf die einzelnen
Zeichen zugreifen. Schau Dir bitte erst gründlich das Tutorial an. Und
wenn Du dazu Fragen hast, dann kannst Du die hier stellen. Assembler und
C sind zwei völlig verschiedene Paar Schuhe!
Das ist ziemlich straightforward... menuetext_1: .db "Menuepkt 1",0 menuetext_2: .db "Menuepkt 2",0 menuetext_3: .db "Menuepkt 3",0 ; ... Rest vom Programm ... cpi menu_cnt, 0x01 breq ausgabe_menue_1 ; JA, dann Sprung zu cpi menu_cnt, 0x02 breq ausgabe_menue_2 ; JA, dann Sprung zu cpi menu_cnt, 0x03 breq ausgabe_menue_3 ; JA, dann Sprung zu ; Kein Menue 1-3 gefunden rjmp sonstwohinzumbeispielneuentastereinlesen ausgabe_menue_1: ldi ZL, LOW(menuetext_1*2) ; Adresse des Strings in den ldi ZH, HIGH(menuetext_1*2) ; Z-Pointer laden rjmp ausgabe_menue ausgabe_menue_2: ldi ZL, LOW(menuetext_2*2) ; Adresse des Strings in den ldi ZH, HIGH(menuetext_2*2) ; Z-Pointer laden rjmp ausgabe_menue ausgabe_menue_3: ldi ZL, LOW(menuetext_3*2) ; Adresse des Strings in den ldi ZH, HIGH(menuetext_3*2) ; Z-Pointer laden rjmp ausgabe_menue ausgabe_menue: lcd_flash_string_1: ; temp1 muss definiert sein und ggf. push/pop zum Retten ; siehe Tutorial lpm temp1, Z+ ; Zeichen von Anfangsadresse (Z) ; nach temp1 schauffeln, Z um ; eins erhöhen cpi temp1, 0 ; Endezeichen (0) erreicht? breq lcd_flash_string_2 ; JA, dann Sprung zu ; lcd_flash_string_2 call lcd_data ; (NEIN), dann Zeichen ausgeben rjmp lcd_flash_string_1 ; Sprung zum nächsten Zeichen ; holen lcd_flash_string_2: ret
ja ich weis dass ich in nem reg nur 8 bit speichern kann deshalb frag ich ja hier nach wie cih das lösen kann. ich weis auch dass nur asci zeichen gespeichert werden können und da geht ja immer nur ein buchstabe. soviel weis ich auch! Des programm oben soll nur den gedanken verdeutlichen. lies mal den betreff dann weist du um was es geht!
Ähm statt ret natürlich rjmp sonstwohinzumbeispielneuentastereinlesen, ist ja mit Sprüngen gemacht und nicht mit Unterprogrammaufrufen.
Thx stefan! so hab ich mir das auch gedacht aber ich hab halt gemeint ob vielleicht das geht so wie in c dass ich in ner variablen einen ganzen text speichern kann! Sowas nenn ich mal ne vernünftige antwort!
In C speichert es in diesem Fall eigentlich auch nur eine Adresse in der Variable. Es erscheint dir so, als ob der Text dann dort drin steht. Die Fummelei mit Platz im Speicher für die eigentlichen Zeichen anlegen und Laden der Speicheradresse ins Arbeitsregister bei Zugriff ist bei C "versteckt". Du könntest (und solltest ruhig mal zu Lernzwecken) dir aus dem C ein ASM machen lassen (ASM-Listing oder ASM-Ansicht im Debugger) und wenn du dort nachsiehst, wirst du obiges Verfahren erkennen.
des uprog lcd_flash_string ist das das selbe wie in der datei lcd_routines.asm oder?? weil dann könnt ich ja das weglassen oder?
Wahrscheinlich und wegen der Registerretterei sogar besser. Ich habe das gestrippte aus der ersten Antwort nur eingefügt, um zu zeigen, was ausgabe_menue machen muss. Du kannst mit Unterfunktion so arbeiten: ausgabe_menue: rcall lcd_flash_string ; ausgeben rjmp sonstwohinzumbeispielneuentastereinlesen ; fertig, nächste Taste?
funktioniert das ganze dann mit einer einzelnen zahl? also ich mein ich hab in ner variable eine zahl z.b. 5. ist ja weniger als 8 bit! kann ich die so verarbeiten wie ich oben schon gedacht hab?
Meinst du, ob du eine Zahl direkt in ein Register laden kannst? Ja das geht. ldi temp1, $21 Lädt die hexadezimale Zahl $21 (=0x21 in C Schreibweise) in das Register, für das du den Namen temp1 vergeben hast. Andere Schreibweise mit 5 als Beispiel: ldi temp1, 5 Im Wiki steht das unter http://www.mikrocontroller.net/articles/Adressierung#Immediate-Werte
ja das weis ich aber ich meinte dann mit dem variablenaufruf. also: daten: .db $temp, 0 wenn ich jetzt davor eine Zahl in temp geladen hab macht der des dann???
Das hängt von dem dir nicht angegebenen Teil ab. Wenn das "Laden" ein Laden als Register bedeutet, d.h. temp als Name für ein Register steht, kommt nichts sinnvolles raus .def temp = r16 ldi temp, 5 daten: .db $temp, 0 ; ???? wäre ja .db $r16, 0 nach der .def Regel Wenn das Laden ein C-ähnliches Define (Textersetzung) bedeutet, also temp ein symbolischer Name für die Zahl 5 bedeuten soll, könnte es klappen. Ich weiss nur nicht, ob der Hex-Prefix $ zum Bezeichner gehört, also ob der Assembler "$temp" sieht oder $"temp", bzw. befürchte ich dass es einen Syntaxfehler gibt weil Hex-Prefix + kein Zeichen aus 0-9A-F vorkommt. .equ temp = 5 daten: .db $temp, 0 ; wäre dann .db $5 Bestimmt geht .equ temp = $5 daten: .db temp, 0 ; wäre dann .db $5
also ich mein so .def temp = r16 als beispiel ldi temp = 5 daten: .db temp, 0 geht des, dass dann das das gleiche ist wie daten: .db "5" , 0
Nein geht so nicht. Du könntest mit direkter Adressierung arbeiten wie es bei http://www.mikrocontroller.net/articles/Adressierung#Direkte_Adressierung beschrieben ist. Wenn du den Wert 5 bereits im Register temp (bzw. r16) hast, schreibst du den mit sts in den Speicher. .def temp = r16 ; als beispiel daten: .db 23, 0 ldi temp, 5 ; daten sieht noch so aus: 23,0 sts daten, temp ; daten sieht danach so aus: 5, 0 Mit "" musst du aufpassen. "5" ist das ASCII-Zeichen 5. Das ist was anderes als das Byte 5. .def temp = r16 ; als beispiel daten: .db "5", 0 ldi temp, 5 ; daten sieht noch so aus: 53,0 sts daten, temp ; daten sieht danach so aus: 5, 0
ah ok des is schlecht dass des net geht!!! ich hab folgendes problem ich lass einen zähler laufen und die gezählte zahl soll im display erscheinen deshalb fragte ich wie des geht!!
Bittte, bitte, bitte: Schau ins Tutorial. > lass einen zähler laufen und die gezählte > zahl soll im display erscheinen deshalb fragte ich wie des geht!! Auch das findest du im Tutorial: Wie man eine Zahl so aufbereitet, dass man die einzelnen Stellen als ASCII Code vorliegen hat und diese dann an ein LCD bzw. an eine UART übergeben kann. Es hat wirklich keinen Sinn, hier alles nochmal durchzukauen. Wenn zum Tutorial Fragen bleiben dann stell sie. Das ist ok, denn es hilft mir(uns) das Tutorial in diesen Punkten klarer zu machen. Danke.
ich hab das ganze doch nach dem tut gebaut aber etwas anders deshalb hab ich hier gefragt ob es so auch geht!
Wichtig: Lies auch die Teile vom Tutorial, die dich momentan nicht interessieren. Sehr oft sind Techniken und Verfahren in Artikeln versteckt, in denen man sie nicht vermutet. zb. Ist besagte Zahlenausgabe sowohl im LCD Artikel als auch im Uhrenartikel drinnen (und wahrscheinlich auch noch an anderen Stellen).
also hier jetzt mal mein code der vorläufig so ist! ich hab eine 10 bit breite zahl und dann funktioniert das so nicht wie in dem tut! adr_lcd: push temp1 push temp2 push temp3 mov temp2, dmx_adrl mov temp3, dmx_adrh ldi hun, '0' ldi ein, '0' ldi zen, '0' rjmp lcd_number1 lcd_number1: subi temp2, 100 brcs lcd_number2 inc hun rjmp lcd_number1 lcd_number2: ldi temp1, 0x02 subi temp2, -100 cpi temp3, 0x01 add hun, temp1 rjmp lcd_number3 lcd_number3: subi temp2, 10 brcs lcd_number4 inc zen rjmp lcd_number3 lcd_number4: ldi temp1, 0x05 subi temp2, -10 cpi temp3, 0x01 cpi zen, 0x09 rjmp overflow_zen add zen, temp1 rjmp lcd_number5 overflow_zen: ldi zen, 0x00 ldi temp1, 0x01 add hun, temp1 rjmp lcd_number5 lcd_number5: ldi temp1, 0x06 add ein, temp2 cpi temp3, 0x01 cpi ein, 0x09 rjmp overflow_ein add ein, temp1 pop temp1 pop temp2 pop temp3 rjmp adr overflow_ein: ldi ein, 0x00 ldi temp1, 0x01 add zen, temp1 pop temp1 pop temp2 pop temp3 rjmp adr
Big_Daddi wrote: > ich hab das ganze doch nach dem tut gebaut aber etwas anders deshalb hab > ich hier gefragt ob es so auch geht! Wo ist dann das Problem. > lass einen zähler laufen und die gezählte > zahl soll im display erscheinen deshalb fragte ich wie des geht!! Der Zähler ist in einem Register und im Tut gibt es eine Funktion die den Inhalt eines Registers als Zahl auf das LCD ausgeben kann.
> also hier jetzt mal mein code der vorläufig so ist! ich hab eine 10 bit > breite zahl und dann funktioniert das so nicht wie in dem tut! Doch, das tut es. Nur nicht direkt. Aber du kannst dir vom Tutorial das Prinzip abschauen wie man das macht. Dein Code schaut doch gar nicht so schlecht aus. Nur musst du berücksichtigen, dass * es auch Tausender gibt (10 Bit: größte Zahl == 1023) * du anstelle von nur 8Bit Arithmetik eine 16Bit Arithmetik machen musst (weil die Zahl ja in 2 Registern verteilt ist) Das Registerpärchen temp2/temp3 beschreibt bei dir eine 16 Bit Zahl. Um da 100 abzuziehen, musst du die Operation natürlich in 16 Bit machen: subi temp2, 100 // low Byte sbci temp3, 0 // High Byte Der sbci temp3, 0 mag seltsam aussehen. Was soll es bringen 0 abzuziehen. Dazu muss man aber berücksichtigen, dass ja nicht nur die 0 abgezogen wird, sondern auch das Carry Bit, welches gesetzt wird wenn im unmittelbar vorhergehenden subi ein Unterlauf entstanden ist. -> Siehst du: Steht schon auf meiner TODO Liste: Tutorial - LCD Funktionen - 16 Bit Zahlen ausgeben
jetzt kommen wir der sache schon näher! ne die zahl geht max bis 511! also reichen mir 9 bit!
Big_Daddi wrote: > jetzt kommen wir der sache schon näher! ne die zahl geht max bis 511! > also reichen mir 9 bit! OK. Dann kannst du die Tausender weglassen. Ändert aber nichts an der Tatsache, dass du zum abzählen der Hunderter mit 16 Bit Arithmetik arbeiten musst.
Karl heinz Buchegger wrote: > Big_Daddi wrote: >> jetzt kommen wir der sache schon näher! ne die zahl geht max bis 511! >> also reichen mir 9 bit! > > OK. Dann kannst du die Tausender weglassen. > Ändert aber nichts an der Tatsache, dass du zum abzählen > der Hunderter mit 16 Bit Arithmetik arbeiten musst. Nachdem du die Hunderter bearbeitet hast, kannst du wieder bei 8 Bit Arithemtik bleiben. Denn wenn die Hunderter erledigt sind, dann ist das 9. Bit schon mit Sicherheit eine 0 und die übrig gebliebene Zahl ist nur noch im Register temp2. Nach Bearbeiten der Hunderter bleibt ja nach den ganzen Subtraktionen nur noch eine Zahl <100 übrig.
warum ne null??? wenn das 9. bit 1 ist dh 256 dann muss ich doch noch bei den zehner 5 dazu zählen oder nicht??
Big_Daddi wrote: > warum ne null??? wenn das 9. bit 1 ist dh 256 dann muss ich doch noch > bei den zehner 5 dazu zählen oder nicht?? Nein. Wenn du wissen willst, weiviele Hunderter in 387 enthalten sind, dann musst du schon von 387 jeweils 100 abziehen und nicht nur von dem Teil der Zahl der kleiner als 256 ist.
ja des is klar ich hab mir nur des so gedacht also wenn bit 9 gesetzt ist dann zähl 2 bei den hunderter 5 bei den zehner und 6 bei den einern dazu! Also des war halt mein grundgedanke.
Big_Daddi wrote: > ja des is klar ich hab mir nur des so gedacht also wenn bit 9 gesetzt > ist dann zähl 2 bei den hunderter 5 bei den zehner und 6 bei den einern > dazu! Also des war halt mein grundgedanke. Machs nicht unnötig kompliziert durch die einführung von Spezialfällen. > 2 bei den hunderter 5 bei den zehner und 6 bei den einern und dann musst du wieder berücksichtigen, dass die 6 bei den Einern wieder einen Überlauf in die Zehner produzieren können, die ihrerseits wieder einen Überlauf in die Hunderter produzieren können. Und dann gilt das Ganze nur bei 9 Bit Zahlen, wenn du aber mal mehr hast (10 Bit), dann kannst du diese Spezialfunktion auf den Müll werfen und dafür wieder eine Spezialfunktion schreiben. Mit 16 Bit Arithmetik ist das doch viel einfacher. Es folgt nach wie vor dem bewährten Muster: 10000-er zählen, indem 10000 abgezogen wird bis etwas kleiner als 0 erreicht wird. 1000-er zählen, indem 1000 dazugezählt wird bis etwas größer als 0 erreicht wird 100-er zählen, indem 100 abgezogen wird bis etwas kleiner als 0 erreicht wird 10-er zählen, indem 10 dazugezählt wird bis etwas größer als 0 erreicht wird 1er zählen, ... die braucht man nicht zählen, die bleiben übrig. Alles was dazu nötig ist, ist das man die Arithmetik von 8 Bit auf 16 Bit bringt. Dafür ist der Prozessor in Form des Carry Bits vorbereitet. (Nicht vergessen: Auch die Vergleiche auf kleiner/größer 0 müssen in 16 Bit ausgeführt werden. Das ist aber einfach, denn das Vorzeichen ist immer im Highbyte das höchstwertige Bit, es reicht also eine Abfrage mit dem HighByte aus temp3)
Den Sourcecode kann ich so nicht zuordnen bzw. mit deiner Zählerei in Einklang bringen. Ist das vorhandener Code, den du für deine Zwecke anpassen willst? Es könnte sich um einen Teil einer Unterroutine handeln, die anscheinend eine 16-Bit (10 Bit valid?) DMX Adresse (dmx_adrh, dmx_adrl) in eine dreistellige dezimale Zahl (hun, zen, ein) aufsplittet. Die Ausgabe an sich müsste straightforward sein. Die in Registern gehalteten Ziffern hun, zen, ein sind bereits durch den Startwert '0' so angelegt, dass sie direkt und nacheinander als Ziffer aufs LCD ausgegeben werden können. Wenn man hun, zen, ein unbedingt im RAM speichern möchte und eine Zeichenkette ausgeben will, könnte man so vorgehen (obiges Beispiel weiterverwendet): daten: daten_hun: .db "H" daten_zen: .db "Z" daten_ein: .db "E" .db 0 ; neues adr adr: sts daten_hun, hun ; speicher <= register sts daten_zen, zen sts daten_ein, ein Und dann kann man die komplette Ziffernfolge an der Adresse daten ausgeben ldi ZL, LOW(daten*2) ldi ZH, HIGH(daten*2) rcall lcd_flash_string ; ... alter Code ab adr ...
@stefan: ne der code ist der code den ich geschrieben hab. g sorry bin noch nicht so erfahren damit! Ich will mich dadurch eigentlich ein wenig in die mcte einarbeiten da ich des ganze nur theoretisch lern! @Karl Heinz: ja das mit dem überlauf hab ich zwar schon abgefangen aber nicht komplett. ich schau jetzt einfach mal dass ich des ganze nach deinen vorschlägen versuch.
Ist es dann so eher richtig? adr_lcd: push temp1 push temp2 push temp3 mov temp2, dmx_adrl mov temp3, dmx_adrh ldi temp1, '0' lcd_number1: subi temp2, 100 sbci temp3, 0 brcs lcd_number2 inc temp1 rjmp lcd_number1 lcd_number2: rcall lcd_data subi temp2, -100 ldi temp1, '0' lcd_number3: subi temp2, 10 brcs lcd_number4 inc temp1 rjmp lcd_number3 lcd_number4: rcall lcd_data subi temp2, -10 ldi temp1, '0' ldi temp1, temp2 rcall lcd_data pop temp1 pop temp2 pop temp3 ret
Big_Daddi wrote: > Ist es dann so eher richtig? > > adr_lcd: > push temp1 > push temp2 > push temp3 > > mov temp2, dmx_adrl > mov temp3, dmx_adrh > ldi temp1, '0' > > lcd_number1: > subi temp2, 100 > sbci temp3, 0 > brcs lcd_number2 > inc temp1 > rjmp lcd_number1 > > lcd_number2: > rcall lcd_data Ich kanns hier nicht ausprobieren (mangels Hardware und Emulator), aber das sieht schon mal nicht schlecht aus. Was passiert wenn du das laufen lässt? (muss jetzt leider weg. Ich schau spätestens morgen wieder rein).
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.