Forum: Mikrocontroller und Digitale Elektronik Float ins Externe EEPROM schreiben. Funkt. nicht so ganz


von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

Guten Nachmittag,
Ich Arbeite immer noch an mein Temperaturmessgerät. Nun bin ich dabei 
ein Alarm für die Sensoren ein zu führen, denn man einstellen kann. Das 
Problem ist der Wert(in °C) soll im EEPROM(Externer Chip) gespeichert 
werden. Bis jetzt habe ich nur ein uint8_t gespeichert, im EEPROM. Wenn 
ich die vorhandene Funktion für writeEEPROM(adresse, uint8_t data) 
abändere auf Float so das ein Float geschrieben wird anstatt ein 
uint8_t. Und ich das nachdem schreiben wieder auslese kommt nur die ganz 
Zahl als Float zurück also so:

writeEEPROM_Float(22, 21.92f); //21.92f schreiben

Wenn ich dann mit readEEPROM_Float(22) das ganze wieder auslese und zum 
USART sende dann kommt nur 21.00 zurück.

Kann das vielleicht an der Adressierung liegen? Denn ich schreibe ja die 
EEPROM Adresse und 0xFF.

Mfg Felix.

von Peter D. (peda)


Lesenswert?

Wie soll denn ein float in ein Byte passen?

von Vanouver (Gast)


Lesenswert?

Könnte das daran liegen, dass Dein float 32bit umfasst, Du aber nur ein 
Byte in den eeprom schreibst? Ich sehe in Deiner Funktion jedenfalls nur 
einen einzigen Daten-Schreibzugriff.

von Stefan K. (stefan64)


Lesenswert?

1
void writeEEPROM_Float(unsigned int eepromaddress, float data) {
2
  i2c_start(I2C_Device_Address + I2C_WRITE);
3
  i2c_write(eepromaddress & 0xFF);
4
  i2c_write(data);
5
  i2c_stop();
6
  _delay_ms(5);
7
}

i2c_write(data) schickt nur ein einziges Byte Deines floats. Wie ist 
denn diese Routine definiert und gibt Dir der Compiler keine Warnung, 
weil die Typen nicht passen?

Gruß, Stefan

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Felix N. schrieb:
> uint8_t. Und ich das nachdem schreiben wieder auslese kommt nur die ganz
> Zahl als Float zurück also so:
>
> writeEEPROM_Float(22, 21.92f); //21.92f schreiben

 Schmeiss Float raus, schreibe zwei uint8_t stattdessen, also
 21 und 92.
 Schneller und braucht weniger Platz.

von Felix N. (felix_n888)


Lesenswert?

Marc V. schrieb:
> Schmeiss Float raus, schreibe zwei uint8_t stattdessen, also
>  21 und 92.
>  Schneller und braucht weniger Platz.

Hi. Dieses Idee hat ich auch schon aber, aus einem Float zwei int's zu 
machen da bin ich immer hängen geblieben. Wie mache ich dem am besten 
draus 2 Ints?

von Stefan K. (stefan64)


Lesenswert?

Wie ist bei Dir i2c_write(data) definiert?
Ev. gibt es eine ähnliche Routine, die mehrere Bytes über i2c überträgt. 
Die wäre das Mittel der Wahl.

Z.B.: i2c_writeBlock(uint8_t *pBlock, int dataSize);
1
void writeEEPROM_Float(unsigned int eepromaddress, float data) {
2
  i2c_start(I2C_Device_Address + I2C_WRITE);
3
  i2c_write(eepromaddress & 0xFF);
4
  i2c_writeBlock((uint8_t*) &data, sizeof(data));
5
  i2c_stop();
6
  _delay_ms(5);
7
}

Gruß, Stefan

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Felix N. schrieb:
> Hi. Dieses Idee hat ich auch schon aber, aus einem Float zwei int's zu
> machen da bin ich immer hängen geblieben. Wie mache ich dem am besten
> draus 2 Ints?

 Wie bist du überhaupt beim Float gelandet ?
 Soviel ich weiss, sendet kein Sensor einen Float als Wert raus ?

von Felix N. (felix_n888)


Lesenswert?

Stefan K. schrieb:
> Wie ist bei Dir i2c_write(data) definiert?
> Ev. gibt es eine ähnliche Routine, die mehrere Bytes über i2c überträgt.
> Die wäre das Mittel der Wahl.

So sieht die Methode aus:
1
unsigned char i2c_write(unsigned char data) {
2
  uint8_t twst;
3
  
4
  TWDR = data;
5
  TWCR = (1<<TWINT) | (1<<TWEN);
6
  
7
  while(!(TWCR & (1<<TWINT)));
8
  
9
  twst = TW_STATUS & 0xF8;
10
  if(twst != TW_MT_DATA_ACK) return 1;
11
  return 0;
12
}

Marc V. schrieb:
> Wie bist du überhaupt beim Float gelandet ?
>  Soviel ich weiss, sendet kein Sensor einen Float als Wert raus ?
1
float readTemperatureAnalog(uint8_t channel) { 
2
  float temp = readADC(channel); //Read from ADC
3
  
4
  float mV = (temp / 1023.0) * 5000; //Convert to mV with 5 V Ref
5
  float offSet = mV - 700; // subtract 700
6
  float celsius = offSet / 10; // Divide 10 for °C
7
  
8
  return celsius;
9
  
10
}

von Stefan K. (stefan64)


Lesenswert?

Damit schickst Du mehrere Bytes an den I2C:
1
void i2c_writeBlock(unsigned char *pBlock, int dataSize)
2
{
3
  int i;
4
  for (i=0; i<dataSize; i++)
5
  {
6
    i2c_write(*(pBlock+i));
7
  }
8
}
9
10
void i2c_readBlockNak(unsigned char *pBlock, int dataSize)
11
{
12
  int i;
13
  for (i=0; i<dataSize; i++)
14
  {
15
    *(pBlock+i) = i2c_readNak();
16
  }
17
}

.. in Deinem Programm (writeEEPROM_Float und readEEPROM_Float):
1
  float floatData;
2
  ...
3
  i2c_writeBlock((unsigned char*) &floatData, sizeof(data));
4
  ...
5
  i2c_readBlockNak((unsigned char*) &floatData, sizeof(data));
6
  ...

Alles aus dem Stegreif geschrieben und ungetestet!

Gruß, Stefan

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Felix N. schrieb:
> float readTemperatureAnalog(uint8_t channel) {
>   float temp = readADC(channel); //Read from ADC
>
>   float mV = (temp / 1023.0) * 5000; //Convert to mV with 5 V Ref
>   float offSet = mV - 700; // subtract 700
>   float celsius = offSet / 10; // Divide 10 for °C
>
>   return celsius;
>
> }

 Wenn es um AVR geht, dann ist laut ATMEL ADC = Vin * 1024 / Vref,
 also ist Vin = Vref * ADC / 1024
 oder 5000 * ADC / 1024 mit 5V Vref
 wobei 0x00 = GND und 0x3FF = Vref - LSB
 Auflösung ist somit 4,887mV oder ungefähr 204 Werte pro Volt.
 Das ist genau genug, ADC ist auch nicht 100% genau.

 Um die ganze Rechnerei mit Float zu sparen, kannst du mit Long
 etwa so rechnen:

 uint8_t Ganz =  ADC / 204;
 long lk = ((ADC % 204) * 1000) / 204;
 uint8_t Dez = lk / 10;

 Wie kommst du auf deine Berechnung mit Offset und so ?

von Felix N. (felix_n888)


Lesenswert?

Marc V. schrieb:
> Wie kommst du auf deine Berechnung mit Offset und so ?

Ich nutze denn LM35 aus Sensor. Dieser gibt bei 0 °C 0 mV aus und bei 
150 °C 1500 mV um aber bis -55 Grad zu messen braucht er eine negative 
Spannung. Da man diese aber nicht mit dem ADC messen kann. Habe ich an 
Ground eine 0,7 Volt angeschlossen mit einer 1N914 und ein 1k Ohm 
Widerstand. So kann ich auch im plus Bereich negative Temperaturen 
messen. Die 700 Offset sind also bei -33 Grad gibt der LM35 ein mV von 
370 mV aus. -330 + 700 = 370 mV. Also -330 Entsprechen -33 Grad bei Full 
Range. Durch die Modifikation liegt die Spannung bei -33 Grad nicht bei 
-330 mV sondern bei +370 mV. Sonst kann ich keine negativen Temps 
messen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.