Forum: Mikrocontroller und Digitale Elektronik PIC16F688 EEPROM speichert nicht nach ausschalten


von Mario (Gast)


Lesenswert?

Hallo zusammen!

Ich habe folgendes Problem: und zwar möchte ich mittels EEPROM daten 
nach dem ausschalten wieder verwenden können, sollte ja eigentlich kein 
Problem sein, allerdings sind meine Daten nach den Ausschalten immer 
weg, schreiben und lesen funktioniert einwandfrei.

Ich verwende den PIC16F688, ICD3 In-Circuit-Debugger und Hi-Tech 
Compiler

Hier mal ein einfaches Programm, bei dem das aber auch schon nicht geht.

#include <htc.h>
#include <stdio.h>
#include <EI7C_B.h>

enum STATUS{
AN,
AUS
};

#define ROT RC0
#define GRUEN1 RC1
#define GRUEN2 RC5

void main(void){
  OSCCON = 0x71;    // 8MHz internal;
  OSCTUNE= 0x0F;    // max. frequency
  CMCON0 = 0x07;    // compare mode disabled
  ANSEL  = 0b00000000;
// Port A
  IOCA   = 0x00;    // all interrupts on change disabled
  WPUA   = 0x00;    // all weak pull ups disabled
  TRISA  = 0xFF;    // set all input
  PORTA  = 0x00;    // clear Input Register
// Port C
  TRISC = 0b11011100;    // RC0, RC1 output, RC2:RC5 input
  PORTC = 0xFF;    // LEDs off
//ADC
  ADCON0 = 0b00011101;  //left justified, AN7, enable ADC
  ADCON1 = 0b01100000;  //Fosc/64
  INTCON = 0x00;          //enable interrupts
  PIE1   = 0x00;          //enable AD interrupt
  PIR1   = 0x00;    //clear ADIF
//EEPROM
  EECON1 = 0x00000100;


  WREN = 1;                    //WRITE
  EEADR = 0x0F0;
  if(RC3 == 1){EEDAT = 0x01;}
  EECON2 = 0x55;
  EECON2 = 0xAA;
  WR = 1;

  while(EEIF != 1);           //READ
  RD = 1;
  #asm
    NOP
    NOP
  #endasm
  while(RD == 1);
  EE_DATA = EEDAT;
  if (EE_DATA == 1){ROT = AN;}    //EE_DATA: zwischenspeicher zum 
speichern des gelesenen EEPROM wertes
}

Schonmal Danke für dei Hilfe

von Michael R. (mexman) Benutzerseite


Lesenswert?

Hallo Mario,


Du beruecksichtigst schon, dass die EEPROM-Daten in Bank 1 liegen?


> allerdings sind meine Daten nach den Ausschalten immer
> weg,

Wie stellst Du das genau fest?


Was sagt der Emulator....werden die Daten in den EEPROM-Bereich 
abgelegt? Was passiert nach Reset im Emulator, sind die EEPROM Daten 
dort vorhanden?




Gruss

Michael

von Frank B. (frank_b33)


Lesenswert?

Hallo Michael,
hier mal ein Stück Code, mit dem es bei mir immer funktioniert:

  EEADR = 0;      //Adresse im EEProm
  EEDAT = Akku.low8;    //Wert, der ins EEProm soll

  WREN = 1;      //EEProm WRite ENable
  EECON2 = 0x55;      //unlock write
  EECON2 = 0xAA;      //unlock write
  WR = 1;        //write
  while(WR==1);      //warten bis WR wieder weg ist
  WREN = 0;      //EEProm Write disable


          //Korrekturwert aus EEProm lesen
  EEADR = 0;               //EEProm Adresse 0
  RD = 1;                  //lesen
  Delay1ms(1);        //etwas warten
    Korrektur=EEDAT;         //Korrekturwert auslesen

hth
Frank

von Jens B. (nixiefreak)


Lesenswert?

Es kann sein, dass dein Compiler deine NOPs wegoptimiert, und du so das 
Timing nicht einhältst, nur so als Idee.

Gruß
Jens

von Dieter W. (dds5)


Lesenswert?

Es wäre möglich, dass der Compiler hier eine Bankumschaltung dazwischen 
einfügt.

  EECON2 = 0x55;      //unlock write
  EECON2 = 0xAA;      //unlock write

Dann funktioniert das unlock nicht mehr.

von holger (Gast)


Lesenswert?

So hab ich das mal bei PIC18 gemacht:


//###################################################################### 
#######
unsigned char WriteEEPROM(unsigned char adr, unsigned char dat)
//###################################################################### 
#######
{
 EEADR=adr;
 EEDATA=dat;
 EECON1bits.EEPGD=0; //Point to Data Memory
 EECON1bits.CFGS=0;   //Access Program Flash or Data EEPROM
 Nop();             //Sonst Fehler möglich ?
 EECON1bits.WREN=1;  //Enable Writes

 INTCONbits.GIE=0;   //Disable Ints
_asm
  MOVLW  0x55
  MOVWF  EECON2,0
  MOVLW  0xAA
  MOVWF  EECON2,0
_endasm
 EECON1bits.WR=1;
 INTCONbits.GIE=1;  //Enable Ints

//Poll EEIF Flag um zu sehen wann EEPROM Write vorbei ist
 while(PIR2bits.EEIF==0);
 PIR2bits.EEIF=0;      //Clear EEIF Flag

 EECON1bits.WREN=0;  //Disable Writes
}

von holger (Gast)


Lesenswert?

Und hier noch eine für 16F873

//Schreibt ein Byte ins EEPROM
//Beim 16F873 Adressen von 0 bis 127 möglich
void Write_EEProm(unsigned char adr, unsigned char data)
{
  RP1=1;
  RP0=0; //Bank 2 setzen
  EEDATA = data;    // Data in data register
  EEADR = adr;     // Write to adr

  RP0 = 1;   // Bank 3 setzen
  EEPGD=0;   //Daten EEprom (sicherheitshalber falls Bit 1 war)
  WREN = 1;  // Schreiben ermöglichen
  GIE=0;     // Disable interrupts wichtig !

  MOVLW(0x55);        // Writing 0x55 must be followed
  MOVWF(EECON2);      // immediately by writing 0xAA
  MOVLW(0xAA);        // to EECON2
  MOVWF(EECON2);
  BSF(WR);       // EECON1.WR=1 d.h. schreiben des EEPROM starten

  GIE = 1;   // Enable interrupts
  while(WR); // Warten bis WR auf 0 geht
  WREN = 0;  // Schreibschutz setzen, besser is das

  RP1=0;
  RP0=0; //Bank 0 setzen

  //Ein Verify fehlt hier noch ;)
}

von holger (Gast)


Lesenswert?

Und noch ein ganz altes Teil für 16F84

//Schreibt ein Byte ins EEPROM
void Write_EEProm(unsigned char addr, unsigned char data)
{
  WREN = 1;  // Schreiben ermöglichen

  EEDATA = data;    // Data in data register
  EEADR = addr;     // Write to addres

  RP0 = 1;   // Set page 1 to access EECON1, EECON2
  GIE=0;     // Disable interrupts

  MOVLW(0x55);        // Writing 0x55 must be followed
  MOVWF(EECON2);         // immediately by writing 0xAA
  MOVLW(0xAA);       // to EECON2
  MOVWF(EECON2);
  BSF(WR);       // EECON1.WR=1 d.h. schreiben des EEPROM starten

  GIE = 1;   // Enable interrupts
  EEIE=1;   //Interrupt bei EEPROM Write Complete
  RP0 = 0;   // Set page 0
//Jetzt entweder länger warten und Verify
//oder EEPROM-Interrupt + SLEEP + Verify

  SLEEP;
}

von Jens B. (nixiefreak)


Lesenswert?

@holger: Die Frage ist, für welchen Compiler die Codes sind, es sieht 
nach PICC aus.

Der PICC braucht im Code keine Bankanweisungen, daran kann es eigentlich 
nicht liegen.

von Martin (Gast)


Lesenswert?

@holger: siehe 1. Post, HiTech.

Der HiTech Compiler bringt doch eine Write und Read Funktion f"ur das 
interne EEPROM mit, warum nicht die verwenden? Hat bei mir jedenfalls 
bis jetzt immer problemlos funktioniert...

Gruss Martin

von Mario (Gast)


Lesenswert?

>Du beruecksichtigst schon, dass die EEPROM-Daten in Bank 1 liegen?

Muss ich das gesondert festlegen? Laut Datenblatt ist der Adressbereich 
des EEPROMS von 0 bis FF, und mein EEADR ist ja EEADR = 0x0F0;
Aus dem Datenblatt
"This device has 256 bytes of data EEPROM with an address
range from 0h to 0FFh."

>> allerdings sind meine Daten nach den Ausschalten immer
>> weg,

 >Wie stellst Du das genau fest?

Grundsätzlich lösche ich in dem Programm das EEPROM nie, frage aber die 
Speicheradresse ab und schalte eine LED an. Dies müsste ja dann direkt 
nach einem POR auch wieder leuchten.

Und wie gesagt, schreiben und lesen funktioniert, da ich meine LED 
aufgrund der Daten im EEPROM einschalte und sie auch leuchtet. D.h. wenn 
ich RC3 = 1 habe, wird geschrieben, dann gelesen und die LED geht an. 
ist beim nächsten Einschalten RC3 = 0, bleibt die LED aber aus, sollte 
aber an sein, da sich im EEPROM ja nichts geändert hat...

Gruß Mario

von Mario (Gast)


Lesenswert?

@Martin: Wie sieht die Read/Write funktion des HiTech Compilers denn 
aus? Kannte die bisher noch nicht

von Chris (Gast)


Lesenswert?

Die funktioniert einwandfrei. Dazu muss man dem Compiler aber die CPU 
mitteilen und auch die entsprechende Headerdatei einbinden, ohne die
funktioniert es auch nicht. Müsste <pic.h> sein.

von Mario (Gast)


Lesenswert?

und wie rufe ich die auf und was für parameter hat die?

von Vincent H. (vinci)


Lesenswert?

Da liegt so ein komisches .pdf im Ordner des installierten Compilers... 
dürfte sich "manual" nennen. ;)

->


#include <htc.h>
void eetest(void) {
unsigned char value = 1;
unsigned char address = 0;
// write value to EEPROM address
eeprom_write(address, value);
// read from EEPROM at address
value = eeprom_read(address);
}

These functions test and wait for any concurrent writes to EEPROM to 
conclude before performing the required operation. The eeprom_write() 
function will initiate the process of writing to EEPROM and this process 
will not have completed by the time that eeprom_write() returns. The new 
data written to EEPROM will become valid approximately four milliseconds 
later. In the above example, the new value will not yet be ready at the 
time when
eeprom_read() is called; however, because this function waits for any 
concurrent writes to complete before initiating the read, the correct 
value will be read. It may also be convenient to use the preprocessor 
symbol, _EEPROMSIZE, in conjunction with some of these access methods. 
This symbol defines the number of EEPROM bytes available for the 
selected chip.

von Chris (Gast)


Lesenswert?

Es gibt auch noch die Macros, EEPROM_WRITE() usw.
Sinnvoll wenn man nicht einen Stack verbrauchen will/kann.

von Mario (Gast)


Lesenswert?

Alles klar, danke, werde mir diese komische "Manual" mal anschauen :)

Bei allen hilfreichen Tipps und kommentaren, das eigentliche Problem, 
dass der PIC nach ausschalten die Daten auf dem EEPROM nicht speichert 
besteht leider immer noch.... Irgendwelche Ideen hierzu?

Gruß Mario

von Michael S. (rbs_phoenix)


Lesenswert?

Irgendwie kommt mir das komisch vor. Du Stellst deine ADC-Kofig ein, 
OSC, TRIS-Register und so weiter. Aber das erste, was du mit dem EEPROM 
machst, ist es zu beschreiben. Wenn du den PIC startest und RC3 ist auf 
low, schreibt er eine 0 ins EEPROM und danach ließt du die 0 wieder aus 
und die LED leutet folglich nicht.

Du musst nach der Konfig erstmal den Wert lesen, wenn der 1 ist, die LED 
anschalten und dann leutet diese auch. Dann darfst du danach nicht aber 
gleich wieder die EEPROM-Adresse mit der 0 überschreiben, wenn dein RC3 
auf 0 ist.

Also lesen, LED ggf. setzen und dann hätte ich ein Polling gemacht. Eine 
Taste setzt den Wert im EEPROM und eine andere Taste löscht den Wert. 
Dann sollte es eigentlich funktionieren


Mario schrieb:
> dass der PIC nach ausschalten die Daten auf dem EEPROM nicht speichert
> besteht leider immer noch

Ich weiß wie du das meinst, aber korrekt ist es, dass man wärend dem 
Durchlauf speichert, er die Daten aber auch ohne Strom halten kann. 
Speichern tut er nicht, wenn er aus is, das passiert vorher.



edit: Ganz abgesehen davon gehört ansich in jedes C-Programm für µCs 
eine Endlosschleife, meist nach der Konfiguration. Bei deinem Programm 
ist es im Moment so, dass, wenn deine Konfig abgeschlossen ist und du 
den Wert ins EEPROM schreibst und danach wieder liest, ist das Programm 
vorbei. ggf startet der PIC dann wieder neu, schreibt wieder die Konfig 
usw..

Mein Plan wäre so:

main(){
//Initialisierung
//EEPROM-Wert lesen, evtl LED an
while(1){
//RC3 gedrückt? Wenn ja, 1 ins EEPROM speichern
//RC4 gedrückt? Wenn ja, 0 ins EEPROM speichern
//EEPROM lesen, LED an- bzw. ausschalten
}
}

von Michael S. (rbs_phoenix)


Lesenswert?

Ich kenn mir ehrlich gesagt nicht so mit dem Hi-Tech-Compiler aus, aber 
ich dachte immer, das der halt C übersetzt. Und in C muss man doch 
eigentlich Variablen inklusive Datentyp definieren, oder? Woher weiß der 
Compiler, dass EE_DATA eine Variable ist, und welchen Typ er besitzt, 
also char oder int z.B. .
Und woher weiß der Compiler, dass der bei "ROT = AN", die LED anschalten 
soll? RC0 ist ja als ROT definiert, aber woher weiß er, dass AN "1" 
bedeutet? Wie gesagt, vielleicht ist das da ja eine Eigenheit, aber 
kommt mir irgendwie komisch vor.

von Mario (Gast)


Lesenswert?

@Michael: Die Init stammt aus dem eigentlichen Programm, dieses hier ist 
nur ein EEPROM Testprogramm, daher ADC und sonstige Inits.

Und mit der Schleife hast du natürlich recht, die ist wohl irgendwo 
untergegangen.

Die EE_DATA ist in der Header als unsigned char definiert, damit man 
auch einzelne Bits mit einem Namen komfortabel ansprechen kann, ähnlich 
wie die SFR des Controllers.

Und was AN ist weiß der Compiler aus dem
enum STATUS{
    AN,
    AUS
};
in den ersten zeilen des Quelltextes.
(Und bevor Fragen aufkommen, meine LEDs gehen an, wenn der Port = 0 ist)

Ich befürchte eher, dass die Daten auf dem EEPROM aufgrund irgendwelcher 
Einstellungen nicht gespeichert werden/verloren gehen, nicht wegen des 
Quelltextes.
Wenn jemand noch eine Idee hat, freue ich mich, sonst wende ich mich mal 
direkt an Microchip.

Gruß Mario

von Michael S. (rbs_phoenix)


Lesenswert?

Mario schrieb:
> Ich befürchte eher, dass die Daten auf dem EEPROM aufgrund irgendwelcher
> Einstellungen nicht gespeichert werden/verloren gehen, nicht wegen des
> Quelltextes.

Ich denke eher es liegt am Aufbau vom Programm:

Michael Skropski schrieb:
> Aber das erste, was du mit dem EEPROM
> machst, ist es zu beschreiben. Wenn du den PIC startest und RC3 ist auf
> low, schreibt er eine 0 ins EEPROM und danach ließt du die 0 wieder aus
> und die LED leutet folglich nicht.
>
> Du musst nach der Konfig erstmal den Wert lesen, wenn der 1 ist, die LED
> anschalten und dann leutet diese auch. Dann darfst du danach nicht aber
> gleich wieder die EEPROM-Adresse mit der 0 überschreiben, wenn dein RC3
> auf 0 ist.
>
> Also lesen, LED ggf. setzen und dann hätte ich ein Polling gemacht. Eine
> Taste setzt den Wert im EEPROM und eine andere Taste löscht den Wert.
> Dann sollte es eigentlich funktionieren

Ob dein Ausgang die LED bei 0 oder 1 anschaltet ist ja egal. Fakt ist, 
du schreibst die EEPROM-Zelle, bevor du sie ausliest. Das ist auch nach 
dem Starten des PICs so. D.h. bevor du die Chance hast, den 
gespeicherten Wert auszulesen, überschreibst du ihn schon wieder.

von Mario B. (mmb)


Lesenswert?

Achso, jetzt versteh ich! Is ja logisch. Aber draufgekommen wär ich 
net...

Also das Programm geht dann natürlich auch!! Super, vielen Dank, war 
schon ganz kurz vorm verzweifeln!!

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.