PIC16F EEPROM Schreibfehler

Ich entwickle auf einem PIC16F1936 mit der MPLAB X IDE mit dem XC8-Compiler. Ich habe dieses Projekt erhalten, bei dem ich die Software einer Leiterplatte "aktualisieren" muss, damit sie über eine RS232-Verbindung mit einem externen Tool verbunden werden kann.

Ich habe den Link funktioniert und ich habe auch überprüft, ob das übertragene Datum korrekt ist. Das Problem, das ich habe, ist mit einer bestimmten Funktion, die die Sollwerte für die Leiterplatte kalibriert. Ich kann nicht zu viel über die genaue Funktion der Platine sagen, also tut es mir leid, dass ich nicht alles gepostet habe. Außerdem habe ich einen Großteil des Codes dieses Projekts geerbt, wie zum Beispiel den Code, den ich Ihnen gleich zeigen werde.

Die Kalibrierfunktion funktioniert also so: Sie wird aufgerufen, sobald das Tool den entsprechenden Befehl an die Platine sendet. Danach liest die Funktion (abhängig vom gesendeten Befehl) den Wert des summierten Werts von 40 Werten aus dem ADC und speichert diesen im EEPROM. Hier wird es richtig versaut! Die Kalibrierung funktioniert einwandfrei, wenn ich die Platine auf Null stellen muss, das Problem tritt auf, wenn ich MAX einstellen muss. Oh! Und der Code ist bis auf die EEPROM-Adresse identisch...

Hier ist der Code für die Kalibrierung:

if (zero == 1)
{
    WR = 1;                                         // Set EEPROM_WRITE flag
    EEPROM_WRITE(0x05,(AN1_sum >> 0x08));           // load MSbyte of AN1_sum into NV memory location 1
    EEPROM_WRITE(0x06,(AN1_sum & 0xff));            // load LSbyte of AN1_sum into NV memory location 2
    EEPROM_WRITE(0x07,(AN4_sum >> 0x08));           // load MSbyte of AN4_sum into NV memory location 3
    EEPROM_WRITE(0x08,(AN4_sum & 0xff));            // load LSbyte of AN4_sum into NV memory location 4

    zero1 = AN1_sum;                                // update volatile memory for zero1
    zero4 = AN4_sum;                                // update volatile memory for zero4
    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x09, 2);                          //Write 2 to the EEPORM

    while(WR){                                      //Loop till WR flag is reset by EEPROM CONTROLLER
        MAL = 1;                                        //Light MAL until WR is reset
    }
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
    RESET();
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
}
else if (MAX == 1)
{
    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x01,(AN1_sum >> 0x08));           // load MSbyte of AN1_sum into NV memory location 5
    EEPROM_WRITE(0x02,(AN1_sum & 0xff));            // load LSbyte of AN1_sum into NV memory location 6
    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x03,(AN4_sum >> 0x08));           // load MSbyte of AN4_sum into NV memory location 7
    EEPROM_WRITE(0x04,(AN4_sum & 0xff));            // load LSbyte of AN4_sum into NV memory location 8

    MAX1 = AN1_sum;                                 // update volatile memory for MAX1
    MAX4 = AN4_sum;                                 // update volatile memory for MAX4

    WR = 1;                                         //Set EEPROM_WRITE flag
    EEPROM_WRITE(0x9, 3);                           //Write 3 to the EEPROM

    while(WR){                                      //Loop till WR flag is reset by EEPROM CONTROLLER
        MAL = 1;                                        //Light MAL until WR is reset
    }
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
    RESET();
    for(KILLTIME = 0; KILLTIME <= 200000; KILLTIME++);
}

Nach dem Reset startet die Platine neu und durchläuft diesen Initialisierungsprozess:

MAX1 = EEPROM_READ(0x01);                                               
MAX1 = (MAX1 << 8) + EEPROM_READ(0x02);
MAX4 = EEPROM_READ(0x03);                                 
MAX4 = (MAX4 << 8) + EEPROM_READ(0x04); 
zero1 = EEPROM_READ(0x05);                                           
zero1 = (zero1 << 8) + EEPROM_READ(0x06);                          
zero4 = EEPROM_READ(0x07);                                 
zero4 = (zero4 << 8) + EEPROM_READ(0x08); 

Einfach genug, oder? Dies ist nur Zeit im Code, wo MAX und Null konfiguriert sind.

Ich habe keine Ahnung, warum dies nicht funktioniert. MAX sollte der Wert von AN1 und AN4 zum Zeitpunkt der Ausführung sein. Ich habe die EEPROM-Adressen vertauscht und die Namen der Variablen geändert, um sicherzustellen, dass MAX und ZERO nicht an anderer Stelle im Code überschrieben werden. Kein Erfolg. MAX will nur der richtige Wert sein, wenn ich sage MAX1 = x und MAX 4 = y. Es kann nichts mit den Werten von AN1 und AN4 sein, da sie für TARE gut funktionieren, egal was ihr Wert ist.

Irgendwelche Ideen?

Nur um hinzuzufügen, ich habe die folgenden Lösungen versucht:

  1. Ich habe die EEPROM-Adressen so vertauscht, dass MAX auf Adressen schreibt. Ich meine, dass MAX jetzt auf 0x05-0x08 geschrieben wird und ZERO auf 0x01-0x05 geschrieben wird. Trotzdem habe ich das gleiche Problem. Der Wert vom Sensor wird korrekt auf NULL geschrieben, aber nicht auf MAX.

  2. Ich habe mit der WR-Flagge herumgespielt, indem ich mehr platziert und sie vollständig entfernt habe. KEINE ÄNDERUNG.

  3. Ich habe versucht, die Werte von AN1_sum und AN4_sum in einer temporären Variablen zu speichern, sobald die Kalibrierungsfunktion gestartet wird, und stattdessen diese Variablen verwendet.

  4. Ich habe versucht, die Rollen von ZERO und MAX umzukehren. Damit meine ich, dass ich ZERO auf den maximalen Sollwert und MAX auf das Minimum setze. Ich habe festgestellt, dass ZERO genau eingestellt ist und der Wert, den es hat, den Wert des MAX beeinflussen kann. Zum Beispiel habe ich zuerst angewendet 45 auf beide Kanäle eingestellt und dann den MAX eingestellt. Nach der Kalibrierung hatte MAX einen Wert von 26. Ich habe dann 198 an beide Kanäle angelegt und NULL gesetzt. ZERO hatte einen Endwert von 198, während MAX auf 48 geändert wurde!

Ich weiß seit einiger Zeit, dass MAX der Übeltäter ist, aber ich weiß nicht, warum oder wie das passiert. Ich bin den Rest des Codes durchgegangen und habe überprüft, ob MAX in irgendeiner Weise betroffen ist, aber das ist nicht der Fall.

Wie Sie sagten: "Ich habe festgestellt, dass ZERO genau eingestellt ist und der Wert, den es hat, den Wert von MAX beeinflussen kann.", schlage ich vor, dass Sie alle Schreiboperationen auf ZERO entfernen, nur Operationen auf MAX durchführen und überprüfen.

Antworten (2)

Versuchen Sie, das zweite Argument von EEPROM_WRITE() in den richtigen Typ umzuwandeln. Das EEPROM ist in 8-Bit-Speicherplätzen angeordnet, und wie es aussieht, versuchen Sie beim Ausführen von (AN4_sum & 0xff), die unteren 8 Bits einer Ganzzahl (oder eines größeren Typs) zu maskieren, aber der übergebene Typ bleibt gleich und das Verhalten von diese Funktion kann unvorhersehbar sein. Ich fand es beim Anwenden von Masken immer nützlich, sie für die gesamte Länge der Variablen zu schreiben, die ich zu maskieren versuche, dh (AN4_sum & 0x00ff), damit immer klar ist, was los ist, besonders wenn Sie Code lange danach überprüfen wurde geschrieben. Hoffe das hilft ein bisschen...

Es hört sich so an, als hätten Sie unzureichende Debugging-Unterstützung, was Ihre Arbeit unnötig erschwert.

Außerdem erwähnen Sie mehrmals „das Problem“, aber Sie sagen uns nie genau, welche Symptome Sie beobachten, was es für uns schwierig macht, Ihnen zu helfen. Ist eine LED dunkel geblieben, obwohl Sie erwartet hatten, dass sie blinkt (oder umgekehrt)? Zeigt eine Anzeige mit 7-Segment-Ziffern nicht die erwartete Zahl an?

Wenn ich du wäre,

  1. Ich würde das Datenblatt für den von mir verwendeten Prozessor lesen , insbesondere den Abschnitt "Using the Data EEPROM" Seite 116-117. Es scheint zu sagen, dass das WR-Bit nach dem Setzen der EEPROM-Adresse und der Datenregister gesetzt werden soll, sodass die Zeile "WR = 1;" am Anfang eines Codeabschnitts scheint fehl am Platz zu sein.

  2. Ich würde die FAQ lesen: "Wie schreibe und lese ich Daten aus dem EEPROM mit dem XC8-Compiler?"

  3. Ich würde das Benutzerhandbuch für den Compiler lesen -- "MPLAB XC8 C Compiler User's Guide" , insbesondere den Abschnitt "EEPROM-Zugriffsfunktionen" auf S. 108.

  4. Wenn ich 2 Code-Blöcke habe, die fast dasselbe tun, versuche ich, sie umzugestalten, sodass ich 1 Funktion habe, die all die üblichen Dinge erledigt, und ich rufe diese Funktion von 2 Stellen aus auf. In diesem Fall haben Sie (mindestens) 4 Stellen, die einen 16-Bit-Wert in das EEPROM schreiben, also könnte ich alle 4 so umgestalten, dass sie so etwas aufrufen:

    void EEPROM_WRITE_16( char address, int value ){
        char MSByte = (value >> 0x08) & 0xff;
        char LSByte = value & 0xff;
        if(eeprom_read(address) != MSByte){
            eeprom_write(address, MSByte); // load MSbyte into given EEPROM address
        };
        address++;
        if(eeprom_read(address) != LSByte){
            eeprom_write(address, LSByte); // load LSbyte into following EEPROM address
        };
    }
    
  5. Immer wenn ich etwas mit EEPROM mache, füge ich ein paar "Debug"-Routinen in die Firmware ein, um den Inhalt des EEPROM auszulesen und sie irgendwohin zu schicken, wo ein Mensch sie lesen kann - vielleicht an einen UART-Debug-Port oder, falls einer verfügbar ist, eine LCD- oder LED-Anzeige; vielleicht unbedingt, kurz beim Einschalten.

  6. Manchmal füge ich beim Debuggen schwieriger Probleme zusätzliche "Debug"-Befehle hinzu, um neue Werte in das EEPROM zu schreiben. Wenn diese Funktionen dieselbe(n) Routine(n) aufrufen, die ich an anderer Stelle zum Schreiben in das EEPROM verwende, kann ich diese Routinen mehr oder weniger isoliert testen.

  7. Manchmal sichere ich das Hauptprogramm, lege es beiseite und erstelle ein neues Testprogramm, das als exakte Kopie des Hauptprogramms beginnt. Solange das Testprogramm die unerwarteten Problemsymptome aufweist, entferne ich weiterhin Funktionen, von denen ich glaube , dass sie nichts mit dem Problem zu tun haben, bis ich am Ende ein SSCCE habe – Short, Self Contained, Compilable, Example . Dann poste ich dieses kurze Testprogramm, wenn ich um Hilfe bitte. Ein solches Programm erhält im Allgemeinen viel schneller eine Antwort als entweder (a) das Posten des ursprünglichen, extrem langen Programms oder (b) das Posten nur von Fragmenten des vollständigen Programms, von denen ich glaube, dass sie mit dem Problem zusammenhängen.

Die letzten 3 Schritte (zusätzliches Debug-Scaffolding und SSCCE) erleichtern es, schnell verschiedene Lösungsvorschläge zu testen und zu sehen, ob sie wirklich für meinen Code funktionieren. (Vorschläge wie „Schleife, bis der vorherige Schreibvorgang abgeschlossen ist, bevor ein neuer Lesevorgang gestartet wird“ (a) und Seite 108 des „MPLAB XC8 C Compiler User's Guide“ ; „stellen Sie sicher, dass der Linker auf „Link the Peripheral Library“ eingestellt ist“ (b ) ; '[ersetze] die C-Aufrufe durch die genauen Inline-Assembler-Anweisungen, die in ... dem Datenblatt beschrieben sind' (c) ; etc.).

Viel Glück!