bis zu 7 Zahlen in den EEPROM schreiben ?

Hallo allerseits und frohe Weihnachten…
ich möchte gerne einen Wert der aus bis zu 7 Zahlen (float ZStandNeu) besteht in den EEPROM schreiben,
damit diese nicht nach Spannungsverlust oder Reset verloren gehen.

long ZStand = 898734;  // Zählerstand bei Start
float ZStandNeu;       // Neuer Zählerstand

Ist sowas möglich ? Und wenn JA,WIE ? :blush:

Hintergrund: Ich habe an meinem Gaszähler einen Reedkontakt, der jeden Impuls in eine SQL-Datenbank schreibt,
mit Datum und Uhrzeit, um damit Visuell den Verbrauch anzuzeigen.

Könnt Ihr mir bei dem Projekt behilflich sein ?
Bin noch nicht so lange mit dem Arduino vertraut.

Hier der Sketch, den ich z.Z. nutze, aber da ist der Zählerstand ja immer wieder der wie beim Start… :drooling_face:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <Ethernet.h>             // library for ethernet functions

//ETHERNET-SETTINGS
byte mac[]     = { 0x5D, 0xA2, 0xFA, 0x2D, 0x76, 0x8C };    // MAC-Adresse des Arduino
byte ip[]      = { 192, 168, 178, 41 };                     // IP-Adresse des Arduino
byte gateway[] = { 192, 168, 178, 1 };                    // Gateway
byte subnet[]  = { 255, 255, 255, 0 };                    // SubNet
byte server[]  = { 192, 168, 178, 111 };                     // IP-Adresse des Servers

EthernetClient client;
char host[]    = "192.168.178.111";                      // Domain
char url[]     = "/Arduino/Gas/insert1.php"; // Pfad zur PHP-Datei
char key[]     = "ch5fn7sb";                     // Kennwort aus PHP-Datei

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
byte hoch3[8] = { B01110, B00010, B00110, B00010, B01110, B00000, B00000, B00000 };

int ReedPin = 8;     // Schalter ist mit Pin 8 verbunden
int PowerLED = 3;    // rote kontroll LED
int val;               // Variable für den Pin Zustand 
int buttonState;       // Variable für den letzten Schalterzustand 
int buttonPresses = 0; // Wie oft ist der Schalter gedrückt
long ZStand = 898734;      // Zählerstand bei Anschluss
float ZStandNeu;      // Zählerstand Neu

void setup()
{
   lcd.init(); // initialize the lcd
   lcd.backlight();
   lcd.createChar(0, hoch3);
   lcd.setCursor(8,1);
   lcd.print("m");
   lcd.setCursor(9,1);
   lcd.write(0);
   lcd.setCursor(0, 0);
   lcd.print("Gas-Zaehler"); 
  // warten, bis LAN gestartet
   Serial.begin(9600);
   pinMode(PowerLED, OUTPUT); 
   pinMode(ReedPin, INPUT); 
   Serial.println("Programm gestartet...");
   digitalWrite(ReedPin, HIGH);
   Serial.println(F("Ethernet initialisieren...")); 
   Ethernet.begin(mac, ip);
   delay(5000); 
   client.connect(server, 80);               // Verbindung zum Server aufbauen
   buttonState = digitalRead(ReedPin);  // Anfangszustand lesen
}

void loop()
{
val = digitalRead(ReedPin); // Eingabewert lesen und in val speichern
if (client.connected()) 	
{
   Serial.println("Connected"); 
   Serial.println(digitalRead(ReedPin)); 
   if(val !=buttonState) {
     if (val == LOW) { // Ist der Schalter gedrückt? 
       buttonPresses++; // Inkrementieren der Variablen buttonPresses,immer um 1 erhöhern
       Serial.print(F("Zählerstand "));
       ZStandNeu = ZStand + buttonPresses;
       Serial.print(ZStandNeu/100);
       Serial.print(" m");
       Serial.println(char(179));    // 179 = m³
       digitalWrite(PowerLED, LOW);
       lcd.clear();
       lcd.setCursor(8,1);
       lcd.print("m");
       lcd.setCursor(9,1);
       lcd.write(0);
       lcd.setCursor(0, 0);
       lcd.print("Gas-Zaehler");
       lcd.setCursor(0, 1);
       lcd.print(ZStandNeu/100);
       float gz = ZStandNeu/100;  
       Daten_senden(gz);
       delay(1000);
       client.flush();
       client.stop();
       }
       do 
       {
           Serial.println("Warte bis Schalter wieder geloesst");
           delay(2000);
       } while ( !digitalRead(ReedPin) );
       client.connect(server, 80); 
   }
   }else{
       Serial.println("NOT Connected");
       client.flush();
       delay(1000); 
   }
   buttonState = val; // Den Zustand merken
}

void Daten_senden(float T1)
{
   if (client.connected()) 
   {
    Serial.println(F("Verbunden, Sende Daten..."));
    client.print("GET " + String(url));
    Serial.println("GET " + String(url));
    client.print(F("?T1="));
    Serial.print(F("?T1="));
    client.print(T1);
    Serial.println(T1);      
    client.print("&key=" + String(key));
    Serial.print("&key=" + String(key));
    client.println(" HTTP/1.1");
    Serial.println(F(" HTTP/1.1"));
    client.print("Host: " + String(host));
    Serial.print("Host: " + String(host));
    client.println();
    Serial.println();
    client.println("User-Agent: Arduino");
    Serial.println(F("User-Agent: Arduino"));
    client.println("Connection: close");
    Serial.println(F("Connection: close"));
    client.println();
    Serial.println();
   }
   else
   {
       Serial.println(" ***** VERBINDUNGSAUFBAU NICHT MÖGLICH *****");
       digitalWrite(PowerLED, HIGH);
       lcd.clear();
       lcd.setCursor(5, 0);
       lcd.print("Fehler!");
       lcd.setCursor(0, 1);
       lcd.print("Keine Verbindung");
       delay(5000);
   } 
}

Ich bitte um Nachsicht, der Code ist noch nicht fertig Kommentiert und Aufgeräumt.

Danke

-- Ohne den Code gelesen zu haben --

Der EEPROM kann nur begrenzt beschrieben werden.

Wäre es nicht sinnvoller a) den Zählerstand vorher aus der DB zu lesen? b) einfach nur pro Impuls eine Anfrage zum Höherzählen an die Datenbank zu geben?

Gruß, Tobias

Du musst aus einem Long 4 Bytes machen

long ZStand = 898734;
byte Ebyte1=0;
byte Ebyte2=0;
byte Ebyte3=0;
byte Ebyte4=0;

             
 Ebyte1 = (int)((ZStand >> 24) & 0xFF) ;   
 Ebyte2 = (int)((ZStand >> 16) & 0xFF) ;
 Ebyte3 = (int)((ZStand >> 8) & 0XFF);
 Ebyte4 = (int)((Zstand & 0XFF));

Die Ebytes in dem EEprom ablegen(aber nur bei änderung von einem der Bytes nur das veränderte Byte ablegen damit das EEProm nicht hops geht) und im Setup vor dem Start wieder lesen. Das müsste es sein Meine infos sind von hier auch wieder zurück. http://rclermont.blogspot.de/2010/02/convert-long-into-byte-array-in-cc.html

Hallo Tobias, Da habe ich auch gerade drüber nachgedacht, deine Variante A. Aber da scheitere ich an meinem kleinen Wissen :blush:

Manawyrm: -- Ohne den Code gelesen zu haben --

Der EEPROM kann nur begrenzt beschrieben werden.

Wäre es nicht sinnvoller a) den Zählerstand vorher aus der DB zu lesen? b) einfach nur pro Impuls eine Anfrage zum Höherzählen an die Datenbank zu geben?

Aber die Varinante B, wäre glaube ich schlauer... Auch wegen der Visualisierung...

Danke für den Denkanstoß, werde erstmal LESEN gehen und mal sehen wie weit ich komme...

Aber für HIlfe für Variante A , wäre sehr Dankbar...

2 Probleme:

Eine Float-Typ Variable als Zählerstand zu verwenden ist falsch. Eine Float Zahl kann zwar sehr große Zahlen darstellen aber nur mit begrenzter Genauigkeit. Die Genauigkeit ist auf 6-7 Stellen begrenzt. Wenn Du dann die Zahl um 1 erhöhst dann bleibt die Zahl gleich. Du mußt unsigned Long verwenden.

Du machst ausgiebig Gebrauch von Serial.print, LCD.print und client.print. All diese Funktionen brauchen RAM und dieses ist schnell mal voll und führt zu unvorhersagbaren Verhalten des Sketches. Verwende F() wie in http://arduino.cc/forum/index.php/topic,127552.msg965539.html#msg965539

Für die Zwischenspeicherung des Zählertandes kannst Du das RAM der RTC benutzen der DS1307 hat 56 Byte RAM batteriegepuffert.

Grüße Uwe

Hallo Uwe, ich hatte deinen Vorschlag/Hinweis ja schon teilweise umgesetzt :blush: Habe ich jetzt aber ganz gemacht, alles in (F() gesetzt. Und die Serial Sachen fliegen sowieso raus, wenn er läuft. 8)

Und ich habe die Variable Float-Typ in unsigned long geändert. Jetzt bekomme ich aber keinen Punkt mehr angezeigt :~ Vorher sah die Zahl z.B. so aus : 8536.25 Wurde auch so in die DB gespeichert. Jetzt sieht es so aus 853625. Auch in der DB.... Gibt es dafür eine Lösung ? :~

uwefed: 2 Probleme:

Eine Float-Typ Variable als Zählerstand zu verwenden ist falsch. Eine Float Zahl kann zwar sehr große Zahlen darstellen aber nur mit begrenzter Genauigkeit. Die Genauigkeit ist auf 6-7 Stellen begrenzt. Wenn Du dann die Zahl um 1 erhöhst dann bleibt die Zahl gleich. Du mußt unsigned Long verwenden.

Du machst ausgiebig Gebrauch von Serial.print, LCD.print und client.print. All diese Funktionen brauchen RAM und dieses ist schnell mal voll und führt zu unvorhersagbaren Verhalten des Sketches. Verwende F() wie in http://arduino.cc/forum/index.php/topic,127552.msg965539.html#msg965539

Für die Zwischenspeicherung des Zählertandes kannst Du das RAM der RTC benutzen der DS1307 hat 56 Byte RAM batteriegepuffert.

Ich habe keine RTC dran :~ Aber ein Ethernet-Shield mit SD Karten Slot, da könnte man doch auch speichern , oder ?

Die Variante, den letzten Stand aus der MySQL zu lesen finde ich aber glaube ich besser, habe aber noch nix dazu gefunden, reinschreiben ja, aber nicht wie man aus der DB liest...

Hallo Cetax,

ich war der Meinung, der Code zum Auslesen und Schreiben der DB kam von dir... Sei's drum.

Teil uns mal den Inhalt der Gas/insert1.php mit. Dann kann ich dir gerne ein passendes Script zum Auslesen schicken^^

Gruß, Tobias

Hallo Tobias,
vielen Dank für deine schnelle Hilfe.

ich war der Meinung, der Code zum Auslesen und Schreiben der DB kam von dir…
Sei’s drum.

Nee leider nicht, weiß nur einbischen wie man da was reinschreibt. :blush:

Teil uns mal den Inhalt der Gas/insert1.php mit.
Dann kann ich dir gerne ein passendes Script zum Auslesen schicken^^

Das wäre echt Super !!!
Hier der PHP-Code:

<?php

define("KEY","123456");
 
include("db-config.php");
 
if(isset($_GET['key']))
{
  if($_GET['key'] == KEY)
  {
    if(isset($_GET['T1']))
    {
      $GZ = mysql_real_escape_string($_GET['T1']);
      $DATUM = date("Y-m-d H:i:s");
 
      $result = mysql_query("INSERT INTO Gas (datumzeit, GZStand)
              VALUES('".$DATUM."', '".$GZ."') ") or die(mysql_error());
 
      if(mysql_affected_rows() == 1)
      {
        $result = "Gaswert gespeichert";
      } else $result = "Fehler beim speichern der Daten in der MySQL-Datenbank";
    } else $result = "Kein Wert übergeben";
  } else $result = "Falscher Key";
} else $result = "Kein Key übergeben";
 
print_r($result);
?>

Und der Code der db-config.php:

<?php
define('DB_SERVER',"localhost");
define('DB_NAME',"Gas");
define('DB_USER',"stefan");
define('DB_PASSWORD',"123456");
 
$conn = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD);
if(is_resource($conn))
{
  mysql_select_db(DB_NAME, $conn);
  mysql_query("SET NAMES 'utf8'", $conn);
  mysql_query("SET CHARACTER SET 'utf8'", $conn);
}
else
echo "Fehler beim speichern der Daten in der MySQL-Datenbank";
?>

Ist ja fast wie Weihnachten… :smiley:

Hallo Cetax,

etwas unschön ist die Tatsache, dass deine Tabelle keinen Primärschlüssel hat. (int - ID)

Das ganze müsste so funktionieren.

Probiere mit deinem Browser durch Aufruf von read1.php?key=123456 einmal, ob ein korrekter Wert zurückgegeben wird.

<?php

define("KEY","123456");
 
include("db-config.php");
 
if(isset($_GET['key']))
{
  if($_GET['key'] == KEY) //Key richtig?
  {
    //Von Tabelle Gas nehmen wir (sortiert nach datumzeit) das erste Element. 
	$result = mysql_query("SELECT * FROM Gas ORDER BY datumzeit DESC LIMIT 1") or die(mysql_error()); 
	
	if(mysql_num_rows($result) == 1)
	{
		print_r(mysql_fetch_assoc($result)['GZStand']); //Lies die erste zurückgegebene Zeile ein, und gib dann GZStand aus.
	} else $result = "0"; //Wenn noch nichts in der Datenbank steht, gib mal 0 zurück... 
  } else $result = "Falscher Key";
} else $result = "Kein Key &#252;bergeben";
 
print_r($result);
?>

Ist dies nicht der Fall, wäre es empfehlenswert, der Datenbank einen Selbst-Incrementierenden Primärschlüssel zu verpassen.
Der würde uns eine korrekte/bessere Sortierung ermöglichen.

Ich gehe stark davon aus, dass dieser Code NICHT funktionieren wird, da du das Datum als String/text in der Datenbank ablegst.
Das ist nicht gerade sauber, und verhindert (wie hier) dass man nach dem Datum korrekt sortieren kann…

Gruß,
Tobias (der müde ist und jetzt erstmal schlafen geht… Gute Nacht!)

Hallo Tobias,
nochmals Danke für deine Hilfe :slight_smile:

Also habe deine Code getestet und wie du vermutet hast, kommt ne Fehlermeldung

Warning: mysql_fetch_assoc() expects parameter 1 to be resource, null given in /volume1/web/Arduino/Gas/in_puls1.php on line 16 Resource id #2

Ich verstehe aber nicht was ich an der DB ändern muss, damit ich einen Primärschlüssel (int - ID) bekomme

Ist dies nicht der Fall, wäre es empfehlenswert, der Datenbank einen Selbst-Incrementierenden Primärschlüssel zu verpassen.
Der würde uns eine korrekte/bessere Sortierung ermöglichen.

Ich habe mal 2 Bildschirmfotos gemacht, wie die DB aussieht:
https://dl.dropbox.com/u/80052077/Temp_Messung/SQL_Gas.png
https://dl.dropbox.com/u/80052077/Temp_Messung/SQL_Gas1.png

Das erste zeigt die Struktur und das zweite, den Inhalt.

Ich weiß das das nicht unbedingt mit ARDUINO zu tun hat, aber es ist ja für das Arduino-Projekt :blush:

Vielen Dank

Hallo Cetax, Du hast doch schon eine ID die auch noch auf AUTO_INCREMENT steht. Leider sieht man auf dem Bild nicht, ob diese Spalte der Tabelle auch noch der Primärschlüssel ist.

Hallo Mario :grin:

Du hast doch schon eine ID die auch noch auf AUTO_INCREMENT steht. Leider sieht man auf dem Bild nicht, ob diese Spalte der Tabelle auch noch der Primärschlüssel ist.

Ok, aber wo sieht man das denn ? Von was soll ich ein Foto machen ? :blush:

OK, ich glaube ich habe da was gefunden... ^_^

https://dl.dropbox.com/u/80052077/Temp_Messung/SQL_Gas3.png

Ich bin auf Struktur und dann auf mehr, dort stand was von "Primärschlüssel hinzufügen" und "Eindeutigen Index hinzufügen". Das habe ich dann mal gemacht...

War das das was du meintest ?

Das ist doch schon wunderbar. Jetzt muss nur noch der PHP Code passend geändert werden.

Mach ich morgen :P

Hallo Tobias, das ist ja GÖTTLICH....

Manawyrm: Das ist doch schon wunderbar. Jetzt muss nur noch der PHP Code passend geändert werden.

Mach ich morgen :P

VIELEN DANK !! :D

Huhu ?? :grin: Hast mich vergessen ? :blush:

Manawyrm: Das ist doch schon wunderbar. Jetzt muss nur noch der PHP Code passend geändert werden.

Mach ich morgen :P

Würde mich immer noch über deine Hilfe freuen XD

Gruß Stefan