mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Hex Wert -> Dezimal an LCD ausgeben


Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi.Ich hab hier schon paarmal gelesen, das manche Leute den Hexwert in
Dezimal dann auf das LCD ausgeben. Wie ist das möglich?

Also wenn die Zahl zwischen 0-9 ist, dann wüßte ich schon, wie das
geht...(glaube ich halt). Aber wie kann man ab der Zahl 9, den Hexwert
auf das LCD ausgeben?

Und beim AD Wandler, der läuft ja mit 10 Bit, wie kann ich dann das
realisieren?

Gruß Avus

Autor: Thomas Burkhardt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest dir einmal überlegen, was du wie darstellen willst. In
diesem Fall eine Zahl zwischen 0 und 1024. Für das LCD sind das also
bis zu vier Zeichen. BCD ist dein Freund, wenn es darum geht die Zahl
in einzelne Ziffern zu zerlegen.

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dankeschön

gruß Avus

Autor: ThomaF (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, das ist ja dann die voll große Rechenaufgabe, wenn man die 10 Bit
des AD Wandlers auf LCD ausgeben will. Multiplizieren und Dividieren
ist ja schon ein ganz großer Aufwand.

Mal schaun, ob ich da was finde...

Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Subtrahieren?
In einer Schleife?

...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Multiplizieren und Dividieren
ist ja schon ein ganz großer Aufwand."


Aber überhaupt nicht !


Ein AVR kann schätzungsweise 10.000 16-Bit Divisionen je Sekunde
machen, so schnell kannst Du die Werte gar nicht ablesen.

Der einzige Aufwand ist eventuell für Dich, zu verstehen, wie diese
Routinen funktionieren.


Peter

Autor: Hubert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo ist da das Problem?
Ich messe mit dem ADC im Mega8, multipiziere das 10bit Ergebbnis mit
z.B. 6 um den Messbereich anzupassen. Das Ergebnis sind mV. Zur Anzeige
in Volt durch 100 dividieren für die Vorkommazahl, für die Nachkommazahl
%100 und das Ergebnis jeweils über itoa umrechnen und mit lcd_puts()
ausgeben. Sieht so aus: Ich hoffe es kommt von der Formatierung her
einigermassen an.
lcd_gotoxy(15,1);
Wandelwert=max/100;              /* Maximalwert Vorkommastellen
berechnen*/
ltoa(Wandelwert,Wert1,10);    /* Maximalwert in ASCII-Wert umwandeln*/
lcd_puts_p(ausg[1]);      /* ausgabe "max"*/
lcd_puts(Wert1);        /* Wert von max auf Display ausgeben */
lcd_puts_p(fuellzeichen[1]);  /*Komma ausgeben*/
Wandelwert=max%100;      /* Maximalwert Nachkommastellen berechnen*/
  if (strlen(Wert1)==2){  /*Wenn anzeige zweistellig, dann Kommastelle
nur einstellig*/
    Wandelwert=Wandelwert/10;  /* Wert auf 1 Stelle begrenzen */
    if(Wandelwert == 0){  /* Wenn die ausgabe =0 */
      lcd_puts_p(fuellzeichen[0]);  /* eine 0 ausgeben */
    }
    else{
    ltoa(Wandelwert,Wert1,10);  /*Wert auf ASCII wandeln */
    lcd_puts(Wert1);
    }
  }
  else{
    ltoa(Wandelwert,Wert1,10);      /* Maximalwert in ASCII-Wert
umwandeln*/
    if (strlen(Wert1)==1){    /* wenn Nachkommastelle nur im
hundertstelbereich */
    lcd_puts_p(fuellzeichen[0]);  /* dann eine Null vorher einfügen */

    }
    lcd_puts(Wert1);  /* auf Display ausgeben */
  }

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tut mir leid Hubert, C kann ich nicht.

Zu Peter, du hast recht, es ist schwierig zu verstehen... Wie sieht das
dann aus, wenn ich dann z.B. die Dezimalzahl 1000 habe, also 0x03E8, wie
kann ich dann das ans LCD schicken? Ist das nochmal ein großer Aufwand?

Gruß Auvs

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie würdest du das schriftlich rechnen??

(Dabei mal das "Kleine Einmaleins" nicht anwenden.)

- 1000 subtrahieren, sooft es geht (positiv bleibt) = Tausender
- vom Rest 100 subtrahieren, sooft es geht = Hunderter
- vom Rest 10 subtrahieren, sooft es geht = Zehner
- Rest = Einer

Tausender, Hunderter, Zehner und Einer liegen dann binär vor. Ein Blick
in die Zeichen-Tabelle des LCD wird dir zeigen, ob diese Zahlenwerte
noch verändert werden müssen. Würdest du sie an ein anderes System
senden, welches ASCII versteht (PC), dann müsstest du jeweils der
Offset der ASCII-Tabelle (48) addieren um die Ziffern als (ASCII-)
Textzeichen zu erhalten.

...

Autor: nixo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
läßt sich bei reinen 8-bit werten auch einfach per division lösen, hat
den vorteil, daß der divisionsrest in B stehenbleibt und gleich
weiterverarbeitet werden kann.

Wenn der umzuwandelnde Wert in A steht:

mov    b,#01100100b
div    ab
mov    r2,a           ;Hunderter in r2 schreiben
mov    a,b            ;Divisionsrest in A holen
mov    b,#00001010b
div    ab

die hunderter sind jetzt in R2,
die zehner in A

Gruß
Oliver
und die Einer in B
wiederzufinden

Autor: Martin S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@avusgalaxy
"Tut mir leid Hubert, C kann ich nicht."

wie, du sprichst AVR-Assembler hoch und runter, und kannst kein C?

Ok, meine erste Programmiersprache die ich mal in einem früheren Leben
gelernt hatte war BASIC (schäm), aber dann ging es eigentlich erst
mal mit "Hochsprachen" wie Fortran, Pascal, etc. weiter. Ich hab mich
dann über diverse Assembler-Dialekte (8051, Z80, 80xx, 68000 etc) so
langsam "runter gerobbt" an die Prozessor Register, bis ich
irgendwann mal auf Slice-Prozessor-Ebene Microcode gecoded habe


Na ja, vielleicht ist es ja bei dir anders rum: Vom Kleinen zum
Großen...

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für BASIC braucht sich niemand schämen.
Nur auf dem AVR ist es (BASCOM) zu weit von der Hardware entfernt.

Assembler hat noch Niemandem geschadet. Für kleinere Programme (und ich
schreibe bisher nur kleinere Programme) ist es genial.

Ich denke schon, dass man ASM verstehen kann, ohne C zu verstehen,
glaube aber nicht, dass man ohne ASM-Kenntnisse C (auf dem AVR!)
wirklich kann.

...

Autor: Martin S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, da geb ich dir voll und ganz Recht: man kann ASM verstehen ohne C.
Aber man (ich) kann (komplexe) Sachverhalte besser verstehen, wenn ich
sie in einer flüssigeren Abstraktionsform schreibe (Hochsprache, oder
Metasprache) als in einem registerorientierter Assembler-Befehlssatz
versuche etwas auszudrücken.

Na ja, meine C-Programme sehen dann auch immer ziemlich "prosaisch"
aus, weil für mich 1 Zeile Dokumentation mehr Wert hat als 1 Zeile
Programmiersprache. Aber es gibt durchaus auch Hardcore-Programmierer,
welche Variablenbezeichner  bäh finden, wenn diese mehr als 2
Buchstaben lang sind ....

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nixo. Mir ist klar, das es bei dem 8051 mit div geht, nur bei den
AVR's gibts kein div...

@Martin S.

Hast du nicht auch mal angefangen? Oder bist du als Genie auf die Welt
gekommen?

@Hannes. Danke, verstehe es jetzt ungefähr.
Wenn ich jetzt z.B. 2450 dez. habe, dann kann ich "1000" zweimal
abziehen usw... Das muß ich dann halt im 16 Bit Register machen, oder?
R26 und R27 würde sich dafür eignen. Brauch ich da dann R28 und R29
auch, um 1000 zu subtrahieren?

Gruß Avus

Gruß Avus

Autor: Martin S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@avusgalaxy
Hat doch nix mit Genie zu tun. Eigentlich wollte ich dich ja loben, daß
du "algorithmisch in Assembler denken kannst",  scheint aber irgendwie
nicht angekommen zu sein.

Für mich war Assembler eher der "kniffligere" Teil, da dort halt
manchmal "Tricks" angewendet werden können/müssen, welche halt nicht
so augenfällig sind wie in einer Hochsprache.

"ich persönlich" kann mir eher eine unbekannte Programmlogik in einer
Hochsprache "erarbeiten" (womöglich ist er auch noch prima
kommentiert), als das ganze in Assembler zu "erfrickeln".

Beispiel: Irgendwelches Vektor-Grafik-Zeugs (wie zeichnet man effizient
einen Kreis in eine Rastermatrix ?) mündet schlussendlich in
Bildpunkten, welche in einen linear adressierbaren Speicher organisiert
werden. Da "mach ich mir lieber meinen Kopf" in einer Hochsprache, und
wenn das alles fertig überlegt ist, dann schnappe ich mir die am besten
nutzbaren Register um das in Bitebene abzubilden. Möglicherweise muß
ich dann sogar noch die trigonometrischen Funktionen ebenfalls in
Assembler nachbilden, weil mein Prozessor keine passende Arithmetik
kann.

Hochachtung vor dem, der den "Hochsprachenschritt" direkt
überspringen kann und das dann direkt in Assembler auszudrücken vermag.

Autor: nixo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@all
sorry, habe nicht aufgepasst - war bei meinen mcs51 lieblingen.

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe ja auch gehöhrt, das es in C alles leichter(kompakter) wäre,
aber Assembler ist halt die Sprache, die den Maschinen am ähnlichsten
ist.

Und wenn ich in C mal nicht weiter weiß, dann brauch ich wieder
Assembler.

Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Martin:

Ich wollte dich nicht kritisieren.

Auf dem PC (mit Betriebssystem!) schreibe ich auch nix in Assembler
(hatte mal vor Jahren mit DEBUG einige kleine COM's gebaut, da kam es
aber auf die geringe Dateigröße an). Allerdings schreibe ich da nicht
in C sondern in BASIC. QB und VB sind meine Freunde, aber dafür schäme
ich mich nicht.

Beim AVR (andere MC's nutze ich nicht) hat man ja kein Betriebssystem,
sondern hantiert man ja direkt an der Hardware. Diese ist im Datenblatt
erklärt. Komplizierte Berechnungen muss ich nicht durchführen, ich habe
da mehr Bits zu schubsen als Nummern. Das meiste sind nunmal
I/O-Zugriffe. Daher genügt mir ASM, denn da sehe ich was sich tut.

BASCOM mag ich nicht, weil es davon abhält, ins Datenblatt zu schaun.
Da wird für jedes Hardwarefeature ein Config angeboten, was nix mehr
mit dem Datenblatt zu tun hat. Außerdem ist man so weit von der
Hardware entfernt, dass man (ich zumindest) den Überblick verliert.
Dazu kommt noch, dass man mit der 2KB-Demo angefüttert wird und dann
die Vollversion kaufen muss. Das muss nicht unbedingt sein. Durch die
mitgelieferten Bibliotheken hat man zwar den "schnellen Erfolg",
sitzt aber danach auch schnell in einer Sackgasse, wenn es mal etwas
anders kommt (andere Hardware).

C ist gut. Aber wie jede Hochsprache ist es etwas weiter von der
Hardware entfernt. Dann kommt ja noch dazu, dass ANSI-C nicht
ausreicht, mit dem AVR zu kämpfen. Da kommen ja noch die
AVR-spezifischen LIBs dazu. Das ist mir (als Hobbybastler) einfach
zuviel. Da bleibe ich (vorerst) lieber bei ASM. Das ist kostenfrei,
zukunftssicher (in Bezug auf neue AVR-Typen) und bei meinen kleinen
Programmen auch übersichtlicher. Ich hantiere übrigens mehr mit dem
Tiny12/15 als mit dem Mega8/16/32. Reicht meistens für meine Projekte.

Dies soll aber keinesfalls eine "Kriegserklärung" gegen C (oder
Hochsprachen allgemein) sein, bitte nicht falsch verstehen.

@Avus:
Subtrahieren bis du im Minus bist, dann wieder einmal addieren. Dabei
einen Zähler mitlaufen lassen, der die Anzahl der Subtraktionen (und
Addition) mitzählt. Dieser ergibt dann deine Ziffer. Schau mal bei
ATMEL in die Appnotes (oder in die Appnotes in deinem Rechner, unter
avrtools\avrassembler\appnotes), da war glaube was zur Division
dabei.

...

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Anbei mal eine Umwandlung 32 Bit in ASCII nach der optimierten
Subtraktionsmethode.

Einfach mal mit beliebigen Werten durch den Simulator laufen lassen und
zuschauen, was passiert.


In C geht das natürlich viel einfacher (itoa, ltoa).


Peter

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, Peter, kann ich das einfach für 16 Bit umwandeln? Oder gibt es da
auch schon was fertiges? Oder 8 Bit...wäre noch einfacher zu verstehen.

Gruß  Avus

Autor: avusgalaxy (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ok, habe das jetzt mal gemacht, für 8 Bit und es scheint zu
funktionieren. Nur wie gehe ich da bei 16 Bit vor?

Das von Peter mit

subi r28, byte1(100000);-100,000
sbci r29, byte2(100000)
sbci r30, byte3(100000)

verstehe ich nicht...

byte1????
(100000)???

Keine Ahnung, Gruß Avus

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso benutzt Du zum Subtrahieren temp1, 2 und 3?
Benutze statt SUB SUBI (Subtract immediate).
Das heißt nix anderes, das Du zum subrahieren kein 2. Register
benötigts und den Subtraktionswert direkt angeben kannst:

 SUBI temp1,100

Das würde dann so aussehen:

  ldi zahl1, -1 + '0'
Zahl1:
  inc zahl1
  subi temp1, 100
  brcc Zahl1
  subi temp1, -100

  ldi zahl2, -1 + '0'

Zahl2:
  inc zahl2
  subi temp1, 10
  brcc Zahl2
  subi temp1, -10

  ldi Zahl3, '0'
  add zahl3, temp1


Da es beim AVR kein ADDI (add immediate) gibt kann man mit SUBI auch
addieren wenn vor der Zahl ein - (minus) steht: SUBI temp1,-100 addiert
100 auf temp3 (A + B = A - -B).


@Peter:
Beim Abschnit, wo 10.000.000 subtrahiert werden und Du das nur mit
Byte1, 2 und 3 machst, geht das denn?

  ldi  r23, -1 + '0'
_bcd3:  inc  r23
  subi  r28, byte1(10000000)  ;-10,000,000
  sbci  r29, byte2(10000000)
  sbci  r30, byte3(10000000)
  sbci  r31, 0
  brcc  _bcd3

Beim subtrahieren von 1 Milliarde läßt Du das Byte1 weg, klar, wird da
auch nicht benötigt, aber bei 10 Millionen und einer möglichen 27
Bit-Zahl nur 24 Bit subtrahieren?
Mit 24 Bit kann man doch nur bis 16777216 darstellen und evtl. ist im
Abschnitt _bcd3 noch 99.999.999 übrig.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Andi, Danke, so gehts gleich viel leichter...

Doch bei 16 Bit, wie gehts dann weiter?


.include "m8def.inc"

.def temp1   = r16
.def zahl1   = r17
.def zahl2   = r18
.def zahl3   = r19
.def zahl4   = r20
.def zahl5   = r21

  ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
  out SPL, temp1
  ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten RAM-Adresse
  out SPH, temp1

  ldi temp1, 0xFF    ;Port D = Ausgang
  out DDRD, temp1

 ;Da schreib ich den Hexwert rein:
  ldi zl, 0x03       ; Lowbyte für Z
  ldi zh, 0xD9       ; Highbyte für Z


  ldi zahl1, -1 + '0'

Zahl1:
  inc zahl1
  ???????????????????????????????????????????
  brcc Zahl1

Wie Kann ich vom Registerpaar R31 und R32 1000(dez) subtrahieren?

Mit "sbiw zl:zh, 63" kann man ja nur 63 subtrahieren

Weiß da jemand weiter?

Gruß Avus

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da der AVR ein 8Bit-µC ist muß man eine 16Bit-Subtraktion aus 2
8Bit-Subtraktionen machen was dank des Carry-Bits (Überlauf) einfach
möglich ist.

 subi r28,low(-10000)
 sbci r29,high(-10000)

"SBCI" (sub immediate with carry) heißt, das zur subtraktion das
Carry-Bit (0 oder 1) mit herangezogen wird.
Falls durch "SUBI" das low-Byte der 16Bit-Zahl in r28 ein Overflow
entsteht, z. B. Binär von 0b11100101 auf 0b01000101, wird nach dem SUBI
das Carry-Bit gesetzt und SBCI subtrahiert dann auf das high-Byte noch
mal 1 dazu.

Eigentlich hat Peter bereits in seinem Beispiel 8 bis
32Bit-Subtraktionen/Additionen dargestellt.
Mußt Du nur noch übernehmen und für Deinen Zweck anpassen.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, es klappt jetzt. Wenn ich in R30 0xE8 und R31 0x03 schreibe, dann
paßt die 1000er Stelle, die 100er Stelle, die 10er Stelle nur die 1er
Stelle geht nicht.

Kann doch nicht gehen, oder?

Bei den letzten Zeilen von Peter.....


subi r16, -10 - '0'
mov r16, r30

Zuerst addiert Peter 10 zu der Zahl "0", ist dann 0x3A. Und dann
überschreibt er R16 mit r30. Wie kann das gehn?

Kapier ich leider nicht..

Gru? Avus

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube, das es so gehöhrt:

ldi r16, 10 + '0'
add r16, r30

Stimmt das?

Gruß Avus

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schaut doch einfach mal in die appnote
http://www.atmel.com/dyn/resources/prod_documents/...



;*********************************************************************** 
****
;*
;* "bin2BCD16" - 16-bit Binary to BCD conversion
;*
;* This subroutine converts a 16-bit number (fbinH:fbinL) to a 5-digit

;* packed BCD number represented by 3 bytes (tBCD2:tBCD1:tBCD0).
;* MSD of the 5-digit number is placed in the lowermost nibble of
tBCD2.
;*
;* Number of words  :25
;* Number of cycles  :751/768 (Min/Max)
;* Low registers used  :3 (tBCD0,tBCD1,tBCD2)
;* High registers used  :4(fbinL,fbinH,cnt16a,tmp16a)
;* Pointers used  :Z
;*
;*********************************************************************** 
****

;***** Subroutine Register Variables

.equ  AtBCD0  =13    ;address of tBCD0
.equ  AtBCD2  =15    ;address of tBCD1

.def  tBCD0  =r13    ;BCD value digits 1 and 0
.def  tBCD1  =r14    ;BCD value digits 3 and 2
.def  tBCD2  =r15    ;BCD value digit 4
.def  fbinL  =r16    ;binary value Low byte
.def  fbinH  =r17    ;binary value High byte
.def  cnt16a  =r18    ;loop counter
.def  tmp16a  =r19    ;temporary value

;***** Code

bin2BCD16:
  ldi  cnt16a,16  ;Init loop counter
  clr  tBCD2    ;clear result (3 bytes)
  clr  tBCD1
  clr  tBCD0
  clr  ZH    ;clear ZH (not needed for AT90Sxx0x)
bBCDx_1:lsl  fbinL    ;shift input value
  rol  fbinH    ;through all bytes
  rol  tBCD0    ;
  rol  tBCD1
  rol  tBCD2
  dec  cnt16a    ;decrement loop counter
  brne  bBCDx_2    ;if counter not zero
  ret      ;   return

bBCDx_2:ldi  r30,AtBCD2+1  ;Z points to result MSB + 1
bBCDx_3:
  ld  tmp16a,-Z  ;get (Z) with pre-decrement
;----------------------------------------------------------------
;For AT90Sxx0x, substitute the above line with:
;
;  dec  ZL
;  ld  tmp16a,Z
;
;----------------------------------------------------------------
  subi  tmp16a,-$03  ;add 0x03
  sbrc  tmp16a,3  ;if bit 3 not clear
  st  Z,tmp16a  ;  store back
  ld  tmp16a,Z  ;get (Z)
  subi  tmp16a,-$30  ;add 0x30
  sbrc  tmp16a,7  ;if bit 7 not clear
  st  Z,tmp16a  ;  store back
  cpi  ZL,AtBCD0  ;done all three?
  brne  bBCDx_3    ;loop again if not
  rjmp  bBCDx_1

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... oder einfach

 subi r30,-(10 + '0')

Dann ist die Einer-Stelle zwar nicht in r16, sondern in r30, aber dafür
wieder einen Takt eingespart :-)

@Peter: Ist das eigentlich von Deiner Sicht richtig, das auf Byte3 und
Byte4 (r30 und r31) 1000 addiert und 100 subtrahiert werden?
Liegt das an der Optimierung?

@Hauke Sattler:
Das mit der AppNote ist mir bekannt aber die Routinen daraus dauern
gegenüber der Sub-Methode ewig und benötigen auch noch SRAM.
Für bestimmte Anwendungsfälle sind die geeignet aber nicht nötig für
ASCII-Ausgabe von Binärzahlen.
Da komme ich mit meiner Multifunktionsroutine zur Ausgabe von 8 bis 32
Bit-Zahlen schneller weg inkl. ASCII-Ausgabe in den LCD-Buffer.

Gruß
Andi

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich meinte halt nur das man das Rad nicht von neuem Erfinden muß. Und
außerdem hat die Appnote ne relativ gute Doku. Und letzteres ist bei
"Anfänger" Projekten mehr wert als ein paar eingesparte Taktzyklen.

P.S.

Ich progge AVR und Z80 und DMG90 ausschließlich in Assembler.

Das liegt aber daran, das es damals als ich auf dem Amstrad CPC464
geproggt habe, noch kein C gab (oder ich damals zumindest nicht davon
wußte)

Als ich dann mal vor ein paar Jahren nen DMG90 unter C proggen wollte,
hat mich der Compiler faßt ibn den Wahnsinn getrieben.
Nur Fehlermeldungen (mit deren Doku man nix anfangen konnte)
Danach hab dann mit ASM probiert und es fubbte faßt auf anhieb.

Ich denke dieses Erlebniss hat mit C für den Rest meines Lebens
verleidet.
Deshalb code ich selbst große Projekte ausschließlich in Assembler.
(Das größte hat zu Zeit ca 4,6 kWord)

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist schon klar, aber das mit dem Sub-Verfahren ist nicht neu erfunden
sondern muß immer wieder eingetrichtert werden ;-)
Desweiteren spart es wirklich unmengen an Takte gegenüber der
Bin2BCD-Funktion.
Die Bin2BCD16-Funktion benötigt laut Atmel selbst mindestens 751 Takte,
die Sub-Methode für 16 Bit im Schnitt nur ca. 150.
Wenn das nicht aussagekräftig genug ist sich die Sub-Methode anzutun
dann weis ich auch nicht mehr.

Gruß
Andi

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@avusgalaxy

ups, das ist ein Dreckfuhler, richtig muß es heißen:

subi r30, -10 - '0'
mov r16, r30


  subi  r28, byte1(10000000)  ;-10,000,000
  sbci  r29, byte2(10000000)
  sbci  r30, byte3(10000000)
  sbci  r31, 0

Das ist doch eine 32 Bit Subtraktion (4 Byte: r31...r28)

Kannst natürlich auch schreiben:

  ...
  sbci  r31, byte4(10000000)

denn 10000000 = 0x00989680, d.h. Byte4 ist 0.


Anbei das 16-Bit Beispiel, a0..a4 muß man mit Registern definieren.


Peter

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Zahlreichen Antorten. Das mit dem Sub funktioniert
wirklich gut und ist auch verständlich.

Jetzt läuft auch mein AD-Wandler (zum erstenmal). AVCC auf 5V und den
Eingang auch. (1023). Wenn ich den Eingang auf GND lege, dann erscheint
0 am Display. Soweit so gut.

Hab jetzt im Forum ein bisschen gestöbert und hab folgendes gefunden.

Anzeigewert = Messwert * (5 / 1024)

Damit kann ich ja die Spannung auf das LCD ausgeben. Nun bahnt sich
aber das nächste Problem auf: Messwert * (5 / 1024)...

Da muß ja wieder multiplizieren und dividieren.. Beim 8051'er wäre das
nicht schwer..

Also 5/1024 = 0.0048828125. Und das müßte ich dann mit dem Wert ADCL
und ADCH multiplizieren. Wie soll das bitte gehn?

Wie habt ihr das bloss geschaft?


Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal 5 dürfte einfach sein. (Notfalls 5 mal addieren)

Durch 1024 erreichst du durch Schieben und Wegwerfen des unteren
Bytes.

...

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im Ordner Appnotes vom AVR-Studio findest Du in den Dateien avr200.asm
und avr201.asm (nur für Megas) Divisions- und Multiplikationsroutinen
welche Du verwenden kannst.

Aber es geht auch anders.

 5 / 1024 = 0,0049

 mal 10000 = 49

Damit haben wir schon mal eine feste Konstante als Ganzzahl was das
ganze Vereinfacht.

Diese Ganzzahl multiplieziert man dann einfach mit dem Messwert:

 z. B. 374 * 49 = 18326

Das ist dann die gemessene Spannung welche am LCD mit einem "." nach
der 1 dargestellt werden kann, also 1.8326.

Die nötigen 16x16 Bit-Multiplikationen dafür findest Du in der
avr200.asm.

Natürlich kannst Du auch in einer Schleife 49 mal den gemessenen Wert
auf ein 16 Bit-Register aufaddieren:

 in r16,ADCL
 in r17,ADCH
 clr r18
 clr r19
 ldi r20,49
loop:
  add r18,r16
  adc r19,r17
  dec r20
 brne loop

Im Registerpaar r17:r16 ist der Messwert welcher auf das Registerpaar
r19:r18 49 mal addiert wird.
Das wäre dann schon alles.
Danach zur Dezimalwandlung, 1. Stelle ausgeben, "." sugeben, 2.
Stelle...
Ist zwar dann nicht auf die 1/100-Stelle genau aber OK.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, mach ich da was falsch? Bei mir zeigt das LCD "b.127" anstatt
5.000 an. Aref ist auf 5V



        in r28,ADCL
       in r29,ADCH
        clr zl
        clr zh
       ldi temp1,49
rechner:
        add zl,r28
        adc zh,r29
        dec temp1
       brne rechner
       rcall lcd_null



ldi r19, -1 + '0'
_bcd7:inc r19
subi r30, low(1000);-1000
sbci r31, high(1000)
brcc _bcd7


ldi r18, 10 + '0'
_bcd8:dec r18
subi r30, low(-100);+100
sbci r31, high(-100)
brcs _bcd8

ldi r17, -1 + '0'
_bcd9:inc r17
subi r30, 10;-10
brcc _bcd9

ldi r16, 10 + '0'
add r16, r30



       mov temp1, r19
       rcall lcd_data

       ldi temp1, '.'
       rcall lcd_data

       mov temp1, r18
       rcall lcd_data


       mov temp1, r17
       rcall lcd_data

       mov temp1, r16
       rcall lcd_data

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das liegt daran, das Du Deine Dezimalwandlung nur für Zahlen bis 9999
ausgelegt hast.
Aber der maximale Zahlenwert beträgt 1023 * 49 = 50127.

Füge am Anfang folgendes hinzu:

 ldi r20, -1 + '0'
_bcd6:
 inc r20
 subi r30, low(10000)   ;-10000
 sbci r31, high(10000)
 brcc _bcd6
 subi r30, low(-10000)  ;+10000
 sbci r31, high(-10000)

Danach dann das Digit in r20 zuerst ausgeben.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank Andi, jetzt geht es einwandfrei... Danke...

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe mir überlegt, wie man die Ungenauigkeit ausbügeln könnte.
Probier mal folgendes:

        in r28,ADCL
       in r29,ADCH
        clr zl
        clr zh
       ldi temp1,49
rechner:
        add zl,r28
        adc zh,r29
        dec temp1
       brne rechner

       mov  r16,zh     ;Abgleich (ZH:ZL - ZH:ZL/512)
       lsr  r16        ;r16 (ZH:ZL) / 512
       mov  r17,r16
       lsr  r17        ;In r17 1/4 von r16
       lsr  r17
       add  r16,r17    ;zu r16 addieren ergibt 5/4 von 1/512
       sub  zl,r16     ;Abgleichwert von ZH:ZL subtrahieren
       sbci zh,0

       rcall lcd_null

In r16 kommt 1/512 von ZH:ZL was von ZH:ZL abgezogen wird.
Je höher der Messwert desto höher der Abgleichwert.
Zumindest ist damit der höchste Wert 5.0006
Wenn Du dann noch die 5 stelle (6) nicht ausgiebst werden genau 5.000
angezeigt.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow, wieso weißt (kannst) du soviel? Hattest du Kurse? Wieviel Jahre
machst du das schon?

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach schon ein bißchen länger mit Proggen rum (seit den ZX81-Zeiten).
Funtzt das mit dem Abgleich?

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja, 5,0006 V... Haargenau. Hab die letzte Stelle weggenommen.

So könnte man ja auch einen Drehzahlmesser fürs Auto oder Motorad
bauen. Muß ja nicht immer der Timer sein, oder? Mit dem LM2907 könnte
man ja die Frequenz in eine Spannung umwandeln und dann in den AD
Wandler schicken. Müßte doch gehen, oder?

Mit den Timern habe ich leider noch keinen Durchblick, deshalb kommt
mir diese Idee.


Danke nochmal

Gruß Avus

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Theoretisch ginge das. Man muß dann eine ADC/RPM-Wandlung machen also
das bei ADC=1023 7000RPM und beim ADC=0 0RPM angezeigt werden.
Wenn man das in Schritten von 7 macht kommt man bei ADC=1023 auf
7161RPM als max.-Wert.
Wenn das nicht reicht dann mit einer Stufung von 8 (max. 8184RPM).
Nur wird es dann wohl schwieriger sein den Spannungsteiler für den
ADC-Pin anzupassen.
Mittels Timer ist RPM-Messung technisch gesehen wesentlich einfacher da
man mittels einem sehr genauen Quarz die Zeit zwischen 2 oder mehr
Impulsen mist und diese dann einfach als Divisor zur Umrechnung mittels
Division hernimmt.
Dafür ist die Software wohl etwas komplexer aber das wird doch
hoffentlich noch.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Andi..

Ich dachte mir, wenn ich 1023x10 nimm, dann hab ich eine max. Drehzahl
von 10230, was ich aber nicht brauche. Brauche bis max. 7000 U/min

Aber auf was ich noch nicht gekommen bin ist, in 50'er Schritten
anzuzeigen. Habe vorher 1023x50 genommen = 51150, aber da wird die
Anzeige sehr empfindlich.

Mit 1023x10 Hab ich jetzt 10'er Schritte. Gibt es da irgendeinen
Trick?

Ich dachte mir, daß ich die letzte Stelle Abfrage, bevor ich sie ans
LCD Ausgebe. Also 125"2" U/min, da ist 2 kleiner als 5 und ich mache
eine 0 draus. Wenn es 125"8" ist, dann ist es größer als 4 und ich
mach 1255 U/min drauß. Wäre das so in Ordnung, oder würdest du das
anders machen?

Gruß Avus

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Upsss.. da hab ich was falsch geschrieben. Natürlich will ich wenn
12"7"0 U/min ist das in 1250 U/min umwandeln. Habe das Problem jetzt
gelöst.

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also so ne Art beruhigte Anzeige oder zum einfachen ablesen, find ich
gut.
Einfach das 3. Digit vergleichen auf kleiner 8 und kleiner 3.
Ist es kleiner 8 dann das 3. Digit auf 5.
Ist es größer, also nicht der Fall, also >= 8, das 3. Digit auf 0 und
das 2. Digit um 1 erhöhen.
Aber was ist, wenn das 2. Digit bereits 9 hat (Überlauf (von 9 auf 0
springt))?
Dann muß das 2. Digit auf 0 gesetzt werden und das 1. Digit um 1 erhöht
werden.
Brauchst dazu eine verschachtelte Rundungsfunktion für die 3. Stelle
die auch die 1. und 2. Stelle beeinflussen kann.
Wie hast Du das gelöst?

Gruß
Andi

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ginge das vielleicht so?
Vor/bei der ganzen Rechnerei 3 Subtrahieren und dann statt Runden nur
Abschneiden. (unter 5 ist 0, über 5 ist 5)

...

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das paßt!
Ist schon spät, zu komplex gedacht.

Gruß
Andi

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja, das mit dem subtrahieren braucht man glaube ich nicht.
Einfach vor der LCD-Ausgabe prüfen, ob die vorletzte Stelle kleiner
'5' ist.
Wenn, dann ne '0' draus machen, wenn nicht, dann ne '5':

 cpi r17,'5'
 brlo Kleiner5
 ldi r17,'5'
 rjmp WarGrößerGleich5
Kleiner5:
 ldi r17,'0'
WarGrößerGleich5:
 ldi r16,'0'           ;Das letzte Digit dann noch auf '0'
 ....

oder so ähnlich.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Andi, habe es gestern noch so gelöst:

       cpi r17, '5'; vergleiche R17 mit Zeichen 5
       brlo null   ; wenn kleiner, dann springe zu null

       ldi r17, '5'; wenn größer, dann lade Zeichen 5
       rjmp digit
null:
       ldi r17, '0'; wenn kleiner, dann lade Zeichen 0
digit:

Eigentlich könnte ich es ja auch in einem Timer laufen lassen.
Nur fehlt mir da der Ansatz, wie ich es mache. Muß dabei das ganze
Programm in den Timer Interrupt kopiert werden und beim Hauptprogramm:

Loop: rjmp Loop

stehn?

Oder muß ich in dem Timer nur die berechungen für den ADC machen und im
Hauptprogramm immer ans LCD schicken?

Geht das mit dem Overflow Timer?

Was für einen Timer brauche ich (8 Bit glaube ich) und was für einen
Teiler sollte man da nehmen?

Oder z.B. könnte ich jetzt eine Digitaluhr spielendleicht machen. Wie
sieht das dann da aus? Mache ich da im Hauptprogramm immer die
Berechnungen, was er anzeigen soll und im Timer nur ein Register
inkrementieren, oder wie sieht das da dann aus?

Wie kann ich ausrechnen, das alle Sekunden ein Timerinterrupt
stattfindet?

Wenn das Programm im Timerinterrupt ist, werden da die Programmschritte
auch mitgezählt, oder hält da der Timer an, weil ja das sei
(Interruptbyte) ausgeschaltet wird, damit kein anderer Interrupt
stattfinden kann.

Fragen über Fragen. Ich weiß, es gibt ein Datenblatt von Atmel... aber

mein Englisch...

Kennt jemand einen Link, da wo die verschiedenen Timer erklärt werden
und auch Testprogramme dabei sind? Weil bei Testprogrammen lerne ich am
leichtesten, weil ich dann den Ablauf verstehe, wenn ich ihn sehe.

Danke im voraus

Gruß Avus

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das jetzt so im Forum recht schwierig zu erklären.
Falls du ne ICQ Nummer hast, dann kann man das Timerhandling mal P2P
durchsprechen.

cu
Hauke

Autor: avusgalaxy (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Hauke. Nehme das Angebot gerne an. Werde mich in nächster Zeit mal
melden. ICQ Nummer? Schick ich dir per mail..

Habe jetzt mal ein Programm geschrieben. Sollte eine Digitaluhr
werden.

Hab mir das mal so zusammengebastelt. Den Timer habe ich irgenswo aus
dem Forum,

Nur wie muß ich das Programm umschreiben, damit die Zeit am Display im
Sekundentakt hochläuft? Habe mir vom Peter die genaue Sekunde
angeschaut, doch da blicke ich nicht durch. Peter ladet da 256 in ein
Register, warum? Ein Register hat ja nur 8 Bit, oder?

Vielleicht kann mir jemand helfen.

Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Avus...

Ohne Datenblatt kommst du nicht weiter. Du wirst dein Englisch also
aufbessern müssen. Muss(te) ich auch, wir hatten in den 50er und 60er
Jahren kein Englisch, nur etwas Russisch. Und ohne ein dickes
Englisch-Deutsch-Wörterbuch verstehe ich die Datenblätter auch nicht.
Das ist zwar mühsam, aber notwendig. Also tu selbst mal was und fang
selbst an, Datenblätter zu lesen, lass nicht immer Andere deine Arbeit
erledigen.

Gruß...
...HanneS...

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ah, hab ich gesagt, das du mir ein Programm schreiben sollst?

Ich habe mir selber Gedanken über die Digitaluhr gemacht und das (fast)
fertige Programm dazugegeben. Für Dich mag es ein Kinderspiel sein,
sowas zu machen, aber andere Leute fällt das schon ein bisschen
schwerer.

Ich bräuchte ja nur einen Denkanstoss. Dabei glaube ich nicht, das du
(andere) mit einem guten Tip dann meine Arbeit erledig(st)(en).


Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Avus...

Meine Reaktion bezog sich auf diesen Abschnitt von dir:
-----
Fragen über Fragen. Ich weiß, es gibt ein Datenblatt von Atmel... aber

mein Englisch...
-----
Und deine Fragen beweisen, dass du kaum ins Datenblatt rein schaust.
Für mich ist es auch kein Kinderspiel, aber ich versuche erstmal mit
dem Datenblatt weiter zu kommen, auch wenn es schwer fällt. Ich könnte
es mir auch leicht machen und einfach hier fragen. Aber erstens ist das
nicht mein Stil und zweitens ist der "Anfänger-Bonus" irgendwann
aufgebraucht, dann bekommt man keine Fragen mehr beantwortet, die man
selbst mit Hilfe des Datenblatts hätte klären können.

Viel Erfolg...

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Und deine Fragen beweisen, dass du kaum ins Datenblatt rein schaust"

Im Datenblatt steht meißtens, welche Bytes man wo setzen und löschen
kann und was man damit machen kann.

Nur wie man es dann im Programm sinvoll anwendet, damit man zu einem
Ergebnis kommt, davon kann ich nicht viel finden.(Überhaupt, wenn man
nochnie mit Timer gearbeitet hat)

"Aber erstens ist das
nicht mein Stil und zweitens ist der "Anfänger-Bonus" irgendwann
aufgebraucht, dann bekommt man keine Fragen mehr beantwortet, die man
selbst mit Hilfe des Datenblatts hätte klären können."

Willst du damit sagen, daß wenn ich das Datenblatt auswendig lerne, daß
ich einwandfrei Assembler behersche und den µC zu 100 % ausnutzen
kann... Das glaub ich nicht....

Ich denke, programmieren hat viel mit Fantasie zu tun, weil was nützt
es mir, wenn ich alle Befehle auswendig kenne und dann nicht weiß, wie
man was machen kann.

Am Anfang ist es wichtig, das man mal die Grundsachen
beherscht...(Timer, ADC, PWM, LCD, rechnen) Erst wenn man das ein
bisschen beherscht, dann kommt die Fantasie dazu, um tolle Programme zu
entwickeln, weil man dann Timer, ADC, PWM, LCD und rechnen miteinander
verbinden kann. Nur wenn man noch nie mit einem Timer gearbeitet hat,
dann hilft das Datenblatt auch nicht weiter. Wenn man den 8 Bit Timer
erstmal versteht, dann ist es sicher kein Problem, die Informationen
zum 16 Bit Timer aus dem Datenblatt zu holen, weil ja dann die
Grundkenntnisse schon da sind.

Verstehst du mich?

Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verstehe dich sogar recht gut.

Trotzdem fällt mir da erstmal ein Zitat ein (der Zitierte möge mir
bitte verzeihen...):

----->8-----

Also als wir noch Kinder waren, teilweise sogar noch als Jugendliche,
hat uns so mancher (Erwachsener) das Sprichwort: "Betroffene Hunde
bellen!" um die Ohren gehauen. Das hat bei uns meisten einen gewissen
Gegenprotest hervorgerufen, weil stets ein Quäntchen Wahrheit dran
war.

-----8<-----

Übrigens: Datenblatt auswendig nutzt garnix. Es geht da eher ums
Verstehen. Aber tröste dich, ich vertehe es auch nicht beim ersten
Lesen. Ich konzentriere mich jeweils auf die Dinge, die ich gerade
benötige. Aber ich beschäftige mich damit, auch wenn es schwer fällt.

Frohes Schaffen...

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@avusgalaxy:
Wird mal wirklich Zeit, das Du Dir gedanken über "Algorythmik" mast,
also über Vorgehensweisen mit dem was man zur Verfügung hat.
Fang doch mal mit einer Routine an mit der Du ganze Ketten von Zeichen
im Flash (Zeichenketten oder auch Strings) an das LCD ausgeben kannst
aber probiers komplett selber.
Z. B. übergibts Du der Routine die Startadresse der Zeichenkette in den
Z-Pointer und die Routine (Unterprogramm) gibt die Zeichenkette Zeichen
für Zeichen aus.
Mach Dir mal Gedanken drüber wie man das macht.
Es gibt auch die Methode von Diagrammen in der man erst mal grafisch
darstellt, welche Schritte nach welchen Schritten zu erledigen sind.
Ohne Algorythmik nutzt Dir die komplette Kenntnis eines µC (Register,
Befehle) nicht sehr viel.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi ihr zwei. Dann werde ich mich mal bemühen, euch nicht wegen Sachen,
die im Datenblatt stehen zu nerven...Werde so gut es geht, mein
Englisch einsetzen.

Habe nur noch 2 Probleme, um meine Digitaluhr zu verwirklichen:

1.) der Timer...

Wie er jetzt funktioniert, hab ich geschnallt(Timer 0).
Habe mir heute den ganzen Tag überlegt, wie ich mit dem Vorteiler und
dem Timer auf 1 Sekunde komme.(ohne Rest.) Bin auf folgendes gekommen:
8MhZ
1s = 1000mS ; 8 000 000 Hz....1000ms / 8 000 000 = 0,000125 mS
0,000125 mS ; 1 Takt..........Vorteiler=256 (0,000125*256)
0,032 mS    ; 256 Takte.......TCNT0=125 (0,032*125)
4ms         ; alle 32000 Takte 4 mS wird der Timer aufgerufen.

Stimmt das bis jetzt, oder bin ich auf dem Holzweg?

Um aus den 4 mS eine Sekunde zu machen, dekrementiere ich ein Register
(250), bis es null ist. Wenn es noch nicht null ist, dann verläßt das
Programm den Timer.
OK.
4 mS * 250 = 1000 mS also eine Sekunde.

Am Anfang des Timers setze ich noch das TCNT0 neu, damit das Timing
auch passt.

Nur wenn ich das Programm teste, dann braucht die Sekunde am Display 5
Sekunden(@8 MhZ). Wo ist da der Fehler?

2.) @ Andi
Eigentlich wollte ich es mit

.db "   "
machen. Nur komm ich nicht drauf, wie man dazwischen Register einfügen
kann. Also so:

.db "   ",h1,h2,":",m1,m2,":",s1,s2,0

Verstehst du, was ich meine? Ist das Überhaupt möglich?

Gruß Avus, und sorry wegen gestern...

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Läuft dein AVR mit 8Mhz?? - Wirklich??? - Nachgemessen???? (Fuse?)

Ansonsten läuft Timer0 nicht runter sondern hoch. Willst du 125, dann
musst du 125 vor Überlauf einstellen. Das wäre dann 256-125. Da dies
aber nicht allzuweit von 125 entfernt ist, wird es daran alleine nicht
liegen.

Mit Vorteiler 256 und Zählumfang 125 kommst du schon auf 4ms, liegst
also richtig.

Ansonsten rate ich dir nicht einfach drauflos zu programmieren, sondern
erstmal zu versuchen, anderer Leute ihre Quelltexte zu analysieren und
zu verstehen, warum das so und nicht anders gemacht wird. Dann würdest
du etwas über das Sichern des SREG erfahren, würdest feststellen, das
der Timer etwas "holperig" arbeiten kann weil die Int-Aufrufzeit
unterschiedlich sein kann (und was man dagegen tun kann). Und die
vielen kleinen Stolpersteine, von denen im Wiki schon ein großer Teil
aufgelistet ist.

...

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit den Zeichenketten mit einer Routine vom Flash zum LCD war jetzt
nicht für die Darstellung der Uhrzeit gedacht.
Du willst ja nicht nur die Uhrzeit oder Zahlen am LCD anzeigen sondern
auch ganz normale Texte wie "Uhrzeit: " oder vielleicht irgend wann
mal verschiedene Menüpunkte.
Und dafür jedes Zeichen mit 2 Befehlen auszugeben ist doch doof.
Das war als Anregung gedacht damit Du Übung bekommst, um einen
Algorythmus selbst zu 'kreieren'.
Ein Algorythmus hat nix mit den ASM-Befehlen zu tun.
Ein Algorythmus in ASM ist genau der gleiche Algorythmus wie in C,
Basic oder 8051-ASM wenn der das gleiche macht, nur mit
unterschiedlichen Möglichkeiten oder mehr oder weniger Komfortabel zu
erstellen.
Du kannst Ja auch die Routine zur Dezimalumwandlung so ändern, das
diese die LCD-Ausgabe gleich mit macht, aber versuchs auch mal allein,
auch, wenns ne Woche dauert.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Hannes, Hi Andi..

Die 8 Mhz stimmen...

@Andi

Mit db hab ich schon gearbeitet bzw, das LCD Programm so umgeschrieben,
daß ich es mit zl und zh und R0 dann auslesen konnte.

Ah ja, das mit .db "Uhrzeit",hh,0
funktioniert das irgendwie? Brauchst nur ja oder nein hinschreiben.

Danke

Avus

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>"Ah ja, das mit .db "Uhrzeit",hh,0
>funktioniert das irgendwie?"
Oh man, Du mußt noch viel lernen.

Gruß
Andi

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß, und du weißt es auch.

Gruß Avus

Autor: avusgalaxy (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi Andi, hi Hannes.

Wollte mal mein neues Programm hier reinstellen. Die Digitaluhr läuft
jetzt. In 24 Stunden geht sie allerdings 4 Minuten nach.

Sieht jetzt der Algorythmus besser aus, bzw. das Programm allgemein?

Habe jetzt sehr mit den Registern gespart und mehr mit dem S-RAM
gearbeitet. LCD Ausgabe mache ich immer gleich nach den Berechnungen.

Und .db ist auch Dabei.

Passt das jetzt besser?

Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nunja, selber schuld. Du wolltest es ja wissen...

Also mein zweites Programm sah auch nicht besser aus. Eher schlechter,
denn ich hatte nur "selbstgeschriebenen und verstandenen" Code drin.
Ich gehe trotzdem mal davon aus, dass du jede Zeile in deinem Code
verstehst, die einfachen selbstgeschriebenen genauso wie die
hochoptimierten von Peter...

Aber das gesamte Programm konnte ich nicht begutachten, denn es ist ja
nicht vollständig. Da fehlen ja noch die LCD-Routinen, die du per
Include einbindest und in der ISR aufrufst.
Und genau da sehe ich ein Problem. Du hast nämlich gegen die drei
goldenen Regeln der Interruptprogrammierung verstoßen:
http://www.mikrocontroller.net/forum/read-1-130140...

Denn du rufst aus der ISR die LCD-Routinen auf, von denen ich annehme,
dass sie Warteschleifen enthalten. Das ist tödlich, denn das dauert so
lange, dass einige Interrupts "verschlafen" werden.

Teste das doch mal im Simulator, besonders die Situation, wenn sich
Sekunde, Minute und Stunde ändern, also die meisten LCD-Zugriffe
stattfinden. Ich möchte wetten, dass diese ISR länger als 4ms braucht.
Das wird die Ursache für das Nachgehen sein. Obwohl du nicht übermäßig
viel Genauigkeit erwarten solltest.

Abhilfe (Vorschlag):
Im SRAM einen Bereich definieren, in dem die gesamte (aufbereitete)
Ausgabezeile steht. Erreichst du am einfachsten, wenn du in INIT den
Ausgabestring aus dem Flash ins SRAM kopierst.
In der ISR werden dann nur die Ziffern aktualisiert, mehr nicht.
Zusätzlich wird in einem (oberen) Register ein Flag gesetzt, das dem
Hauptprogramm sagt, dass sich die Zahlen geändert haben.

Im Hauptprogramm fragst du das Flag ab. Ist es gesetzt, dann gibst du
den gesamten String aus dem SRAM an das LCD aus, löscht das Flag wieder
und schickst den AVR schlafen (Idle-Mode). Ist das Flag nicht gesetzt,
dann schickst du ihn gleich schlafen.
Der Sleep-Mode bewirkt, dass der Timeraufruf präziser erfolgt. Das ist
zwar bei deinem Programm aufgrund des großen Vorteiles nicht so
wichtig, sollte man aber trotzdem tun.
Da nun dein Hauptprogramm auch Register nutzt, wird es jetzt wichtig,
in der ISR das SREG zu sichern.

...

Autor: avusgalaxy (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Halli Hallo.

Du hast recht, Hannes, da hab ich ja viele Fehler gemacht. Habe dann
zum Probieren die LCD-Ausgabe ins Hauptprogramm geschrieben, doch ohne
erfolg, weil der Befehl "rcall lcd_null" mehr als 4ms braucht. Ich
glaube, er braucht bei mir ca. 10 ms.

Jetzt hab ich mich für den 16 bit Timer (50 000 Zyklen)entschieden, 8
als vorteiler--->400 000 Zyklen bis zum Überlauf, und im Timerinterrupt
einen Teiler von 20...400 000 x 20 = 8MhZ..

OK.
Habe am Anfang das mit dem S-Ram gemacht. Der µC ließt die db Adresse
einzeln aus und speichert sie sofort ins S-Ram. 0x0060 ist der
Startwert des LCD's.

Den Idle-Modus hab ich auch aktiviert... Wußte garnicht daß das geht.
Ich dachte, der µC wacht nur bei ext. Interrupts auf. Danke

Als erstes nach dem Init ruf ich den Timer auf, damit die berechneten
Werte gleich ins S-Ram gespeichert werden.

Im Timer setzte ich dann das T-Flag (zum Schluss), das ich dann im
Hauptprogramm auslese. Wenn nichts berechnet wird, wird das T-Flag
nicht gesetzt.Wenn es gesetzt ist, wird das LCD aktualisiert, indem ich
wieder einzeln das S-Ram auslese und ans LCD schicke.

Ist es jetzt besser als vorher? Ich vertrag die Wahrheit. Also raus
damit..:-)

Ah ja, vielen Dank für die guten Tips mit S-RAM , sleep und so...

Gruß Avus

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das letzte Programm noch nicht angesehen, da das sehr viel Zeit
kostet, die ich jetzt nicht habe.

Das T-Flag ist dazu eigentlich Blödsinn.
Jedes gute Programm, das einige Arbeiten im Timer-Int erledigt, andere
im Hauptprogramm, braucht ein Register, mit dem Hauptprogramm und ISR
miteinander kommunizieren können. Ich nenne dieses Register (eines der
oberen, damit man "billig" Bits setzen und löschen kann, also
r16...r23) meist "flags" oder "mode". Die 8 Bits können dann
unterschiedliche Aufgaben signalisieren. Sie bekommen dann
dementsprechende Namen. In der ISR wird das jeweilige Bit gesetzt, in
der Mainloop wird es geprüft, gelöscht und abgearbeitet. Die
Abarbeitung darf sogar länger dauern als Zeit zwischen 2 INTs ist, da
nur jeder 250. Int das Flag setzt. Dann unterbricht der Int eben die
Abarbeitung, sie wird nach Verlassen der ISR dort, wo sie unterbrochen
wurde, fortgesetzt. SREG-Sicherung in der ISR vorausgesetzt, aber das
ist ja selbstverständlich, oder?

Besser ist jedoch, wenn man sich eigene LCD-Routinen schreibt, die
keine Warteschleifen enthalten und stattdessen mit dem Timer-Int
synchronisiert werden. Mittels einer Zustandsvariable (Register) kann
sich diese Routine merken, was sie schon getan hat bzw. was sie in der
"nächsten Runde" tun muss. Somit entfallen die Warteschleifen, die ja
nur sinnlos Prozessorleistung verheizen. Die LCD-Routinen sollten nicht
in der ISR laufen sondern im Hauptprogramm. Ein weiteres Flag in
"flags" (oder "mode") kann die Synchronisation übernehmen. Die
Timer-ISR setzt es alle x Durchläufe, wobei x der erforderlichen
Verzögerung entspricht (lieber etwas größerer Abstand, du kannst eh'
nicht so schnell lesen). Die LCD-Routine löscht dann dieses Flag
wieder. Mit dem LCD-Zustandsregister wird dann ermittelt, ob und was
die Routine tun soll.
Das ist aber schon höherer Stuff, habe ich auch noch nicht realisiert,
das liegt aber daran, dass ich derzeit nix mit LCD mache.

Wenn ich Zeit gefunden habe, deinen neuen Quelltext zu analysieren,
dann melde ich mich nochmal.

...HanneS...

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Hannes. Danke für die schnelle Antwort. Ich dachte mir, ich nehme das
T-Flag her, da es bei meinem Programm sowieso nicht benützt wird.
SREG hab ich leider nicht gesichert.

Verstehe ich das richtig=?

Am Anfang des Programmes sollte der Timer schon laufen. R16 ist dabei
0x00. Im Timer wird R16 immer inkrementiert. Vor dem Hauptprogramm
Frage ich dann ab, welchen Wert R16 beinhaltet. Wenn es 0x01 ist, dann
soll es das LCD Initialisieren, wenn es 0x02 ist, dann soll es das LCD
löschen.
Das mach ich dann solange, bis das LCD bereit ist.... Äh, is glaube ich
noch zuhoch für mich.

Was machst du gerade? Grafik Displays?

Gru0 Avus

Autor: ...HanneS... (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du kein SREG sicherst, dann macht dein Hauptprogramm Mist, da die
ISR dem Hauptprogramm die Flags unterm Ar..(Hintern) verändert.

Grafik-LCDs interessieren mich nur im Textmode. Zur Zeit mach ich aber
garnix mit LCDs. Habe noch genügend andere Projekte mit kleinen AVRs.
Einen Teil findest du bei www.hannes.de.md.
Das heißt aber nicht, dass ich mich noch garnicht mit LCD beschäftigt
hätte (Anhang).

...

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi avusgalaxy
Ich hab mir mal dein Prog angesehen aber den Thread nicht sonderlich
genau verfolgt.

Ich hätte da ein paar Vorschläge.

Zum einen wäre da die Überlaufprüfung (ich nehme einfach mal die von
der Sekunde aber die anderen gehen equivalent)

du hattest in deinem Code:

;Sekundenausgabe
sek:
  lds    temp,    sekunde
  cpi   temp,   60;Wenn 60 dann
  brne   sek_ausgabe
  clr   temp    ;Sekunde 0
...

statt dessen könnte man folgendes schreiben:
  lds    temp,    sekunde
  cpi   temp,   60;Wenn >=60 dann
  brlo  sek_ausgabe
  subi   temp,    60;Sekunde -60

das würde die Zähler erheblich unempfindlicher machen.
Überleg mal was passiert, wenn durch Zufall  deine Sekunden bis 61
erreichen? (ich weiß daß das momentan nicht passieren kann)

Weiterhin komme ich mit deinem timer setup nicht ganz klar.
Du willst doch deinen M8 mit 8MHz betreiben.
Wenn man nun den Teiler in den CS1xs Bit auf clk/256 stellen würde
(CS1x=1 0 0)
Dann würde der timer nach 1 Sekunde auf 31249 stehen (nicht 31250 denn
er fängt ja bei 0 und nicht bei 1 an)
Wenn man jetzt den Timer1 im CTC mode betreibt, und das ICR1 bzw. OCR1A
register auf diese 31249 einstellt, dann würde tatsächlich nur jede
volle sekunde ein Interupt auf "Timer/Counter1 Capture" bzw. auf
"Timer/Counter1 Compare Match A" eintreten. Ein zusätzlicher Teiler
ist nicht notwendig.
Weiterer Vorteil wäre das sich durch den CTC mode der Timer sofort beim
ereichen der 31249 wieder auf null stellt.
Man braucht also gar nicht mehr direkt auf die TCNT1H und TCNT1L
zuzugreifen.

Als letztes würde ich die generelle Programmstruktur umändern.
Die Hex->BCD Routinen würde in die Darstellungsroutine vebannen.
Wieterhin würde ich zulassen, daß der Timer Interrupt aus der LCD
herraus aufgerufen werden kann.
Dazu müßte man den Inhalt der darzustellenden Daten Doppelpuffern
(doublebuffering).

Ich versuche m,ich mal durch den code zu wurschteln.

Cu
Hauke

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mich bereits durchgewurschtelt.
Mir gefallen auch diese und jene Stellen nicht, aber so richtig
sachlich falsch sind die meisten Stellen ja nicht.

Bei Beibehaltung der Original-LCD-Routinen gehört das Hochzählen der
Zeiten und die Ausgabe in die Mainloop, gesteuert von einem Flag,
welches in der Timer-ISR alle Sekunde gesetzt wird.

Die Timer-ISR würde ich bei 4ms lassen, aber mit Timer0, da Timer1
hierfür zu schade ist (ICP usw.). Die 4ms hätten den Vorteil, dass man
in dieser ISR noch nebenbei Tasten entprellen kann, denn irgendwann
kommt sicher die Idee, die Uhr auch stellen zu wollen. Mit 1s-INT-Takt
entprellt es sich schlecht. Nach dem Stellen der Uhr kommt sicher auch
der Wunsch, die Uhr als Wecker oder Schaltuhr nutzen zu können. Alles
Dinge, die sich sehr gut in eine 4ms-Timer-ISR einbauen lassen, nicht
aber in ein 1s-Intervall.

...

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Hauke. Danke für die vielen Tips.

Das mit der Sekundenausgabe ist so viel sicherer, wie du es schreibst.
Doch die Zeile mit "subi   temp,    60;Sekunde -60" würde ich doch
auf "clt temp" lassen, weil wenn es mal 61 ist, dann minus 60 ist
eins. Stimmt das?

Versuche schon die ganze Zeit, das mit dem Timer zu realisieren...
Zuerst:

  ldi temp, 1<<toie1  ; 00000100
  out TIMSK, temp  ; Timer 1 interrupt ein

Dann: Timer 1 = 32249

  ldi temp, timer1high
  out ocr1ah, temp
  ldi temp, timer1low
  out ocr1al, temp

Dann den CTC Mode und Teiler 256 einstellen:

  ldi temp, 0b00000100
  out tccr1a, temp

  ldi temp, 0b00001000
  out tccr1b, temp

und
  sei
Müßte doch stimmen, oder?

Fehlt da nochwas? Ich brings nicht zum laufen...

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Hannes... dann vergiss ich das mit dem 16 Bit Timer wieder.

Also dann (fast) alles raus aus timer 0. Nur den Teiler erhöhen und
wenn der Teiler auf 0 ist, ein Flag(register) setzen. Das mit der
Tastenentprellung klingt auch gut.

Ach Hannes, du hast geschrieben, das "sleep" bei mir nicht viel
bringt, weil ich so einen großen Vorteiler habe. Wäre da gut, wenn ich
garkeinen Vorteiler habe?

Gruß Avus

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Hannes
Ich habe ja auch nicht gesagt das die falsch sind.

Mit dem Entprellen hast du schon recht, aber es geht ja hier erstmal
darum, daß Timerhandling zu lernen.

Der Timer1 ist eigendlich wirlich zu schade, aber wenn man was richtig
aud die beine stellen will dann nimmt man eh ne RTC von Dallas oder
Phillips oder nimmt nen async RTC-Timer im AVR mit Uhrenquarz.

Aber in einer sache muß ich dir wiedersprechen.
Das hochzahlen der Stunden, Minuten und Sekunden gehört auf jeden fall
in die ISR. Sich bei dieser Sache nämlich auf das Hauptprogramm zu
verlassen, provoziert geradezu eine ungenaue Uhr.

Nur die Umrechnung Hex auf BCD hat nun wirklich nichts dort verloren,
diese macht man am besten direkt vor der Ausgabe zum LCD.

cu
Hauke

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nööö...

Großer Vorteiler bewirkt (nebenbei), dass man viel Zeit hat, den Timer
auf Startwert zu setzen, denn er bleibt ja soviele Takte Null, wie der
Vorteiler groß ist. Du hast Vorteiler 256, also ist es egal, ob du den
Timer-Reload nach 7, 9 oder 15 Takten setzt. Bei Vorteiler 1:1 wäre das
schon ein gewaltiger Unterschied, da sollte man schon exakte
reproduzierbare Verhältnisse haben oder man muss den Timer einlesen und
den Reload dazu addieren.

Wenn du alles in die Mainloop legst, dann musst du im Int unbedingt das
SREG sichern und wiederherstellen.

Du brauchst irgendwann noch mehr (eigene) Flags, also solltest du ein
Register (r16...r23) dafür reservieren. Das erste Flag sagt, dass die
Sekunde voll ist (Zählerstand 250=0). Das nächste könnte in der ISR bei
Zählerstand 125 gesetzt werden, worauf die Mainloop den (oder die)
Doppelpunkt(e) auf dem Display durch Leerzeichen überschreibt, was das
Blinken des/der Doppelpunkte(s) bewirkt (das wolltest du doch schon
immer, oder etwa nicht???).
Wenn du die "Variablen" Sekunde, Minute und Stunde in drei unteren
Registern führst, sparst du dir SRAM-Zugriffe. Da du dort nicht mit
Konstanten vergleichen kannst (cpi), schau dir mal cpse an. Der
Vergleichswert wird dann vorher in ein oberes Register (tmp)
geschrieben. Dabei würde ich zuerst alle Zählumfangsbegrenzungen (Sek,
Min, Stunde) abarbeiten, dann erst die ASCII-Umwandlung und
Aktualisierung des im SRAM liegenden Ausgabestrings. Denn die
Vergleichsreferenz für Sek und Min ist 60 (braucht nur einmal gesetzt
werden), für Std dann 24.

...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Hauke

"Der Timer1 ist eigendlich wirlich zu schade, aber wenn man was
richtig
aud die beine stellen will dann nimmt man eh ne RTC von Dallas oder
Phillips oder nimmt nen async RTC-Timer im AVR mit Uhrenquarz."

Geht astrein.
Der Timer ist doch zum Benutzen da.
Aber unnütz extra Hardware zu verschwenden, das wäre wirklich schade
ums Geld und den Platinenplatz.


"Das hochzahlen der Stunden, Minuten und Sekunden gehört auf jeden
fall
in die ISR. Sich bei dieser Sache nämlich auf das Hauptprogramm zu
verlassen, provoziert geradezu eine ungenaue Uhr."

Na aber Hallo !
Oftmals habe ich auch ein Userinteface, d.h. die Hauptschleife wird
immer unter 1s durchlaufen.
Da ich keine Sanduhren darstellen kann (und will), muß der Nutzer
sofort eine Reaktion auf einen Tastendruck erkennen können.
Und damit ist das Sekundenzählen so sicher, wie die Bundesbank.
Ich mache es ausschließlich so, seit etwa 15 Jahren und habe nie auch
nur eine Sekunde verloren.


"Nur die Umrechnung Hex auf BCD hat nun wirklich nichts dort
verloren,
diese macht man am besten direkt vor der Ausgabe zum LCD."

Warum denn nicht ?

Ich richte mir oft einen Zeichenspeicher ein, wo alles sofort
eingetragen wird. Und dieser Zeichenspeicher wird etwa alle 0,2..0,5s
komplett an das LCD übertragen.
Damit verhindert man ein Flackern bei schnell wechselnden Werten und
der Nutzer ist in der Lage, die Werte auch abzulesen (Ergonomie).
Den Trick habe ich mir vom Multimeter abgeguckt, da werden auch nur
maximal 2..5 Meßwerte je s angezeigt.


Peter

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Hauke:

Dein Einwurf betreffs Genauigkeit und RTC ist berechtigt. Wenn du aber
mal weiter oben liest, stellst du sicher fest, dass ich meine Aussage
zur Genauigkeit bereits gemacht habe. Du rennst also offene Türen ein.

Du meinst, dass das Hochzählen der Sekunden, Minuten und Stunden in die
ISR gehört. Nunja, wenn man bei den Hundertstel Sekunden beginnt, dann
auf alle Fälle.
Ich glaube aber nicht, dass die Mainloop das Flag verpennen könnte, das
nur alle Sekunde einmal gesetzt wird. Selbst wenn die LCD-Routinen ihre
Warteschleifen behalten, dürfte das unmöglich sein. Da muss man schon
derben Stuss programmieren...

...

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, jetzt weiß ich dann wirklich nicht mehr, was richtig und was falsch
ist.

Avus

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt kein richtig oder falsch, nur manche Sachen machen mehr Probleme
als andere.

Deshalb habe ich dir ja angeboten das man sich per icq mal unterhält.

P.S.
Die Modifikation von deinem Code hab ich fertig.
Bin sie nur grade am testen. Dann schick ich sie hier.

cu
Hauke

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Hauke, auf Dich hab ich ja ganz vergessen...

Du bist leider Offline im ICQ

Gruß Avus

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nicht wirklich offline
nur unsichtbar

Ich bin es leid Werbung über ICQ zu bekommen

cu
Hauke

Autor: Hauke Sattler (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
OK

Die Uhr läuft =8)

Source im Anhang

Falls du noch Fragen hast
meine ICQ# ist: 1905682

cu
Hauke

Autor: Hauke Sattler (Gast)
Datum:
Angehängte Dateien:
  • uhr.prj (900 Bytes, 124 Downloads)

Bewertung
0 lesenswert
nicht lesenswert
P.S.
Im Anhang hab ich noch nen *.prj File für VMLAB reingetan

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Hauke. Das Programm sieht ja sehr gut aus.

Da hab ich wohl ein paar überflüßige Sachen gemacht. Vielen Dank.

Was kann ich mit der .prj File machen?

Gruß Avus

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich entnehme aus deiner frage, daß du vmlab nicht kennst.

VMLAB ist eine sehr gute Programmierungs und Simulationsumgebung.

Es gibt auch eine freie (in der codegröße beschränkte) Testversion.

Zu finden ist das prog unter www.amctools.com

Das praktische ist, daß das Prog nicht nur den AVR simuliert sondern
auch das drumherum um den AVR.

z.B. RS232 Geräte, I2C Bausteine, LCD Module, Taster, LEDs,
Wiederstände, Kondensatoren usw.

Das Projektfile dieht zur Definition dieser simulierten
Hardwareumgebung.

In dem oben genannten *.prj File habe ich halt ein 20*4 Char LCD Modul
eingebaut.

Ok so eine Simulation, ist vileicht nicht so schnell wie nen echter M8,
aber man kann genau sehen wo das Programm hängengebleiben ist.

cu
Hauke

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Hauke. Wie kann ich die Simulation im VMLAB ansehen? Bist
überhaupt online? (ICQ)?

Gruß Avus

Autor: Hauke Sattler (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Moin erstmal.
Ich war gestern nicht mehr lange online.

Ich hab noch nen paar Anmerkungen zu deinem Orginalcode, welche ich
gestern vergessen habe dabeizuschreiben.

Deine hex->BCD routine war zwar gut und richtig, aber du hattest noch
vergessen die BCD Zahlen in ASCII Zeichen zu verwandeln.
Ich habe dies mit in die Hex->BCD Routine reingepackt.

Deine Methode zur Erkennung des String-Endes für die LCD Daten ist zwar
recht elegant, aber sie braucht zwingend eine 0x00 am Ende des Strings.
Diese hast du auch bei den Uhrdaten angegeben.
.db "Zeit: 12:00:00",0,0

Nur die Routine welche die Uhrdaten ins RAM einließt hat einen
entscheidenen Mangel

anfang:
  lpm
  tst     r0
  breq     fertig
...
fertig:

Du testest direkt am anfang ob das aus dem Flash gelesene Zeichen eine
0 ist, und wenn ja dann bendest du die Schleife.
Das bedeutet, daß die für das Beenden der LCD Routine benötigte Null
gar nicht erst ins RAM geschrieben wird.
Man muß den Test ob es eine Null war ans Ende der Schleife setzen.

Ich habe im neuen code mal die ganze Sache von Timer1 auf Timer2
portiert. (Damit Hannes seinen Timer1 frei hat)

Weiterhin wird jetzt das SREG und die Register welche in der ISR
verwendet werden erst gesichert und am Ende zurück gelesen.
Das heißt die ISR kann dein Hauptprogramm nicht durcheinderbringen.

cu
Hauke

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Hauke...

> Deine hex->BCD routine war zwar gut und richtig, aber du hattest
> noch vergessen die BCD Zahlen in ASCII Zeichen zu verwandeln.
> Ich habe dies mit in die Hex->BCD Routine reingepackt.

Hat er nicht vergessen, war drin.
Schade eigentlich, dass du Peters hochoptimierte Bin->Ascii-Routine
nicht verstanden und daher so verunstaltet hast.

> Nur die Routine welche die Uhrdaten ins RAM einließt hat einen
> entscheidenen Mangel

Das stimmt. Diese Routine ist zu umständlich und kopiert die Null nicht
mit. Habe ich auch erkannt (auch ohne VMLAB), aber vorerst als
Pillepalle abgetan, da es schlimmere Bugs gab und ich schrittweise an
die Beseitigung herangehen wollte damit der Lerneffekt (und damit der
Weg zur Selbstständigkeit) nicht auf der Strecke bleibt. Das trifft
auch auf die anderen Stellen zu, in denen ("sicherheitshalber")
unnötige Befehle ausgeführt werden.

...HanneS...

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Räusper....

Sorry ich kann in seinem code Uhr2.asm die BCD->Ascii umrechnung partou
nicht finden.

Und was heißt hier eigendlich verunstaltet.

Ich habe Peters Routine sehr wohl verstanden, und hab auch noch einen
Fehler darin gefunden.
Die 3.letzte zeile muß
  subi  r30, -10 - '0'
lauten.

  subi  r16, -10 - '0'
  mov  r16, r30
wäre Unsinn weil R16 noch nicht definiert ist und
weil das um 10 erhöhte R16 sofort mit r30 überschrieben würde.

Ich bin von der Routene ausgegangen welche in Avus seinem Code war.

Es wurde halt lediglich die letzten beiden Digits von Peters Routine
verwendet und folgende Zeilen eingefügt:

mov    temp1,temp
um temp zu beizubehalten

subi     temp1,-58  ; =addi temp,(10+48) (48=ASCII 0)
subi     temp2,-48  ; =addi temp,48 (48=ASCII 0)
bcd->Ascii Umrechnung

Jetzt sag mir mal bitte wo da die Verunstalltung sein soll.

Und mit Pillepalle bezeichne ich nur sachen die Schönheitsfehler
produzieren. Sachen die den Code ins Nirvana laufen lassen nenn ich
anders.

cu
Hauke

P.S.
Hannes wenn du flamen willst dann bist du hier im falschen Forum.

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> P.S.
> Hannes wenn du flamen willst dann bist du hier im falschen Forum.

Will ich nicht, bin deshalb auch weg hier. Macht weiter.

...HanneS...

Autor: avusgalaxy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na, ja... Lassen wir das lieber... Vielen Dank für eure große Hilfe. Hab
durch eure Beispiele sehr viel dazugelernt.

@ Hauke...

Wie kann ich dich im ICQ erreichen=?

Gruß Avus

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Avus

Evt. muß ich dich Einladen.
Schick am besten mal deine ICQ# per mail.
Mal schauen ob das klappt.

cu
Hauke

Autor: Torsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schade um Deine Zeit HanneS.

Autor: Hauke Sattler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry
Aber erhätte seine Zeit ja nicht mit rumstänkern verplempern müssen.

cu
Hauke

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.