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.