Forum: Mikrocontroller und Digitale Elektronik indizierte addressierung


von Peter B. (Gast)


Lesenswert?

hat jmd zu dem thema informationen, links. da ich nun den wert vom adc
einer tabelle zuordnen mag sodass er mir dann die temperatur
letztendlich schreibt die werte für die tabelle sind atm uninteressant.


also meine bisherige recherche ergab

das ich am anfang die anfangsadresse der tabelle setze und dann immer
den wert den der adc ausließt dazuzählt. somit dann in der richtigen
zelle ist (diesen Wert ausließt und meinetwegen in ein register
ausgibt) aber wie kommt er in die richtige zelle er muss ja spalte und
zeile auswählen.

ich würde mich über ein bspprog freuen

gruß Peter


PS: Programmierung erfolgt in Assembler (AVR-Studio 4), Microcontroller
wird der atmega8 verwendet

von crazy horse (Gast)


Lesenswert?

Mir fällts schwer, deinen Text zu lesen und zu verstehen.

von Olaf (Gast)


Lesenswert?

Stimmt, vielleicht waere es einfacher wenn der OP in Englisch schreibt.
Schliesslich koennen ja fast alle die sich mit Etechnik beschaeftigen
auch Englisch und es ist ja auch keine Schande wenn man als Auslaender
noch kein Deutsch kann.

Olaf

von Peter B. (Gast)


Lesenswert?

hm wo hast probleme was verstehst net, ich erkläre gern genauer.

die grundproblematik:
ich habe ein poti am adc Port eines Atmega8 hängen kann die register
ADCL ADCH schon wunderbar auslesen und auf ein lcd ausgeben (binär).
und nun möchte ich eine Datenbank anlegen die zu jedem Wert den der ADC
Port liefert einen bestimmten Datensatz besitzt. und dieser Datensatz
soll dann in ein register geschrieben werden und später auf dem lcd
ausgegebn werden.

ADC bekommt signal ---> atmega8 schaut nach Datensatz ---> schreibt den
passenden Datensatz in ein Register ----> atmega8 gibt dieses register
auf ein LCD aus ---> ich bin zufrieden

gruß peter

von johnny.m (Gast)


Lesenswert?

Tja, ein bisschen mehr Mühe mit Grammatik, Rechtschreibung (Deine
Shift-Taste scheint Ausfallerscheinungen zu haben) und Formulierung
solltest Du Dir schon geben. Ich weiß nicht, ob Du Dir vorstellen
kannst, dass es einem eventuell vorbeischlendernden Hilfswilligen
absolut keinen Spaß macht, sich das Geschreibsel überhaupt
durchzulesen...

von johnny.m (Gast)


Lesenswert?

...Das ist schon mindestens zwei Klassen besser...

von Peter B. (Gast)


Lesenswert?

Es tut mir leid, ich bin es vom Chatten so gewöhnt und schreibe meistens
ohne Punkt, Kommata und alles klein wenn ich im Internet unterwegs bin.
Aber ich werde mich bemühen.

gruß Peter

von johnny.m (Gast)


Lesenswert?

Du meinst also 'indirekte Adressierung' bzw. eine Lookup-Table. Was
verstehst Du unter 'Datensatz'? Wie viele Werte sollen da pro Index
abgelegt sein?

von Peter B. (Gast)


Lesenswert?

ich denke ein Wert pro Index würde für den Anfang erstmal reichen, um zu
lernen wie so eine "Lookup-Tabelle funktioniert.

@ jonny m. (wie du aus meinem letzten Thread weißt, bin ich noch
blutiger Anfänger und muss noch sehr viel lernen)

von Hannes L. (hannes)


Lesenswert?

So richtig verstanden habe ich dich immer noch nicht.

Möchtest du jedem ADC-Kanal einen Platz im Array reservieren und die
Augenblickswerte der Eingänge an verschiedenen Positionen des LCDs
anzeigen?

Möchtest du nur einen ADC-Kanal abfragen und die Werte in zeitlicher
Reihenfolge im Array (Tabelle) ablegen, um Tendenzen zu erkennen?

Möchtest du nur einen ADC-Kanal abfragen und dessen Wert am LCD
ausgeben? (dann brauchst du keine Tabelle/Array) Dann würde sich eine
Mittelwertbildung anbieten, um die Anzeige etwas zu beruhigen.

Zum Deutsch: Es ist schwer, solches Kauderwelsch zu lesen, die
Hilfsbereitschaft sinkt dadurch kollossal. Schlimmer jedoch ist, dass
man dadurch die Zusammenhänge nicht erkennt und nicht versteht, was du
meinst. Rechtschreibung und Grammatik helfen bei der Strukturierung der
Sätze und schaffen die Möglichkeit, Zusammenhänge eindeutig und
unmissverständlich zu beschreiben. Gelegentlich passierende
Rechtschreibfehler oder Buchstabendreher kritisiere ich ausdrücklich
nicht, das passiert Jedem mal. Aber wenn man Hilfe möchte, sollte man
schon vernünftige, unmissverständliche Sätze schreiben.

...

von johnny.m (Gast)


Lesenswert?

> ...zu jedem Wert den der ADC Port liefert einen bestimmten
> Datensatz besitzt.

Sieht mir nach einer klassischen Lookup-Table aus.

Du willst also nicht den ADC-Wert direkt ausgeben, sondern einen
anderen Wert (z.B. Kennlinien-Linearisierung o.ä.). Dazu musst DU
zunächst im Programmspeicher (FLASH) eine Tabelle von Bytes oder Words
anlegen, die für jeden Wert, den der ADC liefern kann, einen Wert
enthält. Das macht man z.B. so:

.cseg
ADWerte:
.db 0x01, 0x02, 0x03, ...

Auf diese Werte kannst Du dann mit Hilfe des Z-Pointers und des
lpm-Befehls zugreifen.

Ich muss jetzt kurz weg und hab deshalb grad keine Zeit für weitere
Erklärungen. Kannst ja in der Zwischenzeit schon mal schauen, ob Du mit
den Infos weiterkommst...

von Peter B. (Gast)


Lesenswert?

Ok ok ich werde mich bemühen. Ich lege an meinem ADC Eingang (ADC0 ein
Eingang) eine Spannung, die im Moment durch ein Poti500 verändernt
werden kann (später PT100 mit Opto davor) an. Nun möchte ich diesem
Wert der an ADC0 anliegt einlesen (was auch funktioniert) und diesem
einen entsprechenden Wert aus einer Tabelle zuordnen. Dieser Wert aus
der Tabelle soll dann auf ein LCD-Display (dessen Anstteuerung auch
schon klappt) ausgegeben werden.

gruß

der bemühte Peter

von Hannes L. (hannes)


Lesenswert?

Das heißt also, dass deine Tabelle im Flash liegt und zu jedem möglichen
Messwert einen (der Charakteristik des Sensors entsprechenden)
Anzeigewert enthält.

Dann schau mal hier:
http://www.hanneslux.de/avr/mobau/uiwa/uiwa.html

Es handelt sich zwar nicht um Anzeigewerte, sondern um (eine Art)
"Fehlerpunkte", aber das Prinzip ist das gleiche.
Man setzt den Z-Pointer auf den Anfang der Tabelle, addiert als Offset
den gemessenen Wert dazu, und liest dann per LPM den entsprechenden
Tabellenwert aus. Beim Setzen des Pointers bitte beachten, dass der
Adressraum im Flash wordorientiert ist (16 Bit), LPM aber
byteorientiert zugreift. Die relevante Programmsequenz findest du ab
Label "tim01b:".

Viel Erfolg...
...

von Christoph W. (christoph)


Lesenswert?

also nu mal ehrlich. Ich weiß nich, was eure ersten unqualifizierten
Antworten sollten ! Ich hab keine zwei Anläufe gebraucht um zu
verstehen, was er meint. Und wenn dann Posts kommen wie "Schreib doch
bitte in Englisch" oder "Achte auf Groß und Kleinschreibung" dann
hättet ihr euch die auch sparen können. Wenn ihr unbedingt auf solch
eine Klugsch*****-Art antworten müsst, dann tretet dem "Verein der
Wahrung Deutscher Sprache" bei. Die suchen immer solche Leute wie euch
!
Also johnny.m, Glückwunsch für deine ersten Posts. Die sind mindestens
2 Klassen besser als Kindergartenniveau. Mensch ! Hier kommen leute
her, die Fragen zu einem Thema haben und sich nich über etwaige
Schreibfehler zurechtweisen lassen wollen !
Und jetz nich schonwieder einen Streit in diesem Thread losbrechen !



So. Nun zurück zum Thema. Du legst mittels ".org 0xE00" eine Addresse
im FLASH-ab. Hinter diese schreibst du deine Wertetabelle (1024 Bytes
für 10 Bit). Wenn du den ADC ausgelesen hast, machst du folgendes :

ldi ZH,0x1C ; Byteaddresse des ersten Tabelleneintrages
ldi ZL,00
add ZL,reg_ADCL
adc ZH,reg_ADCH
lpm reg_out,Z

jetzt hast du in reg_out den Tabellenwert für deinen ADC-Wert. Willst
du 16 bits lesen passt du das folgendermaßen an :

ldi ZH,0x18 ; Doppelter Speicherbedarf
ldi ZL,0
add ZL,reg_ADCL
adc ZH,reg_ADCH
add ZL,reg_ADCL
adc ZH,reg_ADCH
lpm reg_out_L,Z+
lpm reg_out_H,Z+

und in der Tabelle steht dann zuerst das LOW, dann das HIGH-Word.
kannst du aber einfach durch vertauschen der LPMs umdrehen ...
Beide Tabellen sind so ausgerichtet, dass sie am Ende des FLASHs liegen
und 1024 Einträgeumfassen.

von johnny.m (Gast)


Lesenswert?

@Christoph:
Möglicherweise bist Du ein ganz schlauer, wenn Du aus dem Kauderwelsch
am Anfang sofort mehr als nur Vermutungen rausgelesen hast. Aber ich
habe versucht ihm zu helfen, und wenn Du meinst Du kannst das besser,
dann bitte sehr... Ob dem Opener das jetzt was bringt sei
dahingestellt, aber Deinen Kommentar über meine Postings hättest Du
Dir auch getrost schenken können, zumal Peter ja auch korrekt drauf
reagiert hat!

von Christoph W. (christoph)


Lesenswert?

ich stimme dir scho zu, dass das kein Text is, mit dem man ne Prüfung
bestehen kann aber der Inhalt kommt trotzdem durch ... am Anfang will
er, dass der ADC Wert in eine Temperatur übersetzt wird und was er in
der Mitte schreibt ist, was er bisher fand (was einer Lookup-Tabelle
entspricht) ...

solchen Zynismus kann man sich dann aber trotzdem sparen :
"Deine Shift-Taste scheint Ausfallerscheinungen zu haben"
"2 Klassen besser"

nu ja. ich hab wohl auch deutlich übers Ziel mit dem Post
hinausgeschossen ... tschuldige für den zu scharfen Schreibstil ...
lassen wirs dabei ...

von johnny.m (Gast)


Lesenswert?

Genau. Kein Streit...

von Hannes L. (hannes)


Lesenswert?

> Genau. Kein Streit...

Nagut, dann fühle ich mich eben nicht angegriffen...

;-)

...

von Peter B. (Gast)


Lesenswert?

so Jungs da is man mal kurz weg um was zu erledigen und scho gehts hier
ab wie Harry g !!! Is scho in Ordnung ich kann scho mit Kritik leben
und wenn des hier so gewünscht ist (groß und Kleinschreibung und
halbwegs geordnete Sätze), dann richte ich mich auch danach.
Schließlich will ich etwas von euch und net Ihr von mir. Kann ja in
anderen Foren und Chats weiterhin klein schreiben.

aber trotzdem danke christoph

Ich schau mir jetzt mal die letzten Posts genauer an.

danke soweit

gruß Peter

von johnny.m (Gast)


Lesenswert?

@Peter:
> Schließlich will ich etwas von euch und net Ihr von mir...
Bravo, Das ist die richtige Einstellung! Und ich glaube, auch Christoph
hat verstanden, dass es mir eigentlich nur darum geht, dass viele sich
sichtlich überhaupt keine Mühe mit der Formulierung ihres Problems
geben, andererseits aber erwarten, dass andere sich die Mühe machen,
aus dem Geschreibsel schlau zu werden. Es ist jedem selbst überlassen,
ob er sich diese Mühe über einen gewissen Punkt hinaus macht (wie
Christoph es offensichtlich getan hat) oder nicht.

Ich finde es auch nicht i.O., wenn manch einer nur kritisiert, aber
nichts Konstruktives zu vermelden hat. Wenn ich sehe, dass meine Kritik
fruchtet, dann bin ich auch durchaus bereit, 'sachdienliche' Hinweise
zu geben. Wenn nicht, dann halte ich das Maul.

In Deinem Fall hat die Kritik ja was gebracht, und deshalb habe ich
dann auch versucht, Dir ein paar konstruktive Hinweise zu geben,
nachdem Du Dein Problem etwas präziser erläutert hast.

Es geht eben nicht darum, dass in diesem Forum irgendetwas besonders
gewünscht ist, sondern eher darum, dass die Chancen, Hilfe zu erhalten,
signifikant besser liegen, wenn man gleich von Anfang an mit den
richtigen, vollständigen und verständlichen Infos rausrückt und eine
kleinschreibung ohne punkt und komma trägt eben nicht unbedingt zur
lesbarkeit bei...

Wenn ich irgendwo derartige Kritik anbringe (und das ist nicht wirklich
böse oder zynisch gemeint), dann auch nur, wenn das Thema des Threads
mich wirklich interessiert und ich mich auch an der Diskussion
beteiligen möchte. Andernfalls halte ich meine Finger von der Tastatur
fern...

von Peter B. (Gast)


Lesenswert?

so hab mir jetzt mal die Lösungsvorschläge angeschaut, des von Christoph
mit dem zeiger setzten und Position Errechnen is mir nun klar. Doch wie
springt er an die position (ich versteh net wie ich diese Tabelle
aufbauen muss).  hanneslux des bsp Programm is nicht schlecht, blos du
setzt den Zeiger wieder ganz anders als Christoph

ldi zl,low(uerrtab*2)      ;Pointer auf
ldi zh,high(uerrtab*2)     ;Spannungs/Error-Tabelle

warum eine subroutine mit 2 multiplizieren

ein zeile mit 10 datensätzen oder 16 und wie viele zeilen brauch ich
bei 16 wären des theoretisch 64. (wie gesagt einen 10 bitwandler der
adch und adcl auswirft (2x8 bits insgesam word mit 16 bits) aber nur 10
sind belegt).

Für eine kleine Erklärung wie diese Tabellen strukturiert sein sollen
wäre ich dankbar.

gruß Peter

von johnny.m (Gast)


Lesenswert?

Es wird keine subroutine multipliziert. uerrtab ist die Adresse (Marke)
des ersten Elements der Fehlertabelle. Das mit dem Multiplizieren mit 2
liegt daran, dass der Speicher Wortorganisiert ist, lpm aber auf
einzelne Bytes zugreift. In der Korrekturtabelle sind an jeder
Programmspeicheradresse zwei Bytes hintereinander abgelegt. Um auf
diese Bytes zuzugreifen, besitzt der Befehl lpm die Möglichkeit, mit
dem LSB des Adresszeigers (also Z) auf die einzelnen Bytes zuzugreifen.
Dazu wird die Wortadresse um ein Bit nach links geschoben (was einer
Multiplikation mit 2 entspricht). Wenn das LSB jetzt 0 ist, wird auf
das erste Byte zugegriffen, wenn es 1 ist, dann auf das zweite. So
lässt sich der Programmspeicher byteweise belegen.

von Peter B. (Gast)


Lesenswert?

also kuckt euch des jetzt mal bitte an ob ich des richtig verstanden
habe.


.db   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  <<<< DS 1 (adc  Wert0)
.db   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1  <<<< DS 2 (adc  Wert1)
.db   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0  <<<< DS 3 (adc  wert2)
.db   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0  <<<< DS 4 (adc wert3)
.db   0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0  <<<< DS 5 (adc wert4)
.db   0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0  <<<< DS 6 (adc wert5)
.db   0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0  <<<< DS 7 (adc wert6)
.db   0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0  <<<< DS 8 (adc wert7)

und wenn ich jetzt ADHL und ADCH einlese und insgesamt den wert 5 hat,
so springt er in die 5 zeile und gibt mir
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 aufgeteilt in high und lowbyte
zurück. Stimmt das jetzt soweit ?

gruß Peter

von Peter B. (Gast)


Lesenswert?

sry für den doppelpost

von johnny.m (Gast)


Lesenswert?

Wenn Du nach wie vor nur eine Zahl für jeden ADC-Wert ausgeben willst,
dann nicht!

Vielleicht nochmal zur Erläuterung:
Im Programmspeicher legst Du ein Segment an, in dem Du einzelne Bytes
speichern willst (Jedes durch Kommata getrennte Element in einer mit
.db eigeleiteten Zeile ist ein ganzes Byte!). Da der Programmspeicher
wortorganisiert ist (die dort i.d.R. abgelegten Befehle sind entweder
16 oder 32 Bit lang, weshalb eine Byte-Organisation keinen Sinn macht),
könnte man im Prinzip an jeder Adresse nur ein Byte ablegen, was mit
einer Speicherausnutzung von 50% sehr ineffizient wäre. Der lpm-Befehl
ermöglicht es aber, einzeln auf Low- und High-Byte der Worte
zuzugreifen, indem er die Adresse künstlich verlängert und 'rechts'
vom LSB ein zusätzliches Bit einfügt, mit dem er entscheidet, ob das
Low- oder das High-Byte angesprochen werden soll. Auf die ursprüngliche
Wort-Adresse bezogen hieße das, es werden 'Halbschritte' eingefügt,
also im Prinzip zwischen den Wortadressen (es folgen aus der Luft
gegriffene Beispiele) 1265 und 1266 eine '1265,5', die dann nur die
letzten 8 Bit der Adresse 1265 anspricht.

Wenn man jetzt den Z-Pointer auf das erste Element der Tabelle zeigen
lässt (das LSB des Z-Pointers ist 0), erhält man mit lpm genau dieses
erste Element, welches den höheren 8 Bit des Wortes an der Stelle
entspricht. Erhöht man den Z-Pointer jetzt um 1 (das LSB von Z ist
jetzt 1), dann erhält man die 8 LSB des Wortes. Und noch mal 1
dazuaddiert (dann ist das LSB des Z-Pointers wieder 0 und der Rest von
Z um 1 höher als am Anfang) und man erhält die 8 MSB des nächsten
Wortes.

Für Deine Anwendung heißt das zunächst, dass Du den Z-Pointer auf den
Anfang der Tabelle zeigen lässt, wie es oben beschrieben ist.
Anschließend musst Du nur noch den Wert aus dem ADC zum Z-Pointer
dazuaddieren und Du erhältst mit lpm den Wert an der entsprechenden
Stelle. Wenn der ADC also z.B. den Wert 200 liefert, dann addierst Du
die 200 zu dem Z-Pointer hinzu und Du erhältst das 201. Byte (Das erste
hat die Nummer 0!) von der Ursprungsadresse an gezählt.

Ich hoffe, das ist nicht zu viel auf einmal und hilft Dir weiter...

von Peter B. (Gast)


Lesenswert?

hm komm grad ganz schön ins schwitzen ^^, aber so wollen wir das ja. Ich
steh scheinbar voll auf dem schlauch.

dann sind praktisch bei meinem bsp immer 16 bytes in einer zeile oder
?
aber wie spring ich da von einem byte auf des nächste nach rechts ?
indem ich zu dem Z-Pointer 1 hinzuaddiere ? und wenn ich am Ende der
Zeile bin dann springt er in die nächste und zählt weiter ?

dann ist die Tabelle praktisch aufgebaut wie folgt (die zahlen geben
die Werte des ADC's an

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
33,34......

gruß Peter

von johnny.m (Gast)


Lesenswert?

Die Zeilen haben keine programmtechnische Bedeutung. Die Tabelle ist von
der ersten Adresse fortlaufend, Byte für Byte. Du musst nur immer drauf
achten, dass in jeder Zeile eine gerade Anzahl Bytes steht, weil bei
einer ungeraden Anzahl das letzte in einem eigenen Wort gespeichert
wird, auch wenn die nächste Zeile wieder mit .db beginnt.

Konkretes Beispiel:

.cseg
uerrtab: .db 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7
         .db 8, 8, 8, 9, 9, 9, 10, 10, ....   ;usw...

; Z-Pointer initialisieren, auf erstes Element von uerrtab zeigen
ldi zl,low(uerrtab*2)      ;Pointer auf
ldi zh,high(uerrtab*2)     ;Spannungs/Error-Tabelle

;...ADC auslesen (gehe mal von 8 Bit Auflösung, left adjusted aus)
in r16, ADCH
ldi r17, 0
add zl, r16
adc zh, r17   ;in zh und zl steht jetzt uerrtab*2 + ADCH drin

lpm r18, z    ;lade Wert aus Tabelle in r18

Wenn der ADC z.B. den Wert 15 geliefert hat, dann steht in r18 am Ende
eine 7 drin (oben nachzählen, das 16. Element in der Tabelle, also das
mit der Nummer 15, ist eine 7).

Wenn Du mit jedem ADC-Wert zwei Bytes ansprechen willst, dann musst Du
den ADC-Wert, bevor Du ihn zum Z-Pointer dazuaddierst, mit 2
multiplizieren (also um ein Bit nach links schieben) und in zwei
Schritten die beiden dazugehörigen Werte aus der Tabelle holen (beim
zweiten einfach den Z-Pointer um 1 erhöhen). Bei mehr Werten
entsprechend, allerdings wird dann irgendwann der Speicher knapp...

von Peter B. (Gast)


Lesenswert?

so bin jetzt weg, geh jetzt nach Hause. Vielleicht schau ich heute Abend
noch mal vorbei, sont hald morgen wieder. Danke für eure Hinweise bis
jetzt.

Bis denn

Peter

von Peter B. (Gast)


Lesenswert?

ahhh jetzt hab ichs, ich glaubs zumindest gecheckt. Dann versuch ich
morgen mal, des an einem Experiment auszuprobieren. Ich seh scho, ich
muss nächstes mal echt klarer formulieren. Der letzte Post von jonny m.
der war der entscheidende.

gruß

Peter

von Hannes L. (hannes)


Lesenswert?

Nochmal zu meinem Beispiel...

Ich lese nur ADCH aus, weil ich in ADMUX linksbündige Ausrichtung
eingestellt habe und mir in dieser Anwendung die Auflösung von 8 Bit
genügt.

Jedes Element der Tabelle enthält nur ein Byte, die komplette Tabelle
enthält also 256 Einträge je 1 Byte. Das Addieren von 0..255 zum
Z-Pointer (der auf Tabellenanfang steht) adressiert dann ein beliebiges
Byte der Tabelle.

Lass dich nicht von der zweiten Tabelle irritieren, die Auswahl, welche
der beiden Tabellen benutzt wird, erfolgt woanders und hat mit der
eigentlichen Funktion der Tabelle nichts zu tun.

Du erwähntest den Begriff "Springen".
Hier wird eigentlich nirgendwohin "gesprungen", es wird nur der
Z-Pointer auf ein bestimmtes Byte innerhalb der Tabelle positioniert,
damit der Befehl LPM den Inhalt dieses Bytes nach r0 kopiert. Schau dir
dazu mal die Befehlsbeschreibung zu LPM an. Auch die Beschreibung der
Speicherarten und Adressierungsarten, die in jedem Datenblatt (recht
weit vorn) zu finden sind, sollztest du dir mal näher anschaun.
Vielleicht hilft das ja zusammen mit unseren Erklärungen zum
Verständnis.

...

von Christoph W. (christoph)


Lesenswert?

Als Anmerkung : Mit solchen Tabellen kannst du auch flugs Strings auf
dem Display ausgeben :

PRINT:
    lpm  value,Z+    ; Lädt Byte aus FLASH (Z-Addresse zählt autimatisch
weiter)
    cpi  value,0     ; ist das Byte 0 ?
    breq  PRINT_EXIT  ; ja - Null-terminierter String zu ende.
    rcall  LCD_DATA    ; ansonsten sende das Byte zum LCD
    rjmp  PRINT       ; und wiederhole von vorne.
  PRINT_EXIT:
    ret

Angesteuert wird das dann einfach per :

STRING:     .db   "Hello world",0  ; 0 zeigt das Ende des Strings
an.

ldi   ZH,HIGH(STRING*2)
ldi   ZH,LOW(STRING*2)
rcall PRINT



Das ist soweit die einfachste und effizienteste Methode um ein LCD zu
beschreiben und verdeutlicht am besten das lpm-Prinzip.

von johnny.m (Gast)


Lesenswert?

Kleine Ergänzung zu den letzten Postings:
Wenn der ADC mit höherer Auflösung als 8 Bit betrieben werden soll und
die auszugebenden Werte größer werden als mit 8 Bit darstellbar, dann
kann man (vorausgesetzt im Flash ist genug Platz dafür) die Werte auch
als 16-Bit-Worte ablegen und mit lpm in jeweils zwei Schritten Low- und
High-Byte laden. Dazu die Tabelle nicht mit .db sondern mit .dw
aufstellen. Das hat den Vorteil, dass man die 16-Bit-Werte (wie bei .db
auch in Dezimalschreibweise, also z.B. 654, 1376...) direkt eingeben
kann und nicht mit irgendwelchen Halbbytes rumspielen muss.

von Peter B. (Gast)


Lesenswert?

Ah hübsch, ich versuche im moment mir eine Routine zu schreiben mit der
ich dann, eine 3 stellige Dezimalzahl auf das Display ausgeben kann.
Das ich nur noch in meiner Tabelle eine Dezimalzahl hab und diese dann
auf dem Display ausgegeben wird. Weil die LCD routine die ich geklaut
habe dort kann man nur einzelne Zeichen ausgeben. Danke für die vielen
Antworten.

gruß

Peter

von johnny.m (Gast)


Lesenswert?

Stop! Die Möglichkeit der Eingabe als Dezimalzahl bezieht sich nur auf
die Schreibweise bei der Programmierung! Gespeichert werden die Zahlen
binär (hexadezimal) und müssen vor der Ausgabe als Dezimalstellen
selbstverständlich erst in BCD oder ASCII (je nach Art der Ausgabe)
umgewandelt werden!

von johnny.m (Gast)


Lesenswert?

...Zusatz: Wenn Du eine dreistellige Ausgabe im ASCII-Format benötigst,
solltest Du die Zahlen als gepackten BCD-Code speichern (im Prinzip als
Dezimal-Zahl eingeben, aber mit 0x davor). Dann musst Du in der
Ausgaberoutine die Bytes reinholen, der Reihe nach die Halbbytes (die
ja den Dezimalstellen entsprechen) extrahieren und in ASCII umwandeln
(also 0x30 dazuaddieren). Eine Tabelle sähe dann z.B. so aus:

tabelle:
.dw 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
.dw 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
;...
.dw 0x96, 0x97, 0x98, 0x99, 0x100, 0x101, 0x102, 0x103b ;...usw...

Dann hast Du in der Tabelle gleich die Dezimalstellen stehen. Wenn Du
allerdings nur 8-Bit-Werte vom ADC hast (also Dezimalwerte von 0..255),
musst Du beachten, dass diese Variante doppelt so viel Speicher
benötigt, wie die Abspeicherung der Hexadezimal-Werte (ein Wort, also
16 Bit pro Wert anstatt 8 Bit!). Dann ist es sinnvoller, die weiter
oben angesprochenen Varianten zu verwenden und die Umwandlung in
Dezimalstellen softwaremäßig in der Ausgaberoutine zu machen.

von Hannes L. (hannes)


Lesenswert?

Peter, schau dir mal an, wie andere Leute Daten an das LCD ausgeben.
(M)Ein Beispiel findest du hier:
http://www.hanneslux.de/avr/stopuhr/index.html
Alle LCD-spezifischen Routinen liegen in der Datei 'LCD_8x24a.inc',
alle Routinen zur formatierten Ausgabe liegen in der Datei
'LCDprinta.inc'. Diese beiden Dateien werden vom Hauptprogramm per
.include eingebunden. Werden nicht alle Ausgabeformen benötigt, so kann
man die nicht benötigten Macros und Routinen löschen. Sas mache ich aber
erst, wenn es im Flash eng wird, was im Beispielprogramm nicht der Fall
ist.

Anhand der vorigen Beiträge sehe ich, dass dir noch einige Basics
fehlen. Schau dich doch einfach mal in der Hilfe zum AVR-Studio um.
Über Menüpunkt help, tools, avr-assembler2, directives (oder so
ähnlich, habe jetzt nicht nachgeschaut) findest du die komplette
Auflistung und Erklärung zu allen zugelassenen Operatoren und
Directiven des Assemblers, ganz in der Nähe findest du den kompletten
Befehlssatz und noch vieles anderes Wissenswerte. Einfach mal etwas in
der Hilfe herumschmökern, die investierte Zeit amortisiert sich
schnell.

...

von Hannes L. (hannes)


Lesenswert?

Auch Johnys Vorschlag ist ok.

Allerdings müsste jetzt erstmal definiert werden, welchen Zahlenbereich
du überhaupt benötigst.

Auch müsste ermittelt werden, welcher Bereich am ADC überhaupt gemessen
werden kann. Es macht keinen Sinn, eine Tabelle mit 1024 Elementen je 2
Bytes zu erstellen, wenn der 'ADC-Messbereich' (also die vom ADC
messbaren Werte in Abhängigkeit von der externen Beschaltung und dem
Temperaturgang des Sensors) nur z.B. von 400 bis 600 geht.
In diesem Falle wäre es 'billiger', einen festen Offset (z.B. 400) zu
subtrahieren und nur 200 Elemente in die Tabelle aufzunehmen.
Brauchst du nur eine dreistellige Zahl, so schau dir die untere und
obere mögliche Zahl an und überprüfe, ob es nicht mit einem Byte und
einem festen Offset geht.

Es kommt also immer auf die Anforderungen an. Sicher kann man das alles
auch in 16-Bit- oder 32-Bit-Arithmetik machen, aber das wäre schon
Verschwendung von Ressourcen. Und ich nehme mal an, dass dein AVR etwas
mehr tun soll, als nur ein simples Thermometer. Da könnte es durchaus
sein, dass du noch Ressourcen für andere Zwecke brauchst.

...

von Peter B. (Gast)


Lesenswert?

also mir fehlen noch jede Menge Basics, ich hab gerade Abitur gemacht
und mach jetzt ein Praktikum (eig als Informatiker), aber der
Informatikchief is gerade auf Montage. Deshalb bin ich jetzt in der
Elektroabteilung und da hab ich hald ein Breadboard gefunden und einen
Atmega8. Und jetzt probier ich hald bisschen was mitzunehmen (wenn ich
scho net in der Informatikabteilung bin (da hatte ich mich bis jetzt
eben mit vb beschäftigt)).

und mein atmega8 soll atm net mehr machn als einen Wert (Spannung
zwischen 0 und 5 V) über den ADC einlesen und dann auf ein Display
umgerechnet ausgeben. Im zum versuch hab ich ein Poti am ADC hängen,
der später mal einem PT100 weichen soll. (Hypothese: vor den PT100 muss
ich warscheinlich noch einen Operationsverstärker hängen, da die
veränderungen zu schwach sind oder)

gruß Peter

von Hannes L. (hannes)


Lesenswert?

Mit PT100 habe ich keine Erfahrung, ich weiß nur, dass der
Temperaturgang sehr gering ist.

Nimm doch erstmal einen Heißleiter als Sensor, oder besser drei Dioden
1N4148 in Reihe und die interne ADC-Referenz des Mega8. Die Dioden
kommen mit der Kathode an GND, Anode an ADC-Pin und ein Widerstand 1k
von Anode nach Vcc. Der ADC misst den Spannungsabfall an den Dioden,
der stark temperaturabhängig ist.

Ich habe gerade etwas Ähnliches mit Mega48 und einer Diode gemacht,
allerdings ohne LCD-Ausgabe (wurde nicht gewünscht), nur als
Thermostat.

Tip...
Analysiere doch erstmal ASM-Programme anderer Leute und versuche, jede
Zeile (und den Zusammenhang aufeinanderfolgender Zeilen) zu verstehen.
Viele offene Fragen beantwortet bereits Datenblatt und Befehlssatz,
weitere Fragen kannst du gerne hier stellen.
Dies gibt dir das erforderliche Knowhow, eigene Ideen umzusetzen.

Auf meiner HP findest du noch einige andere Programme, die relativ
einfach gehalten sind und meist recht üppig kommentiert. Zum Einstieg
(allerdings mit Tiny15) empfehle ich:
http://www.hanneslux.de/avr/divers/index.html
Da werden einige Grundlagen an verschiedenen Versionen eines
Melodiegenerators vermittelt.

...

von johnny.m (Gast)


Lesenswert?

Wie der PT100 zu beschalten ist, hängt von den Gegebenheiten ab.
Zunächst mal muss der (temperaturabhängige) Widerstandswert in einen
Spannungswert umgewandelt werden, damit er überhaupt vom ADC erfasst
werden kann. Das geht entweder über einen Spannungsteiler oder gar eine
Brückenschaltung (u.U. mit nachgeschaltetem Differenzverstärker, dann
kann man auch gleich den Messbereich an den des ADC angleichen).

Aber das mit dem Poti auszuprobieren ist sicher erst mal die beste
Idee. Ich habe genauso angefangen, meine ersten ADC-Schritte zu machen
(Allerdings gab es damals noch keine AVRs...). Das wichtigste ist erst
mal, den ADC ans Laufen zu bekommen und das Prinzip der
Werte-Umwandlung über die Tabelle zu verstehen, der Rest sind Details,
die sich irgendwann (fast) von selbst ergeben. Wenn es mit einfachen
Werten und 8 Bit Auflösung klappt (und das solltest Du als erstes
ausprobieren, auch wenn die Versuchung groß ist, gleich mit
Nachkommastellen und Begleittext rumzuspielen), dann sind es nur noch
kleine Schritte, das ganze zu verfeinern.

Ansonsten ist Hannes' Website sicher die erste Adresse für Dich, was
Beispiele zum Nachvollziehen und Ausprobieren angeht. Also: Gucken, wie
andere es machen, verstehen und dann an die eigenen Bedürfnisse anpassen
/ erweitern.

von Peter B. (Gast)


Lesenswert?

so ne art tongenerator bei mir warens 4 LED's hab ich scho gemacht
läuft auch. einmal hab ichs mit Tasten gemacht. Und dann hab ich ein
LED "Nightriderlichtchen" (des teil des Kid im Kühler hatte) gebaut.
und nun
wollte ich mich eben an so ein Thermometer wagen. Und vll habt ihr es
ja in meinem letzten thread gelesen mit dem ADC einlesen des
funktioniert ja schon ausgebn auf dem Display auch, hald als Binärzahl.


Nun müsst ich eben den Wert einer Temperatur zuordnen (so ein PT100
verhält sich ja relativ linear). Dies wollte ich eben mit so einer
Tabelle machn. Der PT100 muss eben auch skaliert werden, bei 0° C hat
er 100 Ohm. Und verändert dann seinen Widerstand eben. Aber die genaue
skalierung ist im Moment noch uninteressant. Ich möchte ja nur mal
einen dezimalen Wert dem Messergebnis des ADC zuordnen und dezimal
Ausgeben.

Und leider endet mein Praktikum am Fr. Ab Mo Ferienarbeit für 4 Wochen
(--> heißt keine Zeit für mikrocontroller, erst danach wieder). Und es
wäre eben hübsch wenn ich bis dahin den Thermometer noch fertig bekäme
(bis Fr).

gruß Peter

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.