Unterdruck und Höllentemperatur bei falschen Valuetype (Wemos)


Wenn die Ergebnisse nicht den Erwartungen entsprechen, dann ist mit Sicherheit etwas falsch. Das geschah diesmal mit dem Wemos D1 Mini. Einen bereits fertiges Code Beispiel für das Auslesen eines BMP085 Sensors mit einem Arduino, verwendete ich diesmal auf dem Wemos. Nach dem hochladen zeigten sich die nicht erwartenden Ergebnisse. Zumindest war offensichtlich, dass in meiner Wohnung keine 119 Grad Celsius herrschten und bei einem Luftdruck von 4000 Pascal wäre ich sicherlich an Sauerstoffmangel oder kochendem Blut auseinander gegangen. Also musste was an der Berechnung nicht stimmen.


Behoben
Der Fehler ließ sich relativ schnell beheben. Die Verwendeten ValueTypes int und unsigned int wurden ersetzt durch int16_t und unt16_t.

Aber warum
Ein ValueType INT ist immer das gleiche, solange die Variable als INT definiert wird auf einem System. Das eine System ist die Arduino Plattform mit dem 8Bit Mikrocontroller. Der Wemos verwendet wiederum einen 32Bit Mikrocontroller. Das sollte als erstes Auffallen und schnell sollte klar sein, dass etwas mit den Typen etwas nicht stimmt und folglich nicht mit den richtigen Werten rechnet. Eigentlich ist das von Compiler abhängig, welcher Type aus einem INT angelegt wird.
Der Folgende Code macht die Größe eines INT sichtbar, sobald ihr das auf der Ziel Plattform ausführt.

 void setup() {  
  Serial.begin(9600);  
  Serial.print("int: ");   
  Serial.println(sizeof(int), DEC);  
  Serial.print("unsigned int: ");   
  Serial.println(sizeof(unsigned int), DEC);  
  Serial.print("int16_t: ");   
  Serial.println(sizeof(int16_t), DEC);  
  Serial.print("uint16_t: ");   
  Serial.println(sizeof(uint16_t), DEC);  
 }  

Wie man sieht, wird auf dem Wemos kein 16Bit INT, sondern 32Bit INTEGER angelegt

Arduino Nano
Wemos D1 Mini



Aber Moment mal. Damit wäre eine Berechnung auf dem Wemos genauer und der Rechenfehler dürfte erst gar nicht auftreten. Sieht man sich allerdings die Funktionsinhalte an, dann sind mehrere Stellen auffällig, wo die Werte durch Byteshifting hoch oder runter gerechnet werden. Das nur passt wiederum nur mit 16 Bit. Andernfalls muss die Funktion geändert werden.

Zur Vollständigkeit der Beispielcode mit den geänderten ValueTypes. In diesem Fall reichten die Änderungen für INT aus und kann nun für Arduino oder Wemos verwendet werden.

 #include <Wire.h>  
 #define BMP085_ADDRESS 0x77 // I2C address of BMP085  
 const unsigned char OSS = 0; // Oversampling Setting 
// Calibration values
int16_t ac1, ac2, ac3, b1, b2, mb, mc, md;
uint16_t ac4, ac5, ac6;
long b5;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  bmp085Calibration();
}

void loop() {
  uint16_t rawValueUt = bmp085ReadUT();  // MUST be called first
  float temperature = bmp085GetTemperature(rawValueUt);
  uint16_t rawValueUp = bmp085ReadUP();
  float pressure = bmp085GetPressure(rawValueUp);
  float atm = pressure / 101325; // "standard atmosphere"
  float altitude = calcAltitude(pressure); //Uncompensated caculation - in Meters 

  Serial.print("Temperature: "); Serial.print(temperature, 1); Serial.println(" deg C");
  Serial.print("Pressure: "); Serial.print(pressure, 0); Serial.println(" Pa");
  Serial.print("Standard Atmosphere: "); Serial.println(atm, 4);
  Serial.print("Altitude: "); Serial.print(altitude, 2); Serial.println(" M");
  Serial.println();
  delay(2000);
}

void bmp085Calibration(){
  ac1 = bmp085ReadInt(0xAA); Serial.print("ac1"); Serial.print(ac1, DEC);
  ac2 = bmp085ReadInt(0xAC); Serial.print(" ac2"); Serial.print(ac2, DEC);
  ac3 = bmp085ReadInt(0xAE); Serial.print(" ac3"); Serial.print(ac3, DEC);
  ac4 = bmp085ReadInt(0xB0); Serial.print(" ac4"); Serial.print(ac4, DEC);
  ac5 = bmp085ReadInt(0xB2); Serial.print(" ac5"); Serial.print(ac5, DEC);
  ac6 = bmp085ReadInt(0xB4); Serial.print(" ac6"); Serial.print(ac6, DEC);
  b1 = bmp085ReadInt(0xB6); Serial.print(" b1"); Serial.print(b1, DEC);
  b2 = bmp085ReadInt(0xB8); Serial.print(" b2"); Serial.print(b2, DEC);
  mb = bmp085ReadInt(0xBA); Serial.print(" mb"); Serial.print(mb, DEC);
  mc = bmp085ReadInt(0xBC); Serial.print(" mc"); Serial.print(mc, DEC);
  md = bmp085ReadInt(0xBE); Serial.print(" md"); Serial.print(md, DEC); 
  Serial.println();
}
// Calculate temperature in deg C
float bmp085GetTemperature(uint16_t ut){
  long x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
  long x2 = ((long)mc << 11)/(x1 + md);
  b5 = x1 + x2;

  return (float)((b5 + 8)>>4) / 10.0;
}
// calculate pressure from raw value
long bmp085GetPressure(unsigned long up){

  long b6 = b5 - 4000;
  // Calculate B3
  long x1 = (b2 * (b6 * b6)>>12)>>11;
  long x2 = (ac2 * b6)>>11;
  long x3 = x1 + x2;
  long b3 = (((((long)ac1)*4 + x3)<>2;

  // Calculate B4
  x1 = (ac3 * b6)>>13;
  x2 = (b1 * ((b6 * b6)>>12))>>16;
  x3 = ((x1 + x2) + 2)>>2;
  unsigned long b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
  
  unsigned long b7 = ((unsigned long)(up - b3) * (50000>>OSS));

  long p;
  if (b7 < 0x80000000)
    p = (b7<<1 b4="" else="" p="(b7" x1="(p">>8) * (p>>8);
  x1 = (x1 * 3038)>>16;
  x2 = (-7357 * p)>>16;
  p += (x1 + x2 + 3791)>>4;

  return p;
}
// Read 1 byte from the BMP085 at 'address'
char bmp085Read(unsigned char address){
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();
  Wire.requestFrom(BMP085_ADDRESS, 1);
  while(!Wire.available()) {}
  return Wire.read();
}
// read two byte 
int16_t bmp085ReadInt(unsigned char address){
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 2);
  while(Wire.available()<2 0x34="" 0xf4="" 0xf6="" 0xf7="" 0xf8="" 16="" 4.5ms="" 8="" a="" and="" at="" bmp085readint="" bmp085readup="" bmp085readut="" char="" conversion="" delay="" dependent="" for="" int16_t="" into="" least="" long="" lsb="" msb="" on="" oss="" oversampling="" pressure="" raw="" read="" reading="" register="" request="" return="" setting="" temperature="" the="" time="" uint16_t="" uncompensated="" unsigned="" up="(((unsigned" value="" w="" wait="" wire.begintransmission="" wire.endtransmission="" wire.write="" write="" x2e="" x34="" xf4="" xf6="" xlsb="">> (8-OSS);
  Serial.print("Pressure Raw Value: "); Serial.print(up, DEC); Serial.println();
  return up;
}
// calculate altitude by pressure value
float calcAltitude(float pressure){
  float alti = pow((pressure/101325),(1/5.25588));
  return (1 - alti) /0.0000225577;
}


Kommentare

Beliebte Posts aus diesem Blog

Arduino Control (Teil 5) - PWM Signal einlesen

RC Fahrtenregler für Lego Kettenfahrzeug

Angular auf dem Raspberry Pi