sbic EECR,EEWE ; prüfe ob der vorherige Schreibzugriff
24
; beendet ist
25
rjmp EEPROM_read ; nein, nochmal prüfen
26
27
out EEARH, ZH ; Adresse laden
28
out EEARL, ZL
29
sbi EECR, EERE ; Lesevorgang aktivieren
30
in r16, EEDR ; Daten in CPU Register kopieren
31
ret
32
33
; Daten im EEPROM definieren
34
.eseg
35
daten:
36
.db 0b10101010
was ich hier nicht verstehe sind die Zeilen wo dirn steht:
ldi ZL,low(daten) ; Z-Zeiger laden
ldi ZH,high(daten)
was mache ich hier eigentlich?
was ich brauche ist: ich nehme mal an es sind Daten im EEPROM von der
letzten Messung drinnen bevor ich die Versorgung ausgeschaltet habe.
Jetzt will ich die Daten auslesen und in die selben Variablen laden wie
in der vorigen Messung.
Jetzt habe ich aber ein Problem: Ich habe 256 byte zur Verfügung, geißt
das ich kann 256 Variablen des Typs Byte speichern?
wenn ja lautet dann das coding zum Auslesen so:
1
sbic EECR,EEWE ; prüfe ob der vorherige Schreibzugriff
2
; fertig
3
rjmp EEPROM_read ; wenn nicht, dann nochmnal
4
5
out EEARH, ZH ; Adresse laden
6
out EEARL, ZL
7
sbi EECR, EERE ; Lesevorgang = 1
8
9
in Schwellwertleft, EEDR ;Daten aus EPROM in Variable laden
ich habe hier aber folgendes Problem: aus welchem byte lade ich da jetzt
in r16?
wie kann ich dieses festlegen welches ich auslesen will?
lg andy
>ldi ZL,low(Karl_August)>ldi ZH,high(Karl_August)>Karl_August:> .db 0b10101010
was sagt denn das .db aus?
Karl_August legt in dem Fall die Adresse fest?
könnte ich das ganze denn nicht so machen?
ANdy11 schrieb:> was sagt denn das .db aus?http://www.mikrocontroller.net/articles/AVR-Tutorial:_Speicher
Direktiven wie .db sind Anweisungen an den Assembler, keine
Prozessorbefehle. Von denen kann man sie durch den vorangestellten Punkt
unterscheiden. In diesem Fall sagen wir dem Assembler, dass er die
angegebenen Bytes nacheinander im Speicher platzieren soll; wenn man die
Zeile also assembliert, erhält man eine Hex-Datei, die nur diese Daten
enthält.
Hast Du das erste Programm mal getestet?
ANdy11 schrieb:> ldi r16, 0b00000001 ;niederwertigen Bits laden, lese Adresse 1 aus> mov ZL, r16 ;Ausgabe
Das wird nicht gehen.
Warum willst Du unbedingt dem ZL 0b00000001 geben und nicht Karl_August?
Dein Programm wiord nicht größer und nicht schneller. Was steht denn in
ZH drin? Solltest Du vieleicht vorher löschen, oder gib ihm wieder
Karl_August und dein Programm wird gehen.
@ANdy11,
die EEPROM-Adresse ist eine 16-Bit-Adresse.
Es gibt mehrere Varianten, diese an die Schreib- bzw. Leseadresse:
out EEARH, ZH ;Adresse laden
out EEARL, ZL
zu übergeben - auf jeden Fall enthält ZH das High-Byte und ZL das
Low-Byte der Adresse.
Selbstverständlich funktioniert es auch, diese Adresse direkt
einzutragen, allerdings sind die Register ZH und ZL nicht über OUT
ansprechbar - dieser Befehl dient dem Preipheriezugriff.
Otto
ANdy11 schrieb:>>Das wird nicht gehen.> Wieso denn nicht?> das einzige was zählt ist doch, dass die Adresse im ZL steht (wenn man> jetzt ZH vernachlässigt) oder?
Nein, der Z-Pointer ist bei EEPROM-Zugriff irrelevant. Er wurde in
diesem Beispiel als normales oberes Register verwendet und etwas
missverständlich kommentiert.
Welches Byte das EEPROM ausspuckt, wird dadurch bestimmt, welche Adresse
zuvor in die EEP-Adressregister (EEARH:EEARL) geschrieben wurde. Über
welches Arbeits-Register das erfolgte, ist dabei unwichtig. Wichtig für
den Ablauf ist nur:
- Sicherstellen, dass das EEPROM mit dem letzten Schreiben fertig ist
- Adresse in Adressregister schreiben
- Das Steuerbit EERE im Steuerregister EECR setzen (Schalter für
Start des Lesevorgangs)
- Ergebnis aus EEDR abholen.
Das Ermitteln der Adresse kann durch Berechnungen oder Konstanten
erfolgen. Gibt man jeder Adresse einen eigenen Namen, so verwendet man
natürlich diese Namen (Labels, hinter denen sich auch nur eine Zahl
verbirgt, in diesem Fall die Adresse) auch zum Zuweisen.
Oben gab es einige Beispiele mit .DB
Beachte dabei bitte, dass es verschiedene Segmente für die verschiedenen
Speicherarten gibt (.cseg, .dseg, .eseg). Am besten schaust Du Dir mal
die betreffenden Kapitel im Datasheet etwas genauer an. Ich vermute da
noch einige Missverständnisse bei Dir, was Speicherarten und deren
Adressierungsarten betrifft.
...
>- Sicherstellen, dass das EEPROM mit dem letzten Schreiben fertig ist>- Adresse in Adressregister schreiben>- Das Steuerbit EERE im Steuerregister EECR setzen (Schalter für> Start des Lesevorgangs)>- Ergebnis aus EEDR abholen.
1
ldi r16, 0b00000001 ;niederwertigen Bits laden, lese Adresse 1 aus
2
mov ZL, r16 ;Ausgabe
3
rcall Read_EEPROM
4
in Schwellwertleft, EEDR ;Daten aus EPROM in Variable laden
5
6
7
8
Read_EEPROM:
9
sbic EECR,EEWE ;prüfe ob ein vorheriger Schreibzugriff
In EEARH solltest Du auch einen Wert bzw. eine 0 schreiben - sonst
könnte es passieren, das Du immer auf andere Adressen zugreifst.
Den Umweg über ZL kannst Du ebenfalls einsparen:
ldi R15,0
ldi R16,1
rcall read_eprom
read_eprom:
..
..
..
..
out EEAH, R15
out EEAL, R16
ANdy11 schrieb:> jetzt will ich doch nur eine Bestätigung
nein
ANdy11 schrieb:> ldi r16, ;niederwertigen Bits laden, lese Adresse 1 aus> mov ZL, r16 ;Ausgabe
ZL ist ein Register "R30" das kannst Du direkt laden
Also:
ldi r30, 0b00000001
ist das gleiche wie:
ldi ZL, 0b00000001
genauso kannst du schreiben:
ldi r16, 0b00000001
out EEARL, r16
und woher weißt Du, was in EEARH drin ist?
Der EEprom braucht eine 16Bit Adresse. Er benutzt das EEARH auch wenn Du
es nicht extra ladest.
Woher weist Du das die Daten bei 0b00000001 stehen. Warum nimmst Du
nicht das Beispiel mit den Label?
ldi ZL,low(daten)
ldi ZH,high(daten)
Dein Programm wird nicht schneller und auch nicht größer.
Der Assembler schreibt dann da sowieso wieder nur eine "Zahl" rein, aber
die Richtige.
@MarioT:
> Warum nimmst Du nicht das Beispiel mit den Label?
es geht ANdy11 offenbar darum, bereits an bestimmte Adressen
geschriebene (aktuelle) Daten wieder auszulesen - da nutzt kein Label.
Ob er jetzt direkt eine Zahl oder ein Define einträgt, ist für die
Funktion egal, nicht aber für die Lesbarkeit.
>es geht ANdy11 offenbar darum, bereits an bestimmte Adressen>geschriebene (aktuelle) Daten wieder auszulesen - da nutzt kein Label.
naja die Daten werden am Anfang meines Programms ausgelesen, wie gesagt,
nach abschalten der Spannungsversorgung sollen die Schwellwerte (Rotoer
Linienverfolgung) noch beibehalten werden, also ins E²PROM gespeichert
werden.
>..ktion egal, nicht aber für die Lesbarkeit.
Was heißt das denn jetzt wieder?
> nicht aber für die Lesbarkeit.> Was heißt das denn jetzt wieder?
das heisst, dass Du selber nachhalten musst, an welcher Adresse welcher
Wert drinsteht. Wenn Du sinnvolle Defines verwendest (z. B.
Schwellwert), wäre der Code lesbarer.
ANdy11 schrieb:>>..ktion egal, nicht aber für die Lesbarkeit.> Was heißt das denn jetzt wieder?
Der Compieler übersetzt Dein Programm so das es der Prozessor versteht.
Also ob Du jetzt "Daten" als Label oder "Karl_August_Sucht_Seine_Daten"
da hin schreibst ist dem Prozessor egal weil der Assembler immer wieder
die gleiche "Zahl" draus macht. Wenn Du aber später mal oder jemand
anderes das Programm sich ansieht kann er es besser lesen.
asoo, jetzt weiß ich wieso das besser mit Labels zu machen ist, das gilt
nämlich auch fürs schreiben, ich brauch einfach nur sagen schreibe in
"Label" und lese von "Label"
aber das ist mir noch ein Rätsel:
ldi ZL,low(daten)
ldi ZH,high(daten)
Daten:
.db 0b10101010
woher weiß der Prozessor jetzt was er als High Bit und welches als Low
bit nehmen soll, weil in Daten: steht nur ein Byte
dann würde doch drin stehen:
ZH: 10101010 ZL: 10101010
dh--> erstes Bit von der Adresse ZH ist null und somit wertet er nur das
ZL aus oder wie ist das?
Nehmen wir mal an, Du hättest ganz viele (mehr als 256) Werte zu
speichern, dann kommst Du mit einer 8-Bit-Adresse nicht mehr hin. Daher
verwendet das EEPROM 16-Bit-Adressen, welche aus zwei Byte bestehen.
Hans:
.db 0x00
Franz:
.db 0x00
Kurt:
.db 0x00
..
..
..
..
Xaver:
.db 0x00
Otto schrieb:> In ZH und ZL steht das High- ind Low-Byte der Adresse und nicht der> Daten !
naja im endeffekt interessiert mich ja am anfang nur die adresse, denn
das lesen und schreiben gehen ja über andere befehle:
Lesen: in r16, EEDR
also hab ich gedacht in Daten:
wird die adresse festgelegt, und immer wenn ich eine bestimmte datei
lesen will muss ich ZL und ZH die Daten hineinladen, also bekomme ich
bei einlesen inr16, EEDR die Daten die ich haben möchte, so habe ich das
verstanden
ANdy11 schrieb:> aber das ist mir noch ein Rätsel:> ldi ZL,low(daten)> ldi ZH,high(daten)>> Daten:> .db 0b10101010
"Daten" ist die Adresse. Der Assembler sucht sich wenn das Programm
übersetzt wird die Stelle wo die Daten (also das .db steht) und setzt
die "Zahl" oben wo Daten steht wieder ein. Damit steht die Adresse im
Registerpaar ZL und ZH danach übergibst Du es ja dem
out EEARH, ZH ; Adresse laden
out EEARL, ZL
EEARH und EEARL brauchst Du da das EEprom größer als 256 ist.
>ja - aber dieser Befehl liest die Daten aus der 16-Bit Adresse, die Du>vorher übergeben hast.....
also jetzt versteh ich gar nichts mehr
die Schritte sind ja die:
-Schau nach ob nicht geschrieben wird
-lege fest bei welcher Adresse (diese ist 16 Bit lang) die Daten
eingelesen werden soll
-lese anschließend bei angegebener Adresse die 8 bit Daten heraus
> out EEARH, ZH ; Adresse laden> out EEARL, ZL>EEARH und EEARL brauchst Du da das EEprom größer als 256 ist.
ja das stimmt schon, aber ZH und ZL sind jeweils 1 Byte groß und wir
übergeben ihm mit daten sozusagen nur ein byte und das ist wo db steht
wie kann man mit einem byte 16 darstellen war zunächst mal meine andere
frage
und dann habe ich gedacht, dass ich ihm mit
ldi ZL,low(daten)
ldi ZH,high(daten)
das selbe byte für ZL und ZH übergebe (ist ja auch logisch, denn beide
haben (daten) umklammert also würde dann stehen:
EEARH ... High position höheres Byte(interessiert mich eher weniger, da
sich da nur wegen den begrenzten 256byte nur eine adresse ausgeht):
EEARH = 10101010
und EEARL = 10101010, das heißt die Adresse würde dann insgesamt so
ausschauen:
10101010010101010 wobei das erste bit im High Byte 0 ist und somit die
gesamte adresse 10101010 ist
ANdy11 schrieb:> die Schritte sind ja die:> -Schau nach ob nicht geschrieben wird
Ein EEprom braucht zum schreiben ewig. Die Daten die ins eeprom
geschrieben werden sollen, werden zum schreiben übergeben. Dann macht
das der µC im hintergrund. Der Prozessor arbeitet inzwischen weiter.
Damit der µC nicht durcheinanderkommt wenn Du jetzt vom EEprom wieder
was willst muß man erst sehen ob er noch am schreiben ist.
ANdy11 schrieb:> -lege fest bei welcher Adresse (diese ist 16 Bit lang) die Daten> eingelesen werden soll
ldi R15,low(daten)
ldi R16,high(daten)
ANdy11 schrieb:> -lese anschließend bei angegebener Adresse die 8 bit Daten heraus
EEPROM_read:
sbic EECR,EEWE
rjmp EEPROM_read ; nein, nochmal prüfen
out EEARH, R16 ; Adresse laden
out EEARL, R15
sbi EECR, EERE ; Lesevorgang aktivieren
in Schwellwertleft, EEDR
ANdy11 schrieb:> was mich noch irritiert sind die Klammern und low und high
also die Adresse ist z.B. Daten = 0b0010000010001001
das low mit Klammer lädt den low(also die kleineren 8Bit in das
entsprechende Register
Also
ldi R15,low(daten)
ist also in R15 0b10001001 drin
ldi R16,high(daten)
ist also in R16 0b00100000 drin
>das low mit Klammer lädt den low(also die kleineren 8Bit in das>entsprechende Register>Also>ldi R15,low(daten)>ist also in R15 0b10001001 drin>ldi R16,high(daten)>ist also in R16 0b00100000 drin
ABER in Daten ist nur eine 8 Bit lange Zahl zu finden und keine 16bit wo
man unterscheiden muss, deswegen mein einwand vorher
ldi ZL,low(daten)
ldi ZH,high(daten)
oder man gibt die Daten direkt dezimal ein ohne ins binäre oder hex
umrechnen zu müssen. Anstatt 0x10 und 0x0E zu verwenden
z.B.
ldi ZL,low(3600)
ldi ZH,high(3600)
oder
ldi temp, low(3600)
ldi temp2, high(3600)
>Du darfst die richtigen Daten nicht mit der Adresse wo die Daten stehen>Verwechseln
das tuhe ich nicht
aber die Adresse der Daten steht in Daten: .db 0b00000001 --> Adresse1
wenn man dies im ZL hineinlädt, aber wieso lade ich jetzt das selbe im
ZH rein?
ANdy11 schrieb:> das tuhe ich nicht> aber die Adresse der Daten steht in Daten: .db 0b00000001 --> Adresse1> wenn man dies im ZL hineinlädt, aber wieso lade ich jetzt das selbe im> ZH rein?
machst Du nicht
durch das low und high mit den klammern steht in ZH dann .db 0b00000000
ldi ZL,low(daten) ; Z-Zeiger laden
ldi ZH,high(daten)
rcall EEPROM_read ; Daten aus EEPROM lesen
out PORTB, r16
loop:
rjmp loop
EEPROM_read:
sbic EECR,EEWE ; prüfe ob der vorherige
Schreibzugriff
; beendet ist
rjmp EEPROM_read ; nein, nochmal prüfen
out EEARH, ZH ; Adresse laden--> diese steht
jetzt in ZH und ZL, das problem ist aber es steht das selbe in beiden
drinn
out EEARL, ZL
sbi EECR, EERE ; Lesevorgang aktivieren
in r16, EEDR ; Daten in CPU Register kopieren
ret
; Daten im EEPROM definieren
.eseg
daten:
.db 0b10101010
oder kann es sein, dass er die Adressierung automatisch übernimmt, das
würde es nämlich erklären, ich glaub eher die Adressierung von Daten
übernimmt er automatisch, aber was machen dann das .db drinn wenn es
nicht die adressierung angibt?
Nur dass ich keinen AVR kenne, dessen EEPROM bis zur Adresse 3600
reicht...
;-)
Die Adressen binär anzugeben ist großer Quatsch, das macht die Sache nur
unnötig unübersichtlich. Man gibt Werte immer in dem Format an, das für
den Zweck die höchste Aussagekraft hat. Bei Adressen ist das Dezimal
oder Hexadezimal, bei Bitmustern (wenn jedes Bit eine andere Bedeutung
hat, z.B. die Segmente von 7-Segment-Anzeigen) binär und bei Text
(Buchstaben, Zeichen, Ziffern) in ASCII.
Deine penetrante Verwendung der Z-Register führt zu Missverständnissen.
Der Z-Pointer ist für Datenzugriff auf Flash (LPM-Befehl) zwingend nötig
und für indirekten Datenzugriff auf SRAM geeignet. Nimm also andere
Register für den EEP-Zugriff, damit Du nicht in den Glauben verfällst,
es ginge (wie bei LPM) nur mit dem Z-Pointer.
Die Funktionen LOW(x) und HIGH(x) sind keine ASM-Befehle, die der AVR
abarbeitet, sondern Befehle des Preprozessors (also auf PC-Ebene), die
das Aufbereiten von Zahlenwerten erleichtern sollen. LOW(x) extrahiert
dabei den Low-Teil (also die unteren 8 Bit) von x, HIGH(x) extrahiert
das High-Byte der Zahl. Das Ergebnis ist in beiden Fällen ein Byte mit
dem Wertebereich 0 bis 255. Auch wenn Dich die Klammern stören, sie sind
nötig, da eine Funktion syntaktisch Klammern verlangt.
Wenn Du (im Anfangsstadium) Probleme mit symbolischen Adressen hast,
dann nimm doch in Gottes Namen erstmal numerische Adressen, also
Dezimalzahlen, um die Arbeitsweise überhaupt erstmal zu verstehen. Auf
symbolische Adressen kannst Du dann immer noch umstellen, wenn Du
anfängst zu rätseln, welcher Parameter an welcher Adresse (Zahl)
gespeichert ist. Du kannst symbolische EEP-Adressen einmal durch
.DB-Zuweisungen im .ESEG definieren, aber auch durch ganz normale
Konstantendefinition (.equ EEP_tempo=0, .equ eep_mess_links=1, .equ
eep_mess_rechts=2, .equ eep_mess_mitte=3, usw...) im Deklarationsteil
(Kopf) des Programms.
Mehr fällt mir jetzt nicht ein, ich habe aber sicher noch einige Punkte
(an denen ich Missverständnisse Deinerseits vermute) vergessen.
...
ok langsam gebe ich auf zu verstehen was ihr mir erlären wollt
eine frage hätt ich aber doch noch
wenn ich das hier in den Controller lade kann ich dann die richtigen
Daten laden?
>ja dem Adresszähler fürs EEPROM gibt man ne kleinere Adresse, aber für>16Bit Berechnungen kann man halt bis 65535 reinladen.
ich kann mir immer noch nicht vorstellen wie das aussieht wenn ich mit
16 bit rechen, aber das ist ein anderes Thema
>Nein - hier musst Du wieder mit high() und low() arbeiten !
ich bitte dich noch einmal um eine Erklärung wieso das so ist
wenn ich sage
ldi ZL, high(MessergebnisERAMright)
ldi ZH, low(MessergebnisERAMright)
was steht dann in ZL und ZH?
.eseg
die 1. Adresse ist 0000 high = 00, low =00
die 2. Adresse ist 0000 high = 00, low =01
...
die n. Adresse ist 0100 high = 01, low =00 (nur ein Beispiel!)
Dies hier:
MessergebnisERAMleft:
.db 0b00000001 ;Adresse 1
MessergebnisERAMmiddle:
.db 0b00000010 ;Adresse 2
MessergebnisERAMright:
.db 0b00000011 ;Adresse 3
zeigt, dass Du Adresse und Daten verwechselst, da Du als Kommentar
Aresse 1-3 geschrieben hast.
Der Inhalt ist vollkommen beliebig !
ANdy11 schrieb:> MessergebnisERAMright
in dem Wort "MessergebnisERAMright" steht nicht "0b00000011" drin
sondern nur an welcher Stelle im EEProm das steht.
Otto schrieb:> MessergebnisERAMleft:> .db 0b00000001 ;Adresse 1> MessergebnisERAMmiddle:> .db 0b00000010 ;Adresse 2> MessergebnisERAMright:> .db 0b00000011 ;Adresse 3>> zeigt, dass Du Adresse und Daten verwechselst, da Du als Kommentar> Aresse 1-3 geschrieben hast.>> Der Inhalt ist vollkommen beliebig !MarioT schrieb:> in dem Wort "MessergebnisERAMright" steht nicht "0b00000011" drin> sondern nur an welcher Stelle im EEProm das steht.>>>>>> Beitrag melden | Bearbeiten | Löschen |
ich glaube so langsam habe ich es begriffen, sowie ich das im moment
versteh is, dass MessergebnisERAMright die Adresse schon ist, wenn das
so ist, dann könnte ich theoretisch/nein es wäre sogar 100 * besser nach
dem db ein register aufschreiben, indem die daten hineingespeichert
werden, dh beim daten schreiben muss ich ins register bsplsweise r16 die
daten ablegen, dann speichere ich die daten mit der adressierung
High(Mess...) und Low(Mess...) und beim neustart kriege ich die daten
indem ich ihm sage du die adresse ist high low von Mess... ´, der schaut
sich das ergebnis an, ladet es in EEDR und ich bekomme es dann heraus
dann sagt er unexpected defreister
und wenn ich r16 schreibe dann sagt er unexpected register
jetzt frage ich: wie kann ich sonst festlegen wie daten gespeichert
werden, indem man dieses Register verändert ausser das ganze händisch zu
machen sowie vorher, es muss doch irgendeinen grund geben wieso ich das
.db habe, als erste habe ich gedacht das dient zur adressierung, dann
war das logischere die Daten, jedoch sind die nicht variable , was mache
ich jetzt=
?
.eseg
TEXT_BEGRUESSUNG:
.db "UVR 1611Ausgabe auf LCDSpeichern auf SD01.09.2009"
welche_Daten_ins_LCD:
.db 17 ,5 ,1 ,12
Eingang_Text:
.db "Kollektor Solar-VL Solar-RL W",0b11100001,"rmet.SekPuffer.o"
Die Daten Stehen im EEProm
Jetzt üergebe ich die Adresse an r15, r16 z.B.
ldi r15,low(Eingang_Text)
ldi r16,high(Eingang_Text)
danach gebe es dem EEProm
out EEARH, r16 ; Adresse laden
out EEARL, r15
Dann holt man das erste Byte
ist in dem Fall "K"
dann addiere ich eins dazu und hole das zweite Byte "o"
usw.
Hinter ".db" dürfen nur Konstanten folgen, welche als Initialwerte z. B.
zusammen mit dem Flashen in das EEPROM geschrieben werden.
Den gewünschten (aktuellen) Inhalt der EEPROM-Zellen musst Du über die
Schreibroutine in das EEPROM Schreiben.
@Andy(11): Angenommen du möchtest in deinem Programm einen veränderbaren
Wert durch eine Konstante teilen, dann ist es doch bequemer die
Konstante dezimal statt binär anzugeben. Die Aufteilung also High=1110
Low=00010000 erledigt also der Assembler.
Genauso ist es wenn du im Programm Daten aus einer bestimmten EEPROM
Adresse holen möchtest z.B. dort wo eine Kennlinie losgeht
Dann kann man eben im Programm direkt die Stelle dem Adresszähler
übergeben und der Assembler kümmert sich um den Rest.
also
ldi ZL, high(513)
ldi ZH, low(513)
statt
ldi ZL, high(MessergebnisERAMright)
ldi ZH, low(MessergebnisERAMright)