EEPROM und FLASH- Programmspeicher
beschreiben und auslesen bei PIC16F87x

PIC16F871 hat 64 Byte EEPROM
PIC16F877 hat 256 Byte EEPROM
EEPROM kann bis 1.000.000 Schreibzyklen
EEPROM wird angewendet, wenn irgend welche Einstellungen gespeichert werden sollen oder erreichte Zustände vor letztem Ausschalten wiederhergestellt werden sollen.

Bei PIC16F87x-Serie ist es möglich in Programmspeicher zu schreiben. Allerdings hat er nicht so viele Schreibzyklen wie EEPROM.
Er hält nur 1000 Schreibzyklen aus.
PIC16F871 hat 2 k und PIC16F877 hat 8k Programmspeicher. Jede Speicherstelle des Programmspeichers ist 14 Bit groß. Dass heißt, dass wir in eine Speicherstelle 1 Byte und noch 6 Bit speichern können oder ein Wert von 0 bis 16383 ablegen.
Es ist zu beachten, dass man nicht das Programm überschreibt.
Dafür empfehle ich Programm mit Hilfe " #pragma origin 206 " Anweisung weiter in Speicher zu platzieren. Somit können wir sicher den Bereich von 5 bis 205 beschreiben.
Am Speicherstelle 4 befindet sich Interruptvektor und ab Adresse 206 fängt Programm an. Es ist natürlich nur ein Beispiel, Ihr Programm muss nicht unbedingt ab Adresse 206 anfangen.

Anwendungsgebiet: benutzerdefinierte Einstellungen speichern, Menütexte ändern (bei LCD), Kalibrierungswerte speichern, Bootloader.

Damit Lesen und Speichern von EEPROM und Flash klappt, es muss in dem Konfigurationswort erlaubt werden (sehe Beispiel).

Folgendes Beispielprogramm zeigt Lesen und Speichern von EEPROM und Flash-Speicher.
Bei Einschalten des Microcontrollers wird serielle Kommunikation initialisiert. Danach wartet Programm auf einen Befehl von dem PC.
Befehle sind als Zahl zu übertagen, nicht als ASCII -Zeichen.

1 : Flash lesen an Adresse 99 sendet niedere Datenbyte sendet obere Datenbyte
2 : Flash schreiben an Adresse 99 erwartet niedere Datenbyte erwartet obere Datenbyte
3 : EEPROM lesen an Adresse 0 sendet Datenbyte  
4 : EEPROM schreiben an Adresse 0 erwartet Datenbyte  

Nach dem Ausführen des Befehls erwartet Programm das Nächste.

Schaltplan zum Anschluss an serielle Schnittstelle.
Zum Verbinden mit dem PC ist ein Nullmodemkabel vorgesehen.
Programm zum Senden und Empfanden über serielle Schnittstelle.

// Testprogramm: Programmspeicher (FLASH) und interne EEPROM beschreiben und lesen.
// Serielle Kommunikation mit (9600,N,8,1) TX==>RC6, RX==>RC7 TTL-RS232-Conwerter

// 20 MHz
#include <D:\cc5\16F871.H>

// Speicherschutz12,13,4,5=aus,Debug1,1=aus,ProgrammFlash9=an,EEpromRead8=an,
// NiedervoltProgr7=aus, NiederVoltReset6=an,EinschaltTimer3=an,
// WachDogTimer2=aus,Oszillator0,1=XC
#pragma config |= 0b.11.111101.11.00.10

#pragma origin 100          // Adresse des Programms


//******************************************************************************
void InitUSART()
{
    BRGH=1;
    SPBRG=129;              // (9600 baud @ 20MHz input clock)
    SPEN = 1;               // Set_Serial_Pins;
    SYNC = 0;               // Set_Async_Mode;
    TX9 = 0;                // Set_8bit_Tx;
    RX9 = 0;                // Set_8bit_Rx;
    CREN = 1;               // Enable_Rx;
    TXEN = 1;               // Enable_Tx;
    RCIE=0;                 // Rx Interrupt aus
}

//++++++++++++++++++++++ FLASH SREIBEN  +++++++++++++++++++++++++++++++++++++++++

void FlashWR(uns16 adresse,uns16 Data)
{

    EEADR = adresse.low8;   // Adresse in Adressregister übertragen
    EEADRH = adresse.high8;
    EEDATA = Data.low8;     // Daten in Datenregister übertragen
    EEDATH = Data.high8;
    EEPGD=1;                // Auswahl Programmspeicher lesen oder EEPROM
    WREN=1;                 // Schreiben ins EEPROM erlauben
    GIE=0;                  // Interrups verbieten
    EECON2=0x55;
    EECON2=0xAA;
    WR=1;                   // Starten des Sreibens
    nop2();                 // 2 Zyklen zum Schreiben
    GIE=1;                  // Interrups erlauben
    WREN=0;                 // Schreiben ins EEPROM verbieten
}

//++++++++++++++++++++++ FlashWR LESEN  +++++++++++++++++++++++++++++++++++++++++

uns16 FlashRD(uns16 adresse)
{
    uns16 antwort;
    EEADR = adresse.low8;   // Adresse in Adressregister übertragen
    EEADRH = adresse.high8;
    EEPGD=1;                // Auswahl: Programmspeicher lesen oder EEPROM
    RD=1;                   // Starten des Lesens
    nop2();                 // 2 Zyklen zum Speicher lesen
    antwort.low8 = EEDATA;  // Daten aus Datenregister auslesen
    antwort.high8 = EEDATH;
    return antwort;
}

//++++++++++++++++++++++ EEPROM SREIBEN  +++++++++++++++++++++++++++++++++++++++++

void EEPROMWR(char adresse,char Data)

    EEADR = adresse;        // Adresse in Adressregister übertragen
    EEDATA = Data;          // Daten in Datenregister übertragen
    EEPGD=0;                // Auswahl: Programmspeicher lesen oder EEPROM
    WREN=1;                 // Schreiben ins EEPROM erlauben
    GIE=0;                  // Interrups verbieten
    EECON2=0x55;
    EECON2=0xAA;
    WR=1;                   // Starten des Sreibens
    nop2();                 // 2 Zyklen zum Schreiben
    GIE=1;                  // Interrups erlauben
    WREN=0;                 // Schreiben ins EEPROM verbieten
}

//++++++++++++++++++++++ EEPROM LESEN  +++++++++++++++++++++++++++++++++++++++++

char EEPROMRD(char adresse)
{
    char antwort;
    EEADR = adresse;        // Adresse in Adressregister übertragen
    EEPGD=0;                // Auswahl: Programmspeicher lesen oder EEPROM
    RD=1;                   // Starten des Lesesn
    nop2();                 // 2 Zyklen zum Speicher lesen
    antwort = EEDATA;       // Daten aus Datenregister auslesen
    return antwort;
}
//**************************************************************************

void main(void)
{
    uns16 a;                // Variablen
    char i;
    TRISC=0b.1011.1100;     // RC6>TX, RC7<RX
    InitUSART();            // Hardwareschnittstelle des PICs einstellen

    while(1)                // Ganzes Programm ist Endlosschleife
    {
        while(!RCIF);       // Warte auf Empfang
        i=RCREG;            // Empfange Befehl
        switch(i)           // Entschlussele Befehl
        {

            case 1:                 // Falls Wert 1: empfangen
                a=FlashRD(99);      // Programmspeicher an Stelle 99 lesen
                while(!TXIF);       // Prüfen, ob Sender frei ist
                TXREG = a.low8;     // Niederes Datenbyte senden
                while(!TXIF);       // Prüfen, ob Sender frei ist
                TXREG = a.high8;    // Oberes Datenbyte senden
                break;

            case 2:                 // Falls Wert 2: empfangen
                while(!RCIF);       // Warte auf Empfang
                a.low8=RCREG;       // Niederes Datenbyte empfangen
                while(!RCIF);       // Warte auf Empfang
                a.high8=RCREG;      // Oberes Datenbyte empfangen
                FlashWR(99,a);      // Programmspeicher an Stelle 99 schreiben
                break;
            case 3:                 // Falls Wert 3: empfangen
                a=EEPROMRD(0);      // EEPROM an Stelle 0 lesen
                while(!TXIF);       // Prüfen, ob Sender frei ist
                TXREG = a;          // Datenbyte senden
                break;

            case 4:                 // Falls Wert 4: empfangen
                while(!RCIF);       // Warte auf Empfang
                a=RCREG;            // Datenbyte empfangen
                EEPROMWR(0,a);      // EEPROM an Stelle 0 schreiben
                break;
        }                   // Ende des Auswals
    }                       // Ende der Schleife
}                           // Ende des Hauptprogramms

< Zur Startseite