- 12V Akku mit 280 Ah bauen         
Seite 1 von 5 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 44

Thema: EEPROM - ausgelesener Wert ist ungenau

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied Avatar von basteluwe
    Registriert seit
    15.11.2012
    Beiträge
    131

    EEPROM - ausgelesener Wert ist ungenau

    Anzeige

    Praxistest und DIY Projekte
    Hallo Forum,
    ich bin mal wieder an einem kleinen Arduino FM-Radio dran, diesmal mit RDA5807M, Arduino Pro Mini und OLED 128x32.
    Ich speichere die aus dem RDA ausgelesene Frequenz im EEPROM, um bei Neustart bei der selben Station zu beginnen.
    Mein Problem ist die Genauigkeit. Manchmal stimmt die Startfrequenz genau, oft liegt sie aber nach Reset oder Neustart mehr oder weniger neben der vorherigen. Ich hab versuchsweise kleine Pausen vor und nach dem EPROM-Schreiben eingefügt. Hat nichts gebracht. Die sind zwar immer in der Nähe des Sollwerts aber selten genau wo sie sollen.
    Hier der Code:
    Code:
    /**************************************************************************
     * FM-Radio mit RDA5708M, Arduino Pro Mini 3.3V und OLED 128x32           *
     * Steuerung über vier Drucktaster:                                       *
     *    button 1 - volume down                                              *
     *    button 2 - volume up                                                *
     *    button 3 - scan frequency down                                      *
     *    button 4 - scan frequency up                                        *
     * Das OLED-display zeigt zwei Zeilen:                                    *
     *  1- "Empfangsfrequenz"                                                 *
     *  2- "Volume level" + "Batteriespannung"                                *
     *      alternativ bei Unterschreiten von 3,3V "CHARGE BATTERY"           *           
     * Die Empfangsfrequenz wird im EEPROM gespeichert.                       *
     *                                                                        *
     * U.Galepp 2018                                                          *
     **************************************************************************/
    
    #include <Arduino.h>
    #include <Wire.h>
    #include <radio.h>
    #include <RDA5807M.h>
    #include "U8glib.h"
    #include <EEPROM.h>
    
    U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE);  // Auswahl des OLED Typs
    
    #define FIX_BAND     RADIO_BAND_FM            // ausgewähltes Band ist FM
    #define FIX_VOLUME   3                        // Lautstärke beim Start
    
    RDA5807M radio;                               // create an instance of class for RDA5807M chip
    
    int volume = FIX_VOLUME;
    
    int button_1 = 4;                             // Taster für volume up an D4
    int button_2 = 5;                             // Taster für volume down an D5
    int button_3 = 6;                             // Taster für scan up an D6
    int button_4 = 7;                             // Taster für scan down an D7
    int buttonState_1 = 0;
    int buttonState_2 = 0;
    int buttonState_3 = 0;
    int buttonState_4 = 0;
    int frequency;
    char vol[2];
    float volts;
    char akku[4];
    
    /*** setup ***/
    void setup()
      { 
      Serial.begin(57600);
      Serial.println("Radio...");
      delay(200);
      
      radio.init();                               // Radio initialisieren
      radio.setBand(FIX_BAND);
      EEPROM.get(0, frequency);
      delay(100);
      radio.setFrequency(frequency);
      delay(100);
      radio.setVolume(volume);
      
      pinMode(button_1, INPUT);                   // Taster-Pins als Eingang definieren
      pinMode(button_2, INPUT);                   // -||-
      pinMode(button_3, INPUT);                   // -||-
      pinMode(button_4, INPUT);                   // -||-
      digitalWrite(button_1, HIGH);               // Pull-Up Widerstände aktivieren
      digitalWrite(button_2, HIGH);               // -||-
      digitalWrite(button_3, HIGH);               // -||-
      digitalWrite(button_4, HIGH);               // -||-
      } 
    
    /*** Subroutine Spannungsmessung ***/
    void measureVolt()
      { analogReference(INTERNAL);
        volts = (float)analogRead(A0)*6.1/1000;}
    
    /*** Subroutine Datenanzeige auf OLED ***/
    void displayData()
      {
       u8g.firstPage(); 
        do {
          u8g.setFont(u8g_font_helvB14);
          char s[12];
          radio.formatFrequency(s, sizeof(s));
          u8g.drawStr( 10, 15, s);
          u8g.setFont(u8g_font_unifont);
          
          if(volts > 3.3)                         // wenn Vcc > 3.3V zeige "Volume" & "Volt"       
            {
            u8g.drawStr( 0, 32, "Vol:");
            sprintf (vol, "%d", volume);          // Umwandlung int "volume" zu char "vol"
            u8g.drawStr( 35, 32, vol);
            u8g.drawStr( 60, 32, "Bat:");
            dtostrf(volts, 2, 1, akku);           // Umwandlung float "volts" zu char "akku"  
            u8g.drawStr( 95, 32, akku);
            u8g.drawStr( 119, 32, "V");
            }
           else                                   // wenn VCC >= 3.3V zeige "CHARGE BATTERY"
           {
            u8g.drawStr(8, 32,"CHARGE BATTERY");
           }
        } while( u8g.nextPage() );
      }
       
    /*** main loop ***/
    void loop() 
      {
      measureVolt();                              // Batteriespannung messen
      
      displayData();                              // alle Daten auf OLED anzeigen
    
    /*  frequency = (radio.getFrequency());       // nur zum Test was gespeichert ist
        Serial.print("Frequenz: ");                 
        Serial.println(frequency);
    */
       
      if(!digitalRead(button_1) ) {               // wenn Taster 1 gedrückt, Volume einen Schritt runter
       while(!digitalRead(button_1) )             // warten auf Taster loslassen == HIGH
          {delay(10);}
          volume --;
          if (volume < 0) volume = 0;
          radio.setVolume(volume);
          delay(100);
          } 
            
      if(!digitalRead(button_2) ) {               // wenn Taster 2 gedrückt, Volume einen Schritt hoch
       while(!digitalRead(button_2) )             // warten auf Taster loslassen == HIGH
          {delay(10);}
          volume ++;
          if (volume == 16) volume = 15;
          radio.setVolume(volume);
          delay(100);
         } 
         
      if(!digitalRead(button_3) ) {               // wenn Taster 3 gedrückt, abwärts scannen   
       while(!digitalRead(button_3) )             // warten auf Taster loslassen == HIGH
          {delay(10);}
          radio.seekDown();
          delay(100);
          frequency = (radio.getFrequency());     // neue Frequenz aus RDA5807M auslesen
          delay(100);
          EEPROM.put(0, frequency);               // neue Frequenz in EEPROM speichern
          delay(100);
          }
          
      if(!digitalRead(button_4) ) {               // wenn Taster 4 gedrückt, aufwärts scannen   
       while(!digitalRead(button_4) )             // warten auf Taster loslassen == HIGH
          {delay(10);}
          radio.seekUp();
          delay(100);
          frequency = (radio.getFrequency());     // neue Frequenz aus RDA5807M auslesen
          delay(100);
          EEPROM.put(0, frequency);               // neue Frequenz in EEPROM speichern
          delay(100);
          }
      }
    Ich habe heute erst mit EEPROM begonnen, wahrscheinlich habe ich einen Denkfehler aber wo?
    Für Tips wäre ich dankbar.

    Gruß Uwe

  2. #2
    shedepe
    Gast
    Könntest du ungenau mal genauer spezifizieren. Habe deinen Code jetzt nicht gelesen. Aber prinzipiell: Wenn du einen Wert im EEPROM speicherst und nicht total viel Pech hast und dir kosmische Strahlung ein Bit kippen lässt, dann wirst du diesen Wert auch wieder auslesen.

    Dein Problem könnte eventuell daran liegen, dass du die Frequenz als int ausliest, die EEPROM library aber nur bytes erwartet.
    EEPROM.read() gibt aufjedenfall nur einzelne Bytes zurück.

  3. #3
    Erfahrener Benutzer Lebende Robotik Legende Avatar von PICture
    Registriert seit
    10.10.2005
    Ort
    Freyung bei Passau in Bayern
    Alter
    72
    Beiträge
    11.077
    Hallo!

    @ basteluwe

    Ich vermute, dass der Fehler durch AFC ("Automatic Frequency Control" -> automatische steuerung der Frequenz) verursacht ist. Auf der "page 9" des Dateblattes habe ich im Register 04H das AFCD "default=0" gefunden. Das bedeutet, dass AFC aktiv ist und du könntest probieren das AFCD "disable=1" programmieren und schauen ob das hilft.
    MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied Avatar von basteluwe
    Registriert seit
    15.11.2012
    Beiträge
    131
    Zitat Zitat von shedepe Beitrag anzeigen
    Könntest du ungenau mal genauer spezifizieren. Habe deinen Code jetzt nicht gelesen. Aber prinzipiell: Wenn du einen Wert im EEPROM speicherst und nicht total viel Pech hast und dir kosmische Strahlung ein Bit kippen lässt, dann wirst du diesen Wert auch wieder auslesen.

    Dein Problem könnte eventuell daran liegen, dass du die Frequenz als int ausliest, die EEPROM library aber nur bytes erwartet.
    EEPROM.read() gibt aufjedenfall nur einzelne Bytes zurück.
    Mit Ungenauigkeit meinte ich, ich speichere z.B. den Wert 8820, was 88,20 MHz bedeutet. Bei Neustart tuned der chip aber z.B. auf 8800, also 88,0 MHz. Diese Abweichung ist nicht konstant! Manchmal stimmt der Wert auch.
    Ich weiß, dass EEPROM.read() bzw. EEPROM.write() nur bytes akzeptieren. Ich verstehe diese Seite aber so, das EEPROM.put() bzw. EEPROM.get() auch int oder float akzeptieren. Oder nicht?

    Gruß Uwe

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    16.10.2008
    Ort
    Kehnert
    Beiträge
    1.159
    Ich hatte mal ein Problem mit einem AVR, wollte mit der Zuweisung EEPROMVARIABLE = WERT abspeicher. Da musste ich
    feststellen, dass die erste EEPROM-Zelle warscheinlich nicht funktioniert. Nachdem ich eine EEPROM-Dummyfunktion im
    Quelltext davor reingeschrieben habe, lief es.
    VG Micha
    Was brauche ich für Werkzeug - in dieser Reihenfolge seht ihr es:
    Vorschlaghammer, Notebook, BASCOM, Lötequipment, Rohrzange, Bolzenschneider ...

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    .. musste ich feststellen, dass die erste EEPROM-Zelle warscheinlich nicht funktioniert. Nachdem ich eine EEPROM-Dummyfunktion ..
    Es ist sicher fünf Jahre her, da hatte ich dasselbe Problem festgestellt und etliche Hinweise auf ne Dummyfunktion gefunden. Seit der Zeit definiere*) ich wie folgt und habe keine Probleme:
    Code:
    // ###>>> Byte-Array, das erste Byte des EEPROMS gilt als nicht vertrauenswürdig
      uint8_t   firstByteDummy      EEMEM; 
      uint8_t   eeDUMMYbytes [100]  EEMEM;  // Dummies
      uint8_t   eeBytes [12]        EEMEM;  // ?? Allzweckbytes ??
      uint16_t  eeSrvoff[12]        EEMEM;  // Servo-Position - Offset
      u8    SVT[12][11]             EEMEM;  // Servotexte
    *) vgl. Kernighan-Ritchie, Vorwort zur deutschen Ausgabe
    Definition: Eigenschaft und Speicherplatz
    Deklaration: nur Eigenschaft
    Ciao sagt der JoeamBerg

  7. #7
    shedepe
    Gast
    Dass es einzelne Zellen defekt sind, kann passieren. Jedoch konnte ich keine Hinweise finden, dass Zelle 0 per se kaputt ist.

    fas EEPROM.put() bzw. EEPROM.get() auch int oder float akzeptieren
    Stimmt. Da Arduino C++ ist, kann man die Funktionen natürlich entsprechend überladen.

    Ein Dummy Read Write auf den EEPROM ist eine gute Idee.
    Ein weiterer Punkt auf den das Datenblatt hinweist, ist dass der EEPROM Inhalt korrumpiert werden kann, wenn man versucht bei zu geringer Versorgungsspannung zu lesen oder zu schreiben. Das ist in diesem Fall aber denke ich auszuschließen. (Nur der Vollständigkeit halber erwähnt)

  8. #8
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    .. Ein Dummy Read Write auf den EEPROM ist eine gute Idee ..
    Danke. So weit ich mich erinnern kann stammt die Idee aus diesem Forum (oder aus mikrocontroller.net).

    .. Ein weiterer Punkt auf den das Datenblatt hinweist, ist dass der EEPROM Inhalt korrumpiert werden kann ..
    Genau das hatte ich vorhin vergessen zu erwähnen und wollte es eben nachtragen. Auf dem Arduino Pro Mini dürfte ja ein mega328p drauf sein, zu dem schreib t das Datenblatt :
    Zitat Zitat von Atmel-42735B-ATmega328/P_Datasheet_Complete-11/2016
    ..
    12.4.2. Preventing EEPROM Corruption
    During periods of low VCC, the EEPROM data can be corrupted because the supply voltage is too low for
    the CPU and the EEPROM to operate properly. These issues are the same as for board level systems
    using EEPROM, and the same design solutions should be applied.
    An EEPROM data corruption can be caused by two situations when the voltage is too low. First, a regular
    write sequence to the EEPROM requires a minimum voltage to operate correctly. Secondly, the CPU itself
    can execute instructions incorrectly, if the supply voltage is too low.
    EEPROM data corruption can easily be avoided by following this design recommendation:
    Keep the AVR RESET active (low) during periods of insufficient power supply voltage. This can be done
    by enabling the internal Brown-out Detector (BOD). If the detection level of the internal BOD does not
    match the needed detection level, an external low VCC reset Protection circuit can be used. If a reset
    occurs while a write operation is in progress, the write operation will be completed provided that the
    power supply voltage is sufficient.
    ..
    Insgesamt lohnt es sich alle Abschnitte des Datenblatts zum EEPROM-schreiben-und-lesen wenigstens einmal ordentlich durchzulesen.

    Ich komme auch wirklich nicht klar wie Du Deine Umrechnung ".. ich speichere z.B. den Wert 8820, was 88,20 MHz .." machst und in welchem Format die erfolgt. Kannst Du uns bitte darüber auch aufklären?
    Geändert von oberallgeier (08.10.2018 um 11:56 Uhr) Grund: Rechenweg
    Ciao sagt der JoeamBerg

  9. #9
    HaWe
    Gast
    Zitat Zitat von basteluwe Beitrag anzeigen
    Mit Ungenauigkeit meinte ich, ich speichere z.B. den Wert 8820, was 88,20 MHz bedeutet. Bei Neustart tuned der chip aber z.B. auf 8800, also 88,0 MHz. Diese Abweichung ist nicht konstant! Manchmal stimmt der Wert auch.
    tbh, ich habe den vagen Verdacht, dass der "Abrundungsfehler" nicht durch Datenkorruption zu erklären ist, denn 8820 und 8800 liegen nicht um 1 (gelöschtes) Low-Byte auseinander.
    8800 dez = 00100010 01100000 bin
    8820 dez = 00100010 01110100 bin

    wäre es der Datenverlust bei LSB, ergäbe sich dezimal
    00100010 00000000 bin = 8704 dez

    Ich vermute daher den Fehler woanders, z.B. in einem Rundungsfehler in Soft- oder Firmware (z.B. Division Integer durch Integer).
    Auch sonst müsste man bei zufälliger Datenkorruption "veränderte" Werte finden können, die nicht durch glattes Abrunden der letzten beiden Dezimalstellen, sondern eher auch durch randomisierte Vergößerung/Verkleinerung der Ausgangswerte auffallen, dazu wären auch mal einige (10-20) andere solcher beobachteter "Datenveränderungen" interessant zu sehen.

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied Avatar von basteluwe
    Registriert seit
    15.11.2012
    Beiträge
    131
    Ich denke, ich bin inzwischen etwas weiter:
    Ich frage die Frequenz nach jedem Scan-Durchlauf ab und schreibe sie in den EEPROM. Das Problem liegt nun offensichtlich nicht in der EEPROM-Routine sondern im Wert, den der Radio-Chip auf den Befehl "radio.getFrequency()" zurück gibt. Der stimmt nämlich nicht in jedem Fall mit der aktuellen Frequenz überein. Ich lasse im Moment das Terminal mitlaufen und sehe daher die Abweichung zwischen der neu eingestellten Frequenz und dem nach dem Scan gemeldeten und gespeicherten Wert. Warum das so ist, weiß ich allerdings noch nicht.

    Gruß Uwe

Seite 1 von 5 123 ... LetzteLetzte

Ähnliche Themen

  1. [ERLEDIGT] I2C Wert nach EEPROM 24C512 schreiben
    Von Bot-Builder im Forum C - Programmierung (GCC u.a.)
    Antworten: 7
    Letzter Beitrag: 13.03.2013, 08:34
  2. Edit: Wie Wert in EEPROM speichern?
    Von Maxxtro im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 24
    Letzter Beitrag: 23.02.2009, 10:03
  3. Bicore - ungenau
    Von boarter im Forum Elektronik
    Antworten: 0
    Letzter Beitrag: 29.06.2008, 01:15
  4. HEX Wert aus EEprom BINär umwandeln PICBASIC
    Von Robbersoft im Forum PIC Controller
    Antworten: 3
    Letzter Beitrag: 19.08.2007, 00:34
  5. Float Wert in EEPROM schreiben
    Von AlexAtRobo im Forum C - Programmierung (GCC u.a.)
    Antworten: 5
    Letzter Beitrag: 26.06.2006, 22:10

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests