PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATMega8 und EEPROM lesen/speichern



LotharK
25.11.2007, 09:32
Hallo,

ich möchte erfasste Daten im EEPROM speichern und irgendwann wieder lesen können. Leider bin ich nicht sehr bewandert in den Dingen.

Im Netz habe ich schon mal diesen Code gefunden:

.include "m8def.inc"

.DEF rTemp = R16

.DEF rH=R18


ldi rTemp, 0xFF
out DDRD, rTemp

ldi rTemp, 4, HIGH(Daten)
out EEARH, rTemp
ldi rTemp, LOW(Daten)
out EEARL, rTemp

sbi EECR, EERE
in rTemp, EEDR


out PORTD, rTemp
loop:
rjmp loop

.eseg
Daten:
.db 0B01010101

Damit kann ich nun zwar Daten lesen, aber wie schreibe ich diese?
Auch sollten ja mehrere Werte gespeichert werden.

Weiter verstehe ich diese Zeile nicht richtig.

ldi rTemp, 4, HIGH(Daten)
Hier gebe ich die Erste Adresse im EEPROM an. Was aber, wenn ich die 3. Adresse möchte? High(Daten*6)
Ich wäre iber etwas Hilfe dankbar. Vielleicht hat ja jemand ein einfaches Beispiel für mich?

Vielen Dank im Voraus - Lothar

izaseba
25.11.2007, 11:26
Hallo,
Du sollst allerdings vor dem lesen testen, ob Dein EEPROM überhaupt bereit ist
gelesen zu werden.
Ich poste Dir mal zwei Makros aus meinem aktuellen Projekt:

1. lesen


.macro READMOTORVALUE
wait4eep1:
sbic EECR,EEPE
rjmp wait4eep1
ldi tmp,LOW(radrechts)
out EEARL,tmp
sbi EECR,EERE
in tmp,EEDR
wait4eep2:
sbic EECR,EEPE
rjmp wait4eep2
ldi tmp1,LOW(radlinks)
out EEARL,tmp
sbi EECR,EERE
in tmp1,EEDR
.endmacro

2. schreiben

.macro SAVEMOTORVALUEFUNC
wait4ready1:
sbic EECR,EEPE
rjmp wait4ready1
out EECR,null
ldi tmp,LOW(radrechts)
out EEARL,tmp
in tmp,OCR0A
in tmp1,OCR0B
out EEDR,tmp
cli
sbi EECR,EEMPE
sbi EECR,EEPE
sei
wait4ready2:
sbic EECR,EEPE
rjmp wait4ready2
out EECR,null
ldi tmp,LOW(radlinks)
out EEARL,tmp
out EEDR,tmp1
cli
sbi EECR,EEMPE
sbi EECR,EEPE
sei
.endmacro

Die EEprom adressen werden so deklariert


;; EEPROM Segment
.eseg
radrechts:
.db 0x80
radlinks:
.db 0x80


Es werden zwar 2 Adressen nacheinander gelesen, das sollte aber das Prinzip zeigen.

Zu HIGH und LOW habe ich hier (http://www.izaseba.roboterbastler.de/index.php?popup=Tutorial&section=Lektion9)

was geschrieben, ich hoffe es ist verständlich genug.

Gruß Sebastian

LotharK
25.11.2007, 12:21
Hi,
danke erst Mal für Deine Antwort. Jetzt bin ich noch verwirrter als vorher.
Wenn ich mir nun diesen Code anschaue,

;; EEPROM Segment
.eseg
radrechts:
.db 0x80
radlinks:
.db 0x80

verstehe ich nicht, dass radrechts an die gleiche Position wie radlinks gespeichert wird. Wenn das die gleiche Speicheradresse im EEPROM ist, überschreiben sich die Werte da nicht?

Noch eine Frage:
Ich habe bis jetzt noch nichts mit Makros gemacht. Was ist der Vorteil? Sind Unterprogramme nicht effektiver im Speicherplatz?


Ich habe den Code nun so erweitert, und dachte, Wenn ich PortPin B0 aktiviere, liest es den EEProm und bei PB1 schreibt es den EEProm. Leider läuft der Code so nicht. Wo ist denn der Fehler??

.NOLIST
.include "m8def.inc"
.LIST

.DEF tmp = R16
.DEF tmp1 = R17


LOOP:
sbis PinB, 0
READMOTORVALUE
sbis PinB, 1
SAVEMOTORVALUE
rJmp Loop

.macro READMOTORVALUE
wait4eep1:
sbic EECR,EEPE
rjmp wait4eep1
ldi tmp,LOW(radrechts)
out EEARL,tmp
sbi EECR,EERE
in tmp,EEDR
wait4eep2:
sbic EECR,EEPE
rjmp wait4eep2
ldi tmp1,LOW(radlinks)
out EEARL,tmp
sbi EECR,EERE
in tmp1,EEDR
.endmacro

.macro SAVEMOTORVALUEFUNC
wait4ready1:
sbic EECR,EEPE
rjmp wait4ready1
out EECR,null
ldi tmp,LOW(radrechts)
out EEARL,tmp
in tmp,OCR0A
in tmp1,OCR0B
out EEDR,tmp
cli
sbi EECR,EEMPE
sbi EECR,EEPE
sei
wait4ready2:
sbic EECR,EEPE
rjmp wait4ready2
out EECR,null
ldi tmp,LOW(radlinks)
out EEARL,tmp
out EEDR,tmp1
cli
sbi EECR,EEMPE
sbi EECR,EEPE
sei
.endmacro


;; EEPROM Segment
.eseg
radrechts:
.db 0x80
radlinks:
.db 0x80

Vielleicht kann mir ja noch mal wer helfen?

Danke Lothar

izaseba
25.11.2007, 13:17
Sorry, ich wollte Dich nicht verwirren :-(


verstehe ich nicht, dass radrechts an die gleiche Position wie radlinks gespeichert wird. Wenn das die gleiche Speicheradresse im EEPROM ist, überschreiben sich die Werte da nicht?

Wieso gleiche Adresse ?

es sind zwei Adressen hintereinander, 0x80 ist nicht die Adresse, sondern Wert, der in diese Speicherzelle rein soll, das wird in der *.eep Datei Abgelegt.

Warum Makro ?
Naja, da muß man entscheiden was besser ist.
Wenn die Funktion nur einmal im Programm ausgerufen wird ist makro besser, wenn 20 mal ist natürlich ein call besser, spart Speicher

Was hängt denn an PinB1 und PinB0 Taster ?
Pass mit sowas auf, mann kann sich den EEprom ziemlich schnell killen, wenn man Fehler macht.


Achso, ich wollte Dich natürlich nicht unbedingt zu Makros bewegen sondern eher zeigen, wie man was in EEprom schreibt bzw. liesst.

Gruß Sebastian

LotharK
25.11.2007, 14:55
Hi,
jetzt hab ich es auch verstanden - dass 0x80 ein Wert und keine Adresse ist.

An PinB,0 und PinB, 1 liegen die Taster (STK500)
Ich wollte erreichen, dass beim Drücken
die 2 Makros

sbis PinB, 0
READMOTORVALUE
und
sbis PinB, 1
SAVEMOTORVALUE
aufgerufen werden.

Sicher rufe ich die Makros falsch auf.



E:\Assemb\S\EEPROM\Test1\Test1.asm(13): error: SAVEMOTORVALUE: Unknown instruction or macro

Was ist, wenn ich variabel 1 - 10/12 Messergebnisse vorübergehend im EEProm speichern will?

Muss ich da für alle eine Marke im EEProm definieren?

Ich dachte, ich könne das so wie im Stack ablegen und dann wieder hintereinander abrufen.

Und wieso kann ich mir damit den EEPROM zerschießen?

MfG Lothar[/quote]

izaseba
25.11.2007, 15:46
Und wieso kann ich mir damit den EEPROM zerschießen?

Ein Beispiel von mir:

Ein Register sollte auf Tastendruck im EEprom geschrieben werden.

Zu wenig überlegt und es war genau anders herum, kein Tastendruck bewirkte
das schreiben...
Was passiert ?
EEprom wurde nur noch beschrieben, wie lange Dauert das schreiben ?
Irgendwas mit 1 mS, also etwa 1000 Schreibzugriffe in der Sekunde,
dumm nur wenn eeprom 100000 Schreibzugriffe hält.
Bis ich darauf gekommen bin, daß ich einen Fehler gemacht habe, war die EEprom Zelle kaputt und hat kein Inhalt mehr gehalten...
Wie gut, daß es noch weitere EEprom Zellen gab, wo ich was schreiben konnte...

Wenn Du mehrere Sachen im EEprom Speichern willst würde ich das etwa so machen:



.equ eeprompuffer = 0x00
.def null = r1
...
...

clr null

loop:
clr r16
ldi r19,1
loop1:
rcall eepromsave
inc r16
inc r19
cpi r16,20
brne loop1
loop2:
rjmp loop2
eepromsave:

sbic EECR,EEPE
rjmp eepromsave
out EECR,null
ldi r17,LOW(eeprompuffer)
add r17,r16
adc r18,null
out EEARH,r18
out EEARL,r17
out EEDR,r19
cli
sbi EECR,EEMPE
sbi EECR,EEPE
sei
ret

So in etwa ? es werden 21 EEpromzellen beschrieben
Wenn Du keine Interrupt benutzt kannst Du Dir auch cli sei sparen

Tja die Makros, sowas ist schonmal nicht gut


sbis PinB, 0
READMOTORVALUE

mit sbis überspringst Du nicht READMOTORVALUE sondern nur die erste Zeile im Makro, weil an der Stelle wo der Makroname steht, fügt der Assembler alles ein was zwischen .macro und .endmacro steht.

Gruß Sebastian

LotharK
25.11.2007, 16:23
Hi,
ja, das mit dem Zerschießen des EEProms habe ich mittlerweile kapiert.

In der Zwischenzeit habe ich diesen Code geschrieben. (Wie gesagt - ich habe fast noch 0 Ahnung.



.NOLIST
.include "m8def.inc"
.LIST

.DEF rTemp = R16
.DEF rT1 = R17
.DEF rP1=R18
.DEF rP2=R19

ldi rTemp, LOW(RAMEND) ; Stackpointer initialisieren
out SPL, rTemp
ldi rTemp, HIGH(RAMEND)
out SPH, rTemp



ldi rTemp, 0xFF
out DDRD, rTemp ; Port D: Ausgang



LDI rTemp, 0B11111111
OUT PORTD, rTemp

LOOP:
sbis PinB, 0 ; Auf Tastendruck abfragen
rCall READ ; EEProm lesen
sbis PinB, 1 ; Auf Tastendruck abfragen
rCall SAVE ; EEPROM schreiben
sbis PinB, 2 ; Auf Tastendruck abfragen
rCall AddT1 ; Zufällige Zahl ermitteln
rJmp Loop

AddT1:
inc rT1 ; Zufallszahl einstellen
OUT PortD, rT1
RET


READ:
RCall EEPROMLesen
Mov rT1, rTemp
OUT PORTD, rTemp
Ret

SAVE:
MOV rTemp, rT1
rCall EEPROMSchreiben
rCall Pause
rCall Pause
RET


EEPROMLesen:
ldi rTemp, HIGH(W1) ; Adresse laden
out EEARH, rTemp
ldi rTemp, LOW(W1)
out EEARL, rTemp
sbi EECR, EERE ; Lesevorgang aktivieren
in rTemp, EEDR
rCall Pause
RET

EEPROMSchreiben:

ldi rTemp, HIGH(W1) ; High-Adresse im EEPROM laden
out EEARH, rTemp ; und ins EEARH schreiben
ldi rTemp, LOW(W1) ; Low-Adresse im EEPROM laden
out EEARL, rTemp ; und ins EEARL schreiben
sbic EECR,EEWE ; Vorherigen Schreibvorgang abwarten
rjmp EEPROMSchreiben
out EEDR,rTemp ; Daten ins EEPROM-Datenregister
sbi EECR,EEMWE ; Schreiben vorbereiten
sbi EECR,EEWE
rCall Pause
RET

Pause:
DEC rP1
brne Pause
DEC rP2
brne Pause
Ret

.eseg ; EEPROM
W1:
.db 0B10101010

Es soll folgendes passieren. Druck auf Taste PortB0 und der Inhalt des EEs soll gelesen werden. - das funktioniert.

Druck auf Taste PortB2 wird aufgrund variabler Dauer ein zufälliger Wert im Register rT1 erzeugt - das funktioniert.

Druck auf Taste PortB1 soll nun den Inhalt des Registers rT1 an rTemp übergeben und im EE speichern. Das funktioniert nicht. Im EE steht nun nichts mehr. Kontrolle Taste0

Im EE habe ich aber die .eep geladen. Kontrolle Taste0 - Wert war anfangs da.


Wenn ich Deinen Code umsetzen will (ATMEGA8), bekomme ich folgende Fehler:


E:\Assemb\S\TIMER\ATM8\Test2.asm(40): error: Undefined symbol: EEPE
E:\Assemb\S\TIMER\ATM8\Test2.asm(50): error: Undefined symbol: EEMPE
E:\Assemb\S\TIMER\ATM8\Test2.asm(51): error: Undefined symbol: EEPE


Sicher liegt es nicht am Code, sondern daran, dass ich es nicht auf den ATMega8 umsetzen kann.

Hast Du vielleicht ein funktionierendes Beispiel für den ATM8?

Das wäre super! Wie ich sehe, gehts Dir leicht von der Hand.

Ciao Lothar

izaseba
25.11.2007, 17:24
Wenn ich Deinen Code umsetzen will (ATMEGA8), bekomme ich folgende Fehler
Hmm, die deppen haben die Bitnamen geändert, sorry ich arbeite zur Zeit mit Tiny24 und nicht M8...
Sonst sieht Deine Save Funktion nicht schlecht aus.

In der Read Routine sollst Du auch warten, bis EEWE Low geht, vielleicht liegt hier der Hund begraben.

Wenn Du ein Beispiel möchtest schau mal ins Dattenblatt ab Seite 22 gibt es je ein Beispiel zum Schreiben und lesen.

Gruß Sebastian

LotharK
25.11.2007, 18:26
Hi,
hm, lesen tut es ja einwandfrei.
Das Beispiel ist ja fast so, wie ich es postete.
Irgendwie klappt das Schreiben einfach nicht.

Vielleicht gibt es ja jemanden, der ein fertiges Anfängerbeispiel hat?

MfG LotharK

izaseba
25.11.2007, 18:40
Ich glaube ich hab Deinen Fehler, schau Du willst Schreiben:


SAVE:
MOV rTemp, rT1
rCall EEPROMSchreiben
rCall Pause
rCall Pause
RET

in rtemp liegt der zu speichernde Wert, dann machst Du ein rcall nach EEPROMSchreiben, und da knallt es weil,

EEPROMSchreiben:

ldi rTemp, HIGH(W1) ; High-Adresse im EEPROM laden
out EEARH, rTemp ; und ins EEARH schreiben
ldi rTemp, LOW(W1) ; Low-Adresse im EEPROM laden
out EEARL, rTemp ; und ins EEARL schreiben
sbic EECR,EEWE ; Vorherigen Schreibvorgang abwarten
rjmp EEPROMSchreiben
out EEDR,rTemp ; Daten ins EEPROM-Datenregister
sbi EECR,EEMWE ; Schreiben vorbereiten
sbi EECR,EEWE
rCall Pause
RET


Du die den Inhalt von rtemp 2 Mal überschreibst und gespeichert wird LOW der Adresse von W1 ;-)
Entweder nimmst Du einen anderen Register für die Wertübergabe, oder Du ließt rT1 unmitelbar vor dem Schreiben in EEDR aus.

Gruß Sebastan

LotharK
25.11.2007, 19:02
Hallo Sebastian,

ich hatte es auch gerade gefunden. Danke - jetzt läuft alles dank Deiner Hilfe.
Hat mich echt einen Sonntag gekostet.

Ciao LotharK

izaseba
25.11.2007, 19:15
Hallo LotharK,


Hat mich echt einen Sonntag gekostet.


Was ist schon ein Sonntag bei so einer komplexen Sache wie ein µC ;-)
Immerhin gehst Du den 'schweren' Weg über Assembler...

Gruß Sebastian