-         
Seite 2 von 5 ErsteErste 1234 ... LetzteLetzte
Ergebnis 11 bis 20 von 44

Thema: EEPROM - ausgelesener Wert ist ungenau

  1. #11
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.749
    Anzeige

    .. 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 ..
    Hallo Uwe,
    prima dass Du die Lösung gefunden hast. Du denkst aber (auch) schon an das Datenblatt ? ? ?
    Zitat Zitat von Atmel-42735B-ATmega328/P_Datasheet_Complete-11/2016
    ..
    • High Endurance Non-volatile Memory Segments
    . . .
    – Write/Erase Cycles: 10,000 Flash/100,000 EEPROM
    ..
    Na ja, jede Stunde ein Scandurchlauf (mal un?sinnigerweise 24/7) ergibt knapp 9000. Bis 100000 sinds dann zehn Jahre . . . ok, das kann passen. Aber evtl. ist ein durchtickern des Adressraums bei den Schreib-/Lesevorgängen trotzdem sinnvoll (und seis nur deswegen, damit man das mal gemacht hat *gg*)?
    Ciao sagt der JoeamBerg

  2. #12
    Erfahrener Benutzer Fleißiges Mitglied Avatar von basteluwe
    Registriert seit
    15.11.2012
    Beiträge
    111
    Ich denke so geht es jetzt:
    Die EPROM-Bibliothek hat den update-Befehl, der nur in die Adresse schreibt, wenn der Inhalt abweicht. Allerdings geht das tatsächlich nur mit byte, nicht integer! Daher hab ich nun eine Umrechnung eingebaut. Die möglichen Frequenzwerte sind ja begrenzt und lassen das zum Glück zu. Ich habe diese Routine nun in der Hauptschleife drin, nicht mehr nach dem einzelnen Scannen. Alle 5 Sekunden läuft das und bisher hat er bei jedem Neustart (egal ob kalt oder Reset) die vorherige Frequenz exakt geladen.
    Code:
    if (millis() - previousMillis > 5000)
        {
        previousMillis = millis();
        frequency = (radio.getFrequency());       // Frequenz aus Radio auslesen  
        storeFreq = (frequency/10)-825;           // Frequenz in Speicherwert für EEPROM (byte) umrechnen
        EEPROM.update(0, storeFreq);              // falls neuer Speicherwert abweicht, dann update EEPROM
        }
    Gruß Uwe

    - - - Aktualisiert - - -

    Zitat Zitat von oberallgeier Beitrag anzeigen
    Hallo Uwe,
    prima dass Du die Lösung gefunden hast. Du denkst aber (auch) schon an das Datenblatt ? ? ?
    Na ja, jede Stunde ein Scandurchlauf (mal un?sinnigerweise 24/7) ergibt knapp 9000. Bis 100000 sinds dann zehn Jahre . . . ok, das kann passen. Aber evtl. ist ein durchtickern des Adressraums bei den Schreib-/Lesevorgängen trotzdem sinnvoll (und seis nur deswegen, damit man das mal gemacht hat *gg*)?
    Ja das mit den 100.000 Durchgängen ist mir bewust. Das ist aber nicht wirklich ein Problem, denke ich. So oft, wird der Sender nicht gewechselt und täglich benutzt wird das Ding sicher nicht (schon gar nicht 24/7). Trotzdem Danke für den Hinweis

    Uwe

  3. #13
    Erfahrener Benutzer Robotik Einstein Avatar von HaWe
    Registriert seit
    09.10.2014
    Beiträge
    3.300
    frequency = (radio.getFrequency());
    storeFreq = (frequency/10)-825;

    ist frequency vom Typ int oder float?
    welchen Typ liefert radio.getFrequency() zurück?
    Und welchen Typ hat storeFreq ?
    nenne vlt auch mal ein paar typische Werte, die radio.getFrequency() zurückiefert!

    hier teilst du durch 10 (int), bei float/int macht das nichts, aber bei int/int schon, das gibt besagte Rundungsfehler. Gibt es noch mehr solche Stellen mit ähnlichen Berechnungen?

    macht er jetzt noch Fehler beim Speichern und Zurücklesen?

    Immerhin bestätigt es ja auch meine Vermutung, dass es nicht an Datenkorruption im EPROM liegt.
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

  4. #14
    Erfahrener Benutzer Fleißiges Mitglied Avatar von basteluwe
    Registriert seit
    15.11.2012
    Beiträge
    111
    Zitat Zitat von HaWe Beitrag anzeigen
    ...
    ist frequency vom Typ int oder float?
    welchen Typ liefert radio.getFrequency() zurück?
    Und welchen Typ hat storeFreq ?
    nenne vlt auch mal ein paar typische Werte, die radio.getFrequency() zurückiefert!
    ...
    macht er jetzt noch Fehler beim Speichern und Zurücklesen?
    - frequency ist int
    - ich denke, radio.getFrequency() liefert ebenfalls int (typischer Werte ist 8760 als Entsprechung für 87,60 MHz oder 10330 für 103,30 MHz
    - storeFreq ist byte, weil nur byte von EEPROM.update akzeptiert wird

    Nein, in der letzten Variante tritt der Fehler bisher nicht mehr auf.

    Hier der Code, der (bis) jetzt problemlos läuft:
    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 ist 3 (0-15 möglich)
    
    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;
    byte storeFreq;                               // Speichervariable für EEPROM
    char vol[2];
    float volts;
    char akku[4];
    unsigned long previousMillis = 0;
    
    /*** setup ***/
    void setup()
      { 
      radio.init();                               // Radio initialisieren
      radio.setBand(FIX_BAND);                    // Radio auf FM setzen
      storeFreq = EEPROM.read(0);                 // Speicherwert für Frequenz aus EEPROM holen
      frequency = (storeFreq + 825)*10;           // Frequenzwert zu int für Radio-Chip wandeln
      radio.setFrequency(frequency);              // Radio auf gespeicherte Frequenz setzen
      radio.setVolume(volume);                    // Radio auf gespeicherte Lautstärke setzen
      
      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
      
      if (millis() - previousMillis > 5000){      // Prüfung alle 5 Sek ob update der gespeicherten Station nötig ???
        previousMillis = millis();
        frequency = (radio.getFrequency());       // Frequenz aus Radio auslesen  
        storeFreq = (frequency/10)-825;           // Frequenz in Speicherwert (byte) umrechnen
        EEPROM.update(0, storeFreq);              // falls neuer Speicherwert abweicht, dann update EEPROM
        }
       
      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);
          }
          
      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);
          }
      }
    Uwe

  5. #15
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    18.03.2018
    Beiträge
    321
    Zitat Zitat von basteluwe Beitrag anzeigen
    - frequency ist int
    - ich denke, radio.getFrequency() liefert ebenfalls int
    der Typ ist uint16_t, also Integer (unsigned, wenn ich nicht irre)


    Auszug aus radio.h:

    /// Frequency data type.
    /// Only 16 bits are used for any frequency value (not the real one)
    typedef uint16_t RADIO_FREQ;


    Deine Typdefinition ist: int frequency;
    Darin lassen sich Frequenzen von 0 bis 32767 speichern, bzw. 327,67MHz. Wegen dem Vorzeichen.
    Geliefert wird aus der Bilbliothek ohne Vorzeichen.
    Besser wäre, um Folgefehler und Denkakrobatik zu vermeiden: unsigned int frequency;

    Solang Du über die 327MHz nicht hinaus kommst, sollte es aber kein Problem damit geben.


    Wenn Du so machst:

    storeFreq = EEPROM.read(0); // Speicherwert für Frequenz aus EEPROM holen
    frequency = (storeFreq + 825)*10; // Frequenzwert zu int für Radio-Chip wandeln


    kommst Du auf Frequenzen bis 108,00MHz.


    Hier sollte dann aber eine Warnung kommen: radio.setFrequency(frequency);
    Weil der von Dir verwendete Datentyp nicht übereinstimmt. Macht aber nichts, solang das Vorzeichenbit nicht gesetzt ist.


    Hier erzeugst Du ein Problem: storeFreq = (frequency/10)-825; // Frequenz in Speicherwert (byte) umrechnen
    Wenn Du fiktiv 10625 durch 10 teilst, bleiben 1062 übrig, dann -825 = 237. Du speicherst damit letztlich 106,20MHz statt 106,25MHz.

    MfG
    Moppi
    Geändert von Moppi (09.10.2018 um 07:51 Uhr)

  6. #16
    Erfahrener Benutzer Robotik Einstein Avatar von HaWe
    Registriert seit
    09.10.2014
    Beiträge
    3.300
    zu moppis Post:
    stimmt, genau das mit dem dividieren eines int durch (int) 10 ergibt den resultierenden Rundungsfehler bei Hin- und Rückrechnung, den ich oben ansprach.
    Zumindest Datenkorruption auf dem EPROM kann man ja jetzt wohl doch ausschließen.

    Immerhin scheint es aber jetzt ja auf magische Weise nicht mehr relevant zu sein, daher würde mich schon interessieren, wie was vorher berechnet, gespeichert und zurückgerechnet wurde, als der Fehler beim Zurücklesen/rechnen des Speicherwertes noch auftrat.

    was int, int16_t , unsigned int und uint16_t angeht:
    ich würde hier ebenfalls zur originalen Typ Definition uint16_t raten, NICHT unsigned int und auch nichts anderes.

    Grund: Vielleicht nicht hier und nicht hier bei diesem Programm und auf auf dieser AVR Plattform, aber C++ KENNT den generellen Unterschied zwischen dem Plattform-abhängigen unsigned int von nicht exakt definierter Größe und dem expliziten Datentyp uint16_t aus der <stdint> lib.

    Auf ESP8266 oder Arduino Zero/Due z.B. ist int kein 16bit- sondern ein 32bit-Integer, also eher int32_t.

    Und auch wenn C++ (gpp) es oft durchrutschen lässt, so erzeugt es dennoch manchmal Compilierungsfehler, wenn es zum impliziten Casting kommt, z.B. bei Funktionsparametern.

    Also wenn die Lib uint16_t definiert, dann auch uint16_t verwenden, nicht unsigned int
    - und keinesfalls int und auch nicht int16_t , und das wegen des komplett abweichenden Zahlen-Definitionsbereichs!
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

  7. #17
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    18.03.2018
    Beiträge
    321
    Wenn man die Frequenztabellen ansieht, enden die meisten Sender eh auf "0" statt "5".
    Das mit den Datentypen führt meist zu Problemen, die sich kaum finden lassen, wenn man darauf kein Augenmerk legt und sich dessen nicht bewusst ist.
    Das ist natürlich richtig, dass bei unterschiedlichen CPUs die Datentypen unterschiedliche Bitbreite haben können. Deswegen wichtig: Datentypen kennen.

    MfG
    Geändert von Moppi (09.10.2018 um 09:54 Uhr)

  8. #18
    Erfahrener Benutzer Robotik Einstein Avatar von HaWe
    Registriert seit
    09.10.2014
    Beiträge
    3.300
    Zitat Zitat von Moppi Beitrag anzeigen
    Wenn man die Frequenztabellen ansieht, enden die meisten Sender eh auf "0" statt "5".
    Das mit den Datentypen führt meist zu Problemen, die sich kaum finden lassen, wenn man darauf kein Augenmerk legt und sich dessen nicht bewusst ist.
    Das ist natürlich richtig, dass bei unterschiedlichen CPUs die Datentypen unterschiedliche Bitbreite haben können. Deswegen wichtig: Datentypen kennen.

    MfG
    jain,
    die Probleme mit uint16_t versus unsigned int treten auch bei identischen Plattformen im selben Programm auf, nicht nur bei verschiedenen, und auch wenn die Datengröße übereinstimmt, daher IMMER genau identisch verwenden - oder jedes Mal explizit casten!
    Das gleiche gilt für long versus int32_t/int64_t, und ganz besonders auch für char, signed char, unsigned char, int8_t, uint8_t und byte (gerade bei char kann man sich bei Arduino vor Verzweiflung die Haare raufen!).

    Da das Programm aber jetzt ja angeblich funktioniert, ist die Rundung um 0,5 ja offenbar nicht mehr das Thema, doch wie ich schrieb,
    daher würde mich schon interessieren, wie was vorher berechnet, gespeichert und zurückgerechnet wurde, als der Fehler beim Zurücklesen/rechnen des Speicherwertes noch auftrat.
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

  9. #19
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    18.03.2018
    Beiträge
    321
    Das Problem lag wohl hier:


    1. EEPROM.put(0, frequency); // neue Frequenz in EEPROM speichern
    2. EEPROM.get(0, frequency);


    EEPORM.put() wird wohl dann bei dem Wert 10625 nur 129 (die unteren 8 Bit) speichern, wenn die Funktion nur byteweise ins EEPROM schreibt. Damit ist die Frequenz futsch. Kann auch möglich sein dass die put-Funktion zwei Byte ins EEPROM schreibt, nämlich High und Low-Byte, aber nur ein Byte zurückgelesen wird, gäbe auch nichts genaues. Und falls das Folgebyte im EEPROM, an Position #1, für andere Zwecke gebraucht wird, würde das direkt mit überschrieben, falls zwei Byte ab Position #0 geschrieben werden.
    Durch den Umweg mit Frequenz/10 minus 825, den basteluwe hinzugefügt hat, funktioniert es dann, er übergibt put() nur noch ein Byte und da ist die Frequenz dann drin. Vorher war sie ja in zwei Byte drin.

  10. #20
    Erfahrener Benutzer Robotik Einstein Avatar von HaWe
    Registriert seit
    09.10.2014
    Beiträge
    3.300
    Zitat Zitat von Moppi Beitrag anzeigen
    Das Problem lag wohl hier:


    1. EEPROM.put(0, frequency); // neue Frequenz in EEPROM speichern
    2. EEPROM.get(0, frequency);


    EEPORM.put() wird wohl dann bei dem Wert 10625 nur 129 (die unteren 8 Bit) speichern, wenn die Funktion nur byteweise ins EEPROM schreibt. Damit ist die Frequenz futsch. Kann auch möglich sein dass die put-Funktion zwei Byte ins EEPROM schreibt, nämlich High und Low-Byte, aber nur ein Byte zurückgelesen wird, gäbe auch nichts genaues. Und falls das Folgebyte im EEPROM, an Position #1, für andere Zwecke gebraucht wird, würde das direkt mit überschrieben, falls zwei Byte ab Position #0 geschrieben werden.
    Durch den Umweg mit Frequenz/10 minus 825, den basteluwe hinzugefügt hat, funktioniert es dann, er übergibt put() nur noch ein Byte.
    danke, aber das erklärt IMO die Abrundung bei 8820 zu 8800 nicht ausreichend (CMIIW).

    Daher würden mich auch andere damalige aufgetretene "Fehler" interessieren, und auch der komplette Rechenweg.
    ·±≠≡≈³αγελΔΣΩ∞ Schachroboter:www.youtube.com/watch?v=Cv-yzuebC7E Rasenmäher-Robot:www.youtube.com/watch?v=z7mqnaU_9A8

Seite 2 von 5 ErsteErste 1234 ... 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
  •