Hallo ich will eine 8-Bit Zahl aus register xy an ein lcd ausgeben. wie stell ich das an? weil ich muss die zahl ja praktisch in 1er, 10er und 100er zerlegen und die Ziffern dan einzeln an das LCD senden. Aber wie ist sowas zu bewerkstelligen? Ich verwende den ATMega16 unter Assembler. luxx
Hallo Luxx, Du brauchst also eine binär nach ASCII Umwandlung und die findest Du hier: http://www.avr-asm-tutorial.net/avr_de/rechnen/konversion.html Gruß, Klaus
Hi, ich hab ein Programm in Verbindung mit dem aus dem Tutorial gegebenen LCD-routines für eine 8 bit Zahl geschrieben. War aber eines meiner ersten, daher vielleicht vom Code nicht so einbahnfrei. Nach dem Programmtext befindet sich eine Erklärung, zudem habe ich den Programmcode auch dokumentiert. Falls du noch fragen hast, noch mal schreiben. Greetz Mech-Michi
Hallo, das geht einfach, zuerst festellen ob Zahl größer als 100 wenn ja dann 100 abziehen Zähler um eins erhöhen Rest vergleichen ob größer als 100 wenn ja dann nochmal 100 abziehen Zähler um 1 erhöhen wenn nein dann das Selbe mit 10 Im Zähler steht dann immer deine 100er oder 10er Stelle. Wenn 10er fertig ist der Rest die 1er Stelle. es grüsst, Arno
@ arno: stimmt da hätte ich ja selber auch draufkommen können. ich werde mal den quelltext von Mech_michi hernehmen , der is garnet schlecht! Danke fürs posting!!
Hi ich habe da jetzt mal selber was geschrieben nur Klappt das ganze nicht so wie ich will, die Zahlen 0 - 227 werden korekt angezeigt von 228 an zeigt mein Display nur noch "000" an. Wäre nett wenn sich jemand das mal kurz anschauen könnte wo mein Fehler ist? Mfg Jogibär. .include "m16def.inc" ;Port A = Taster ;Port B = ;Port C = ;Port D = LCD ;r20 = Dauer 0b00110000 (Auf LCD eine "0") ;r21 = Dauer 0x01 ;r22 = SUB Wert ;r23 = ;r24 = ;r25 = ;r26 = ;r27 = Wert 100er ;r28 = Wert 10er ;r29 = Wert 1er ;r30 = ;r31 = .def temp = r16 .def temp1 = r19 .def temp2 = r18 .def temp3 = r17 ; STACKPOINTER INITIALISIEREN ldi temp, LOW(RAMEND) out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;PORTS DEFINIEREN ldi r16, 0b00000000 out DDRA, r16 ;PORT A = EINGANG ldi r16, 0b11111111 out DDRD, r16 ;PORT D = AUSGANG ;PROGRAMM rcall lcd_init rcall lcd_clear loop: in r16, PINA ldi r27, 0b00110000 ldi r28, 0b00110000 ldi r29, 0b00110000 ldi r21, 0x01 L100: cpi r16, 0b01100100 ;Vergleichen mit 100 brmi L010 ;Kleiner 100 --> L010 add r27, r21 ldi r22, 0b01100100 sub r16, r22 rjmp L100 L010: cpi r16, 0b00001010 ;Vergleichen mit 10 brmi L001 ;Kleiner 10 --> L001 add r28, r21 ldi r22, 0b00001010 sub r16, r22 rjmp L010 L001: cpi r16, 0b00000001 ;Vergleichen mit 1 brmi Ausgabe ;Kleiner 1 --> Fertig add r29, r21 ldi r22, 0b00000001 sub r16, r22 rjmp L001 Ausgabe: rcall lcd_1zeile mov temp1, r27 ;1.Zeichen anzeigen rcall lcd_data mov temp1, r28 ;2.Zeichen anzeigen rcall lcd_data mov temp1, r29 ;3.Zeichen anzeigen rcall lcd_data rjmp loop .include "lcd-routines.asm" ;LCD-Routinen werden hier eingefügt
Hallo, ich habe dein Programm etwas verändert, die Änderungen sind mit ***** gekennzeichnet. So sollte es funktionieren. Es grüsst, Arno .include "m16def.inc" ;Port A = Taster ;Port B = ;Port C = ;Port D = LCD ;r20 = Dauer 0b00110000 (Auf LCD eine "0") ;r21 = Dauer 0x01 ;r22 = SUB Wert ;r23 = ;r24 = ;r25 = ;r26 = ;r27 = Wert 100er ;r28 = Wert 10er ;r29 = Wert 1er ;r30 = ;r31 = .def temp = r16 .def temp1 = r19 .def temp2 = r18 .def temp3 = r17 ; STACKPOINTER INITIALISIEREN ldi temp, LOW(RAMEND) out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;PORTS DEFINIEREN ldi r16, 0b00000000 out DDRA, r16 ;PORT A = EINGANG ldi r16, 0b11111111 out DDRD, r16 ;PORT D = AUSGANG ;PROGRAMM rcall lcd_init rcall lcd_clear loop: in r16, PINA ldi r27, 0b00110000 ldi r28, 0b00110000 ldi r29, 0b00110000 ldi r21, 0x01 L100: cpi r16, 0b01100100 ;Vergleichen mit 100 brcs L010 ;Kleiner 100 --> L010 ***** add r27, r21 ldi r22, 0b01100100 sub r16, r22 rjmp L100 L010: cpi r16, 0b00001010 ;Vergleichen mit 10 brcs L001 ;Kleiner 10 --> L001 ***** add r28, r21 ldi r22, 0b00001010 sub r16, r22 L001: add r29, r16 ;***** in r16 sind nur noch Einer ***** rjmp Ausgabe Ausgabe: rcall lcd_1zeile mov temp1, r27 ;1.Zeichen anzeigen rcall lcd_data mov temp1, r28 ;2.Zeichen anzeigen rcall lcd_data mov temp1, r29 ;3.Zeichen anzeigen rcall lcd_data rjmp loop .include "lcd-routines.asm" ;LCD-Routinen werden hier eingefügt
@Jogibär L100: cpi r16, 0b01100100 ;Vergleichen mit 100 brcs L010 ;Kleiner 100 --> L010 ***** add r27, r21 ldi r22, 0b01100100 sub r16, r22 rjmp L100 Warum um alles in der Welt schreibst Du 100 als 0b01100100. Ich bein jetzt 25 Jahre im Geschäft, aber das 0b01100100 dezimal 100 ergibt sehe ich immer noch nicht auf einen Blick. Schreib das doch als cpi r16, 100 ;Vergleichen mit 100 und gut is. Allerdings steht jetzt im Code und im Kommentar exakt dasselbe. D.h. der Kommentar erzaehlt mir nichts, was ich nicht auch im Code sehen wuerde und ist damit überflüsig und kann weg. L100: cpi r16, 100 brcs L010 ;Kleiner 100 --> L010 ***** add r27, r21 ldi r22, 100 sub r16, r22 rjmp L100 Allerdings waere ein Kommentar interessant, was den in diesem Code Abschnitt tatsaechlich passiert: ; Ziehe von r16 immer wieder 100 ab solange bis r16 kleiner ; als 100 geworden ist. In r27 wird mitgezaehlt, wie oft das ; moeglich war L100: cpi r16, 100 brcs L010 ;Kleiner 100 --> L010 ***** add r27, r21 ldi r22, 100 sub r16, r22 rjmp L100 L010: So erzaehlt mir der Kommentar sehr viel mehr, als wenn ich nur im Kommentar das dokumentiere, was ohnehin im Code auch ersichtlich ist. Den Kommentar beim brcs wuerde ich (fuer mich) lassen, da ich weiss, dass ich immer wieder Minutenlang ueberlegen muss, wie das nun mit den Flags nach einem Compare ist: Welches Flag bedeutet was? Und somit ist das 'Kleiner' etwas, was zumindest ich nicht sofort (ohne Nachdenken) aus dem brcs ersehen kann. PS: Anders als beim add, gibt es beim sub eine Variante in der man die zu subtrahierende Zahl direkt angeben kann.
> Warum um alles in der Welt schreibst Du 100 als 0b01100100.
Ich vermute mal, weil es dem Unwissenden zeigt, dass man Ahnung hat...
;-) <--- datt iss'n 'Lächeln'...
Aber um die Verwirrung mal perfekt zu machen:
1 | lcd_print8: ;Wird vom Makro aufgerufen. Gibt Byte als 2 |
2 | ;oder 3 Ziffern an LCD aus. |
3 | push wl ;Reg sichern |
4 | ldi wl,-1+'0' ;Hunderter-Stelle als ASCII-Zeichen, |
5 | Zahl |
6 | ;ist positiv |
7 | inc wl ;Hunderter hoch und |
8 | subi xl,100 ;100 subtrahieren bis negativ wird |
9 | brsh pc-2 ;negativ? nein, 2 Zeilen hoch |
10 | cpi wl,'0' ;ja, ist Ziffer = "0"? |
11 | breq pc+2 ;ja, nicht ausgeben... |
12 | rcall lcd_data ;Hunderter ausgeben... |
13 | ldi wl,10+'0' ;Zehner-Stelle als ASCII-Zeichen, Zahl |
14 | ;ist negativ |
15 | dec wl ;Zehner runter und |
16 | subi xl,-10 ;10 addieren bis positiv wird |
17 | brlo pc-2 ;positiv? nein, 2 Zeilen hoch... |
18 | rcall lcd_data ;ja, Zehner Stelle ausgeben... |
19 | ldi wl,'0' ;ASCII-0 |
20 | add wl,xl ;Einer addieren (Rest war ja positiv) |
21 | rcall lcd_data ;Einer ausgeben... |
22 | pop wl ;Reg wiederherstellen |
23 | ret ;zurück |
Grins, duck & weg... ...
@Hannes Ich denke mal Du hast nichts dagegen, wenn ich diesen Code, so wie vieles andere von Dir Geschriebene, einfach verwende. Ich finde naemlich, dass Dein Assembler extrem gut zu lesen und zu verstehen ist. Das musste naemlich auch mal gesagt werden!
@Karl Heinz: Erstmal danke für das Lob... Was soll ich denn dagegen haben? Ist doch auch nur zusammengestoppelt, aufbereitet und dabei auf das Niveau eines Hobbybastlers gebracht. Aber er ist verstanden , besteht also nicht nur aus zusammengesuchten unverstandenen Schnipseln. Die 'gute Lesbarkeit' hat damit zu tun, dass ich den Code ja selbst verstehen möchte, wenn ich ihn nach Wochen oder Jahren wieder lese. Bit- & Bytebruch... ...HanneS...
Schonmal über sowas nachgedacht: #include<stdio.h> unsigned char byt; void main(void){ for(byt=0;byt<255;byt++){ printf("%d%d%d ",byt/100,byt%100/10,byt%10); } } Sollte in Asm auch nur ein paar Zeilen sein, denn div (/) und mod (%)können die meisten µC in Asm. Führende Nullen unterdrücken: printf("%c%c%d ",byt/100?'0'+byt/100:' ', byt/10?'0'+byt%100/10:' ', byt%10);
@Profi, printf macht auf nem 8051 erstmal nen riesen Hopser um 2kB nach oben. Anders gesagt, ein AT89C2051 macht sofort die Grätsche (hat nur 2kB). Und der AVR hat keine Division. Dein Rat war also richtig gut um zu zeigen, wie man es nicht machen sollte ! Peter
@HanneS Ich mußte erstmal nachgucken, daß BRSH = BRCC ist. Der Kommentar zu Zeile 9 ist nicht ganz korrekt, da das Carry nur für positive Zahlen gilt. Man sollte wohl besser von Überlauf und Unterlauf sprechen. Und deshalb darf man auch nicht die Vergleiche für vorzeichenbehaftete Zahlen (BRPL, BRMI) nehmen, sonst stimmen Werte über 227 nicht mehr. Peter
@Peter: Danke... > Der Kommentar zu Zeile 9 ist nicht ganz korrekt, da das Carry nur > für > positive Zahlen gilt. Man sollte wohl besser von Überlauf und > Unterlauf > sprechen. Dann werde ich aus: brsh pc-2 ;negativ? nein, 2 Zeilen hoch wohl brsh pc-2 ;Unterlauf? nein, 2 Zeilen hoch machen müssen... Auf BRPL und BRMI bin ich anfangs auch gelegentlich reingefallen, ist mir aber schon lange nicht mehr passiert. Inzwischen benutze ich BRSH und BRLO nicht mehr, dafür BRCC und BRCS (ist ja das selbe), das erscheint mir irgendwie logischer bzw. direkter. Aber da besteht bei mir noch etwas Lernbedarf, so richtig sattelfest bin ich da noch nicht... Gruß... ...HanneS...
Ja wunderbär, mit BRCS statt BRMI klappt das ganze. Dankeschön Jogibär.
@Peter: tut mir leid, ich wußte nicht, dass der AVR keine Div kann. Habe damit noch nichts gemacht. Das mit dem C-Programm und dem printf sollte ja nicht heißen, dass man es so programmieren soll, sondern rein als Denkanstoß, dass es außer der Subtraktionsmethode auch noch andere Wege gibt. >Dein Rat war also richtig gut um zu zeigen, wie man es nicht machen sollte ! besser: ... wie man es nicht auf einem µC, der kein div und mod kann, machen sollte. z.B. auf einem 68hc908 läuft das nämlich wunderbar, ist halt ein CISC. Deshalb hier noch der Code für 16-bit-Ausgabe: #include<stdio.h> unsigned int w; //Word void main(void){ for(w=0;w<567;w++){ printf("%d%d%d%d%d ",w/10000,w%10000/1000,w%1000/100,w%100/10,w%10); } } Führende Nullen unterdrücken: printf("%c%c%c%c%d ", w/10000?'0'+w /10000:' ', w/ 1000?'0'+w%10000/1000:' ', w/ 100?'0'+w% 1000/ 100:' ', w/ 10?'0'+w% 100/ 10:' ', w%10); Läuft natürlich auf einem 16-bitter optimal, auf einem 8-bitter gibt es bestimmt elegantere Methoden. Code aus dem Stegreif gedichtet, ohne ihn kontrolliert zu haben.
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.