Forum: Mikrocontroller und Digitale Elektronik LCD-Befehl Problem


von Franziska Klein (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

1. Beschreibung der anwendung
   Das Progi soll später ein Zählwerk für eine Maschine werden. Man
könnte es als Impulszähler beschreiben. Ich würd auch einen fertigen
kaufen um mir erst gar nicht die mühe machen wenn er den rest könnte
was er später auch noch tun soll!

2. Beschreibung des Programms
   Das Grund Programm ist eine LCD Ansteuerung mit 8Bit wo noch ein
verstellbarer counter am eingang dranhängt. Nun da meine Ausgabe einen
wert von 000000-999999 haben muss ist es auf diesem wege nicht möglich
es zu verwirklichen (Beispiel im Anhang).
Ich frage mich wie man das anders machen kann oder ob man mit einem
Befehl die Tabellen automatisch hochzählen lassen kann so das aus

ldi  ZL,LOW(Tabelle0*2)
ldi  ZH,HIGH(Tabelle0*2)

wenn sbic  PINA,0x00 ist

ldi  ZL,LOW(Tabelle1*2)
ldi  ZH,HIGH(Tabelle1*2)

usw.

habt ihr eine idee ich würd mich sehr darüber freuen!

von Khani (Gast)


Lesenswert?

Hallo,

zuerst mal eine kurze Anmerkung :
Welchen Controller vewendest Du ?

Das Programm ist anscheinen für einen AVR (AT90S2313) geschrieben. Da
steht aber was von ''.include "8515def.inc"''. Ist das die
richtige Definitionsdatei ?

Du solltest noch kurz sagen, welche Hardware verwendet wird..

MfG, Khani

von Franziska Klein (Gast)


Lesenswert?

Hallo,

und vielen dank für deine antwort

ich habe das Programm auf einen 8515 umgeschrieben, und die
Portbelegung geändert. da ich später noch den counter des Mikros
brauche und der ja auf Port B liegt. Die Text Ausgabe funktioniert
einwandfrei.
Ich nutze ein Standart LCD mit einem HD44780, laufen lasse ich das über
mein stk500!

Problem wie gesasgt, ist das ich die unter Text Zeile im LCD von
000000-999999 hochzählen lassen will, immer um einen schritt sobald
PINA 0x00 gedrückt wird.

Mfg Franzi

von Khani (Gast)


Lesenswert?

Hallo nochmal,

also Du scheinst in Assmbler programmieren zu wollen. Ich weiß die
Befehle nicht auswendig, aber die Idee sollte reichen, dass man sich
informieren kann.

Zähler von 000000-999999 :
Der Wertebereich wird von einer 20bit abgedeckt, das folgt aus dem
maximalen Wert.

beginnend bei 0 bei jedem erkannten Tastendruck eine Variable
hochzählen (Inkrement)
Falls bei dieser Inkrementoperation ein Überlauf stattfindet (zu
erkennen aus dem Carry-Flag), wird eine zweite Variable um 1 erhöht.
Falls auch diese Variable überläuft, einfach eine dritte Variable
erhöhen.
Die Zahl ist nun folgendermaßen gespeichert "Var3 Var2 Var1".
Diesen Komplex kann man nun mit einer binär->ascii Umwandlung auf das
Display schmeißen (diese Routinen sind im Forum recht gut
ausdiskutiert. ich persönlich würde mal die von peter dannegger
empfehlen, die sind dokumentiert und elegant).

Jetzt muss man nur noch die drei Variablen mit einem festen Muster
vergleichen, um festzustellen, ob 999999 erreicht ist. Ist das der
Fall, werden alle drei Variablen auf Null gesetzt.

Viel Spaß beim informieren über die Befehle und die Routinen.

MfG, Khani

P.S.: man kann das sicher auch mit Hilfe einer Timer-Counter-Unit
lösen. Aber so ist es erst mal straight-forward.

von thkais (Gast)


Lesenswert?

Ich würde es mit einer BCD-Zahl lösen, die braucht zwar mehr
Speicherplatz, das ist aber in dieser Anwendung nicht tragisch. So
ersparst Du Dir die Umrechnung einer 20-Bit Binärzahl zur dezimalen
Anzeige.

von Franziska Klein (Gast)


Lesenswert?

Hallo thkais,

Was ist dann eine BCD-Zahl?

Mfg Franzi

von Chris (Gast)


Lesenswert?

Hallo Leute,

ich hab ein ähnliches Problem, hat das schonmal jemand gemacht?
ich mein ein Impulszähler in dieser form realiesiert?
wäre echt nett wenn jemand mal nen beispiel posten könne, ich stehe
nämlich auch vor dem Problem das ich es nicht gebacken bekomme den LCD
zu sagen das bei eingangs impuls er hochzählen soll!

Vielen Dank

von MooseC (Gast)


Lesenswert?

@FK
wenn eine Zahl zwar binär dargestellt wird aber nur einen Wertebereich
von 0 bis 9 aufweist und die Darstellungen von 1010b (Ah) bis 1111b
(Fh) verboten sind.
siehe hier:  http://www.danbbs.dk/~erikoest/bcd.htm

Mach es wie thkais sagt und am einfachsten nur je ein Byte pro Digit,
dann brauchst Du Dich nicht einmal mit den pseudotetraden beim packed
BCD abmühen. Der AVR hat keinen BCD-Korrekturbefehl und Du müsstest es
bei packed BCD mit Abfragen des Halfcarrys nachbilden. Das kannst Du ja
mal machen wenn Du es Dir unbedingt beweisen mußt oder der RAM-Speicher
knapp wird.

Beginne mit der niederwertigsten Steller, den "Einern" und addiere
beim Event eine Eins dazu  (mit inc z.B.).
Vergleiche auf 10. Ist 10 erreicht, setze zurück auf 0 und erhöhe in
gleicher Weise die nächst höhere Stelle. Gibt es keinen Übertrag mehr
mußt Du das Inkrementieren abbrechen..

Das kannst Du locker in einer Loop machen die fast bel. viele Stellen
bearbeitet.


qad, nicht getestet, also keine Gewähr!

ANZAHLSTELLEN: .equ  6
countreg:      .BYTE ANZAHLSTELLEN

IncCounter:
  ldi  XL, low( countreg )  ; universal, wenn als Parameter übergeben
  ldi  XH,high( countreg )
  ldi  r17,ANZAHLSTELLEN    ; universal, wenn als Parameter übergeben
loop:
  lds  r16,X      ; Digit holen
  inc  r16        ; erhöhe um 1
  cpi  r16,10     ; vergleiche mit 10
  brsh uebertrag  ; Ergebnis >=10, (breq reicht hier auch)
  sts  X,r16      ; Ergebnis zurückschreiben
  rjmp end        ; und beenden

uebertrag:
  clr  r16        ; Addition hat Übertrag ergeben -> Digit löschen
  sts  X+,r16     ; zurückschreiben und X auf nächste Digit stellen
  dec  r17        ; Schleifenzähler -1
  brne loop       ; noch was da?
end:
  ret             ;

Beim Ausgeben der Zahl brauchst Du dann nur noch jede Stelle mit '0'
zu addieren. Am besten Du schreibst Dir eine Spezielle Ausgabe für den
Zählstand, die vor dem Übertragen zum LCD zu jedem BCD-Digit den Offset
ASCII 0 dazuaddiert.

z.B. (nicht in BCDCOUNT!)
  :
  lds   r16,X+   ; hole ein Digit
  ldi   r17,'0'  ; ASCII 0 (besser einmal ausserhalb der loop)
  add   r16,r17  ; addiere ASCII 0 zum Digit
  rcall Lcd_Putc ; LCD erwartet Zeichen in r16
  :

Natürlich wäre eine binär/dezimal Umwandlung geschickter, da Du dann
auch andere Werte, die Nicht vom Zähler kommen, dezimal darstellen
könntest...aber das ist nun Dein Ding.


MooseC

von Franziska Klein (Gast)


Lesenswert?

Hallo MooseC,

als erstes möchte ich mich erstmal für deine mühe und deinen code
bedanken!

Ich habe ihn mir mal durchgelesen und denke auch das ich verstanden
habe was er tut und auch wie er es tut!

Was ich jetzt aber noch nicht ganz verstehe ist wie ich die ausgabe
meinem LCD beibringen soll, mit dem derzeitigen code zur ausgabe wird
das ja sicher nichts mehr, kann ich mir vorstellen, weil ich kann die
ausgabe sicher schwierig in

Tabelle0:      .DB " "

innerhalb der "" einfügen.?.

Sehe ich soweit richtig das die Ausgangszahl später in r16 liegt?

ldi  counter,16    ;Zeichenzaehler
    ldi  ZL,LOW(Tabelle0*2)  ;Low-Zeiger auf Tabellenanfang
    ldi  ZH,HIGH(Tabelle0*2)  ;High-Zeiger auf Tabellenanfang
loop_msgstart:  lpm        ;hole Zeichen aus Tabelle
    mov  buffer,zeichen    ;Zeichen uebergeben
    rcall  write_data        ;schreibe Zeichen in LCD
                inc  ZL
    brcc   no_carrystart
    inc  ZH
no_carrystart:  dec     counter                 ;alle Zeichen
gesendet?
                brne  loop_msgstart    ;Nein! Sende naechstes Zeichen

von MooseC (Gast)


Lesenswert?

Hmm

irgendwie glaube ich wir reden nicht über das Gleiche oder ich habe
Dein Problem völlig falsch verstanden.

Wolltest Du nicht einen Zählwert auf das LCD ausgeben? Dein Beispiel
mit dem lpm-Befehl holt sich die (unveränderlichen) Zeichen aus Flash
und gibt sie aus.
Dein 6-Stelliger Zähler muß sich im RAM befinden (oder in Register,
aber das laß mal lieber)

Für Textausgabe wie ein Begrüßung von Deinem Gerät oder Warnungen etc.
ist die Lösung mit lpm zu empfehlen, aber nicht für Variablen.

Variablen werden so definiert:

countreg:     .BYTE    6

Dem Label countreg weist der Assembler die nächste freie RAM-Addresse
zu und beachtet das die nächste freie dann 6 Bytes weiter ist.

Du brauchst zwei Ausgaben:
  eine für Variablen, die Zähler
  und eine für konstate Zeichen, wie eben die Meldungen

üblich ist es Zeichenketten (Strings) mit einer 0 (nicht ASCII) enden
zu lassen und beim Ausgeben eben auf diese Null zu testen und diese
nicht mehr auszugeben.

hello_txt:  .db  "hello world!",0  ; Null am Ende

Deine Zeichenausgabe ist doch über r16, genannt buffer. Also sollte es
ohne Änderung gehen.

Mein Lcd_Putc wäre dann bei Dir write_data

Also: Gebe die Zahl mit dem Ausgabemodul für den Zähler aus und
hänge den konstanten Text "Bunde",0 mit einer Textausgabe aus dem
Flash hinten dran. (oder gebe die paar Zeichen händisch aus)


Sag mal hattest Du etwa vor für alle Zählstände

Tabelle1:      .db   "000001 Bunde"
bis
Tabelle999999  .db   "999999 Bunde"

einzugeben? Ich täusch mich hoffentlich...


MooseC

von Franziska Klein (Gast)


Lesenswert?

Ja ne genau das hatte ich eben nicht vor weil ähm wie man schon sieht
wären das dann ein paar viele befehle die ich ihm schreiben müsste!

ach so das mit der zeichen ausgabe hatte ich eben nicht so ganz gerafft
aber jetzt scheint es mir einzulechten ich werd das mal ausprobieren,
nochmals danke schön!

von Franziska Klein (Gast)


Angehängte Dateien:

Lesenswert?

Hi MooseC,

ich schon wieder, ich hab das ganze mal Coded, und hab folgende
Probleme

a. ANZAHLSTELLEN: .equ  6

ich denke das sollte

.equ Anzahlstellen = 6

heissen oder?

b. countreg:      .BYTE ANZAHLSTELLEN

das will er nicht in .cseg habe es nach .dseg geschrieben

c. X und X+

da bin ich noch ahnungslos was damit überhaupt ist.

ich hoff ich raube dir nich allzuviel zeit!

mfg franzi

von MooseC (Gast)


Lesenswert?

Dazu must Du Dir eine Routine schreiben, mit Loop und so..
Nicht einfach blind in Deinen Code pasten.
Das X+ ist dabei entscheidend...

  ld    r16,X+   ; hole ein Digit
  ldi   r17,'0'  ; ASCII 0 (besser einmal ausserhalb der loop)
  add   r16,r17  ; addiere ASCII 0 zum Digit
??  inc   r16      ; ???????? Was soll das denn?
  rcall write_data ; LCD erwartet Zeichen in r16


richtig erkannt
.equ Anzahlstellen = 6

auch richtig
.dseg

X ist einer der 3 16Bit-Indexregister mit dem Du im Datenspeicher
herrumpointern kannst. (Z kann auch im Programmspeicher zugreifen)

X+ ist ein Autoinkrement nach dem Zugriff

 lds   r16,X  holt ein Byte aus dem Datensegment auf das X zeigt
mit X+ passiert das Gleiche, nur das X automatisch NACH (daher
postincrement) dem lesen/schreiben auf das nächste Byte gestellt wird.

ließ bitte dazu den Instructionset des AVR Seite 5 und 6 Figure 6,7 und
8
Und dann noch bitte Seite 83..87


MooseC

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.