Pages: [1]   Go Down
Author Topic: byte[4] -> long - funktioniert nur bedingt.  (Read 1050 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Grüß Gott Freunde,

ich habe ein Problemchen mit dem folgenden Sketch. Kurz gesagt möchte ich ein long in vier Bytes wandeln, die ich auf einem I2C Eeprom speichern möchte - anschließend abfragen und wieder in float wandeln.

vollständigkeitshalber der Sketch:

Code:
#include <Wire.h>
#define I2CBaustein 0x50 // Festlegen der I2C Zugriffsadresse

byte awert[4];


void setup(){
  Wire.begin();
  Serial.begin(9600);
 
  unsigned long n=65535;
  byte wert[4];

 
 
wert[0] = (byte )((n >> 24) & 0xff);
wert[1] = (byte )((n >> 16) & 0xff);
wert[2] = (byte )((n >> 8) & 0xff);
wert[3] = (byte )(n & 0xff);




 
  schreibeEEPROM(I2CBaustein, 0, wert[0]); // Schreiben
    schreibeEEPROM(I2CBaustein, 1, wert[1]); // Schreiben
      schreibeEEPROM(I2CBaustein, 2, wert[2]); // Schreiben
        schreibeEEPROM(I2CBaustein, 3, wert[3]); // Schreiben
 
}





void loop(){
 
awert[0]=leseEEPROM(I2CBaustein, 0); // Lesen
awert[1]=leseEEPROM(I2CBaustein, 1);
awert[2]=leseEEPROM(I2CBaustein, 2);
awert[3]=leseEEPROM(I2CBaustein, 3);

unsigned long value = (awert[3]) | (awert[2] << 8) | (awert[1] << 16) | (awert[0] << 24);

Serial.println(value, DEC);
Serial.println(awert[0], BIN);
Serial.println(awert[1], BIN);
Serial.println(awert[2], BIN);
Serial.println(awert[3], BIN);
Serial.println("");




delay(5000);
 
}





void schreibeEEPROM(int I2CBausteinAdresse, unsigned int speicherAdresse,byte daten){
 
  Wire.beginTransmission(I2CBausteinAdresse); // Verbindung zu I2C
  // initiieren
#if ARDUINO < 100
  Wire.send((byte)(speicherAdresse >> 8)); // MSB (höherwertiges Byte)
  // senden
  Wire.send((byte)(speicherAdresse & 0xFF)); // LSB (niederweriges Byte)
  // senden
  Wire.send(daten); // Daten-Byte zum Speichern
  // senden
#else
  Wire.write((byte)(speicherAdresse >> 8)); // MSB (höherwertiges Byte)
  // senden
  Wire.write((byte)(speicherAdresse & 0xFF)); // LSB (niederweriges Byte)
  // senden
  Wire.write(daten); // Daten-Byte zum Speichern
  // senden
#endif
  Wire.endTransmission(); // Verbindung zu I2C trennen
  delay(5); // Kurze Pause. Äußerst
  // wichtig!!!
}





byte leseEEPROM(int I2CBausteinAdresse, unsigned int speicherAdresse){
 
  byte datenByte = 0xFF;
  Wire.beginTransmission(I2CBausteinAdresse); // Verbindung zu I2C
  // initiieren
#if ARDUINO < 100
  Wire.send((byte)(speicherAdresse >> 8)); // MSB (höherwertiges Byte)
  // senden
  Wire.send((byte)(speicherAdresse & 0xFF)); // LSB (niederwertiges Byte)
  // senden
#else
  Wire.write((byte)(speicherAdresse >> 8)); // MSB (höherwertiges Byte)
  // senden
  Wire.write((byte)(speicherAdresse & 0xFF)); // LSB (niederwertiges Byte)
  // senden
#endif
  Wire.endTransmission(); // Verbindung zu I2C trennen
  Wire.requestFrom(I2CBausteinAdresse, 1); // Anfordern der Daten vom
  // Slave
#if ARDUINO < 100
  if(Wire.available()) datenByte = Wire.receive(); // Sind Daten vorhanden?
#else
  if(Wire.available()) datenByte = Wire.read(); // Sind Daten vorhanden?
#endif
  return datenByte; // Daten-Byte
  // zurückliefern
}



Ich kann den long erfolgreich in 4 Bytes wandeln, sie speichern und abrufen - aber wandeln geht nur bis 15 Bits. Ab 16Bits kommen fehler auf.

Probleme macht folgende Anweisung

Code:
unsigned long value = (awert[3]) | (awert[2] << 8) | (awert[1] << 16) | (awert[0] << 24);

Der erste Byte wird  korrekt in den long geschrieben, der Zweite Byte nur solang er kleiner 8 Bits ist. Sobald der 8te Bit dazu kommt, wirft er mir fehlerhafte Werte aus.

Die Bytes werden aber korrekt aus dem eeprom abgerufen.

Jemand eine Idee woran das liegen könnte?
Logged

Norway
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Bzzzzzt !
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

string not byte? 
Logged

Forum Moderator
BZ (I)
Offline Offline
Brattain Member
*****
Karma: 266
Posts: 21657
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Du hast 2 Probleme:
byte awert[4];
und
unsigned long value = (awert[3]) | (awert[2] << smiley-cool | (awert[1] << 16) | (awert[0] << 24);

Die bitweise oder verknüpfung funktioniert nur mit Byte Variablen.
Wenn Du awert[2] << 8 schiebst dann erhälst Du eine leere Byte Variable.

Du mußt:
unsigned long value =  awert[0];
value = value*8 + awert[1];
value = value*8 + awert[2];
value = value*8 + awert[3];

Grüße Uwe
Logged

Germany
Offline Offline
Edison Member
*
Karma: 136
Posts: 1491
If you believe something is right, you won't see what's wrong (David Straker).
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alternativ zur Lösung vom Uwe, könnte man beim "verodern" die Datenbreite angeben. Das behebt den Fehler direkt:
Code:
unsigned long value = ((unsigned long)awert[3]) | (((unsigned long)awert[2]) << 8) | (((unsigned long)awert[1]) << 16) | (((unsigned long)awert[0]) << 24);

Grüße,
Oliver
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 146
Posts: 3039
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Jemand eine Idee woran das liegen könnte?

Das liegt daran, dass Du es überhaupt mit Hin- und Herwandeln machst, was gar nicht notwendig ist, und Dich dann in den Datenstrukturen verhaspelst.

Ein "long" belegt doch schon vier Bytes im RAM-Speicher und wenn Du auf diese vier Bytes einzeln zugreifen können möchtest, brauchst Du nur eine passende Deklaration für ein Pointer auf byte, nutzbar als byte-Array ohne eigenen Speicher. Das so mittels Pointer-Deklaration erzeugte byte-Array beginnt an der Adresse der long-Variablen.

Und schon liegen die long-Variable "n" und das byte-Array "wert" vollkommen deckungsgleich im Speicher:
Änderst Du wert[0], wert[1], wert[2], wert[3], dann änderst Du n. Und umgekehrt.

Deklaration:
Code:
 unsigned long n=65336;
  byte* wert = (byte*) &n;

Wozu irgendwas fehlerträchtig wandeln, das schon im Speicher vorhanden ist?
« Last Edit: January 31, 2013, 01:56:44 am by jurs » Logged

Germany
Online Online
Faraday Member
**
Karma: 59
Posts: 3056
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alternativ zu pointern ist auch
union { unsigned long l; byte b[4];}
eine elegante Möglichkeit, auf einzelne Bytes eines long zuzugreifen und den gleichen Speicher auf zwei unterschiedliche Arten zu sehen.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alternativ zur Lösung vom Uwe, könnte man beim "verodern" die Datenbreite angeben. Das behebt den Fehler direkt:
Code:
unsigned long value = ((unsigned long)awert[3]) | (((unsigned long)awert[2]) << 8) | (((unsigned long)awert[1]) << 16) | (((unsigned long)awert[0]) << 24);

Grüße,
Oliver


funktioniert wunderbar, danke - auch den Anderen :-)
Logged

Germany
Offline Offline
Edison Member
*
Karma: 136
Posts: 1491
If you believe something is right, you won't see what's wrong (David Straker).
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Wozu irgendwas fehlerträchtig wandeln, das schon im Speicher vorhanden ist?
Ganz einfach, weil die Array Lösung (ebenso die union Lösung) mindestens genauso fehlerträchtig ist: Nämlich dann, wenn ein Prozessor mit einer anderen byte Reihenfolge verwendet wird.

Oliver
Logged

Germany
Online Online
Faraday Member
**
Karma: 59
Posts: 3056
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

wenn ein Prozessor mit einer anderen byte Reihenfolge verwendet wird.
... funktioniert es genauso.

Es wird nur vorausgesetzt, dass ein  long 4 byte hat. ( Bei allen Vorschlägen )

Und dass es nicht zur seriellen Übertragung auf eine andere Maschine mit anderer Bytereihenfolge verwendet wird.
Aber wenn, muss das jede Lösung berücksichtigen, egal wie oft was unnötig umkopiert wird.
« Last Edit: February 01, 2013, 04:38:48 am by uwefed » Logged

0
Offline Offline
Faraday Member
**
Karma: 24
Posts: 3487
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn die Reihenfolge der Werte umgekehrt wäre (niedrigstes Byte in Wert[0]), dann könntest Du die Arbeit den Compiler machen lassen:

Code:
uint32_t Ergebnis = *((uint32_t *)Wert);
Logged

Check out my experiments http://blog.blinkenlight.net

Germany
Online Online
Faraday Member
**
Karma: 59
Posts: 3056
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Kurz gesagt möchte ich ein long in vier Bytes wandeln, die ich auf einem I2C Eeprom speichern möchte - anschließend abfragen und wieder in float wandeln.

Man sollte die bytes schon so zurückholen, wie man sie geschrieben hat.
Das gilt für float und für long gleichermassen, aber man sollte sich schon für eins von beiden entscheiden  smiley-wink

Wenn man die eine Richtung unnötig mühsam macht, hat man es zurück genauso unnötig schwer.

union oder gecastete Pointer sind eigentlich egal und gleich einfach.
Logged

Pages: [1]   Go Up
Jump to: