Go Down

Topic: Virtual Wire stört BMP180 (Read 4833 times) previous topic - next topic

wisbo

Hallo, Gemeinde,

Ich habe hier eine kleine Wetterstation mit Arduino Mega 2560 und unter anderem einem BMP180 Druck- und Temperatursensor.
Ich möchte die Daten mit  Virtual Wire übertragen, was im Prinzip auch funtioniert.

Problem: Sobald ich vw_setup(2000) einbinde, liefert der BMP180 sporadisch falsche Werte, auch ohne angeschlossenen Sender:

19.3.14  11:58:50      12,50°C -73,-60°C  753 hPa  84,30 %  0,69 m/s aus S  
19.3.14  11:58:51      12,50°C  21,30°C  1012 hPa  83,0 %  0,69 m/s aus S  
19.3.14  11:58:52      12,50°C  21,30°C  1012 hPa  83,0 %  0,68 m/s aus S    
19.3.14  11:58:52      12,50°C  21,30°C  1012 hPa  83,0 %  0,67 m/s aus S  
19.3.14  11:58:53      12,50°C  -87,-80°C  718 hPa 79,60 %  0,67 m/s aus S    

Any Hints?

Danke schonmal

Willi
Grüße

Willi

pylon

Wie wär's mit dem Sketch, der diesen Output erzeugt hat? Ansonsten sind hellseherische Fähigkeiten gefragt und da muss ich passen.

Zudem gehört zu einer solchen Anfrage grundsätzlich ein Link zur verwendeten Hardware, falls möglich gleich zum Datenblatt. Falls die Hardware nicht ein Shield darstellt, das nur auf eine Weise angschlossen werden kann, sollte auch ein Verdrahtungsplan bzw. Schema dabei sein. Und nicht zuletzt einen Link auf die verwendeten Bibliotheken, damit wir auch wissen, welcher Code sonst noch bei Dir läuft.

wisbo

#2
Mar 19, 2014, 05:27 pm Last Edit: Mar 19, 2014, 06:35 pm by wisbo Reason: 1
Ok, hier ein Testprogramm

Ausgabe:

Pressure: 150757 Pa   Altitude: -3482.60 m   Temperature: 21.40°C
Pressure: 101129 Pa   Altitude: 16.50 m   Temperature: 21.40°C
Pressure: 101137 Pa   Altitude: 15.83 m   Temperature: 21.40°C
Pressure: 150755 Pa   Altitude: -3482.05 m   Temperature: -187.00°C
Pressure: 150763 Pa   Altitude: -3481.15 m   Temperature: 21.40°C
Pressure: 101137 Pa   Altitude: 16.75 m   Temperature: 21.40°C
Pressure: 75244 Pa   Altitude: 2440.81 m   Temperature: 21.40°C

Der 433-MHz-Sender ist nicht angeschlossen, Hf-Störungen scheiden also aus.

Verwendete Libraries:
http://www.airspayce.com/mikem/arduino/VirtualWire/
https://learn.sparkfun.com/tutorials/bmp180-barometric-pressure-sensor-hookup-/installing-the-arduino-library

Code: [Select]

#include <VirtualWire.h>

const int led_pin = 11;
const int transmit_pin = 12;
const int receive_pin = 2;
const int transmit_en_pin = 3;


// Include the Wire library for I2C access.
#include <Wire.h>
// Include the Love Electronics BMP180 library.
#include <BMP180.h>

// Store an instance of the BMP180 sensor.
BMP180 barometer;
// We are going to use the on board LED for an indicator.
int indicatorLed = 13;

// Store the current sea level pressure at your location in Pascals.
float seaLevelPressure = 101325;

void setup()
{
 
[color=red][font=Verdana] // Wenn diese Inititialisierung eingebaut ist, liefert der BMP 180 falsche Werte:

 vw_set_tx_pin(transmit_pin);
 vw_set_rx_pin(receive_pin)
 vw_set_ptt_pin(transmit_en_pin);
 vw_set_ptt_inverted(true); // Required for DR3100
 vw_setup(2000);       // Bits per sec[/color]

 
 
 // We start the serial library to output our messages.
 Serial.begin(9600);
 // We start the I2C on the Arduino for communication with the BMP180 sensor.
 Wire.begin();
 // Set up the Indicator LED.
 pinMode(indicatorLed, OUTPUT);
 // We create an instance of our BMP180 sensor.
 barometer = BMP180();
 // We check to see if we can connect to the sensor.
 if(barometer.EnsureConnected())
 {
   Serial.println("Connected to BMP180."); // Output we are connected to the computer.
   digitalWrite(indicatorLed, HIGH); // Set our LED.
   
    // When we have connected, we reset the device to ensure a clean start.
   barometer.SoftReset();
   // Now we initialize the sensor and pull the calibration data.
   barometer.Initialize();
 }
 else
 {
   Serial.println("Could not connect to BMP180.");
   digitalWrite(indicatorLed, LOW); // Set our LED.
 }
}

void loop()
{
 if(barometer.IsConnected)
 {
   // Retrive the current pressure in Pascals.
   long currentPressure = barometer.GetPressure();
   
   // Print out the Pressure.
   Serial.print("Pressure: ");
   Serial.print(currentPressure);
   Serial.print(" Pa");
   
   // Retrive the current altitude (in meters). Current Sea Level Pressure is required for this.
   float altitude = barometer.GetAltitude(seaLevelPressure);
   
   // Print out the Altitude.
   Serial.print("\tAltitude: ");
   Serial.print(altitude);
   Serial.print(" m");
   
   // Retrive the current temperature in degrees celcius.
   float currentTemperature = barometer.GetTemperature();
   
   // Print out the Temperature
   Serial.print("\tTemperature: ");
   Serial.print(currentTemperature);
   Serial.write(176);
   Serial.print("C");
   
   Serial.println(); // Start a new line.
   delay(1000); // Show new results every second.
 }
}
Grüße

Willi

rudirabbit

Lese mal in den Dokus der beiden Lib's nach welche Timer des AVR hier evtl. benutzt werden.
Wenn beide den gleichen Timer verwenden, wird es nicht funktionieren.

Ist nur ein Verdacht von mir. 
Arduino UNO,MEGA,DUE 
Dunkel die andere Seite ist. - Klappe, Yoda, und iss deinen Toast :-)

wisbo


Lese mal in den Dokus der beiden Lib's nach welche Timer des AVR hier evtl. benutzt werden.


Danke, das könnte die Ursache sein. Ich wühle mich dann mal da rein.
Grüße

Willi

pylon

Zuerst mal: wenn Du Code postest, musst Du immer Code-Tags verwenden, das Forum-System kann sonst gewisse Teile unterdrücken.

VirtualWire verwendet Timer1, um in regelmässigen Abständen einen Interrupt auszulösen. Da dessen Handler nicht sehr kurz gehalten ist, kann das Timing unter Umständen etwas durcheinander kommen und ggfs. die I2C-Übertragung des BMP180 stören. Da die Lese-Routine der Bibliothek nicht sehr sauber programmiert ist, könnte dies theoretisch sogar zu einem Dead-Lock führen:

Code: [Select]
char SFE_BMP180::readBytes(unsigned char *values, char length)
// Read an array of bytes from device
// values: external array to hold data. Put starting register in values[0].
// length: number of bytes to read
{
 char x;

 Wire.beginTransmission(BMP180_ADDR);
 Wire.write(values[0]);
 _error = Wire.endTransmission();
 if (_error == 0)
   {
   Wire.requestFrom(BMP180_ADDR,length);
   while(Wire.available() != length) ; // wait until bytes are ready
   for(x=0;x<length;x++)
     {
     values[x] = Wire.read();
     }
   return(1);
   }
 return(0);
}


Der Rückgabewert von Wire.requestFrom() wird nicht geprüft, dafür wird danach unendlich lange gewartet, bis wirklich Daten eingetroffen sind. Das kann verherende Folgen haben. Besser wäre:

Code: [Select]
char SFE_BMP180::readBytes(unsigned char *values, char length)
// Read an array of bytes from device
// values: external array to hold data. Put starting register in values[0].
// length: number of bytes to read
{
 char x;

 Wire.beginTransmission(BMP180_ADDR);
 Wire.write(values[0]);
 _error = Wire.endTransmission();
 if (_error == 0)
   {
   if (Wire.requestFrom(BMP180_ADDR,length) != length) return 0;
   for(x=0;x<length;x++)
     {
     values[x] = Wire.read();
     }
   return(1);
   }
 return(0);
}


Allerdings verwendest Du nicht die von Dir verlinkte Bibliothek, denn diese zwei Methoden existieren dort nicht:

Code: [Select]
    // When we have connected, we reset the device to ensure a clean start.
   barometer.SoftReset();
   // Now we initialize the sensor and pull the calibration data.
   barometer.Initialize();

wisbo


Zuerst mal: wenn Du Code postest, musst Du immer Code-Tags verwenden, das Forum-System kann sonst gewisse Teile unterdrücken.

Sorry, ist geändert.

Ich muß gestehen, daß ich die h- und cpp-Files nicht ansatzweise verstehe , also auch keine Chance sehe, da was zu ändern.

Bei den Library-Links kann ich mich geirrt haben, ehrlich gesagt weiss ich nicht mehr, wo ich meine her habe.
Grüße

Willi

pylon

Dann hänge mal den Code Deiner Bibliothek an, damit wir wenigstens prüfen können, was sie macht.

wisbo

Hier kommt er.

Teil 1:

BMP180.h:

Code: [Select]

/*
BMP180.h - Header file for the BMP180 Barometric Pressure Sensor Arduino Library.
Copyright (C) 2012 Love Electronics Ltd (loveelectronics.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Datasheet for BMP180:
http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf

*/

#ifndef BMP180_h
#define BMP180_h

#include <inttypes.h>
#include "../Wire/Wire.h"

#define BMP180_Address 0x77

#define ChipIdData 0x55
#define ControlInstruction_MeasureTemperature 0x2E
#define ControlInstruction_MeasurePressure 0x34

#define Reg_ChipId 0xD0
#define Reg_Control 0xF4
#define Reg_CalibrationStart 0xAA
#define Reg_CalibrationEnd 0xBE
#define Reg_AnalogConverterOutMSB 0xF6
#define Reg_SoftReset 0xE0
#define SoftResetInstruction 0xB6

#define ErrorCode_1 "Entered sample resolution was invalid. See datasheet for details."
#define ErrorCode_1_Num 1

#define BMP180_Mode_UltraLowPower 0
#define BMP180_Mode_Standard 1
#define BMP180_Mode_HighResolution 2
#define BMP180_Mode_UltraHighResolution 3

class BMP180
{
public:
  BMP180();

  void Initialize(void);

  int GetUncompensatedTemperature();
  float CompensateTemperature(int uncompensatedTemperature);
 
  long GetUncompensatedPressure();
  long CompensatePressure(long uncompensatedPressure);
 
  float GetTemperature();
  long GetPressure();

  float GetAltitude(float currentSeaLevelPressureInPa);
 
  void SoftReset();
  uint8_t SetResolution(uint8_t sampleResolution, bool oversample);

  void PrintCalibrationData();

  uint8_t EnsureConnected();
  uint8_t IsConnected;
  char* GetErrorText(int errorCode);
protected:
  void Write(int address, int byte);
  uint8_t* Read(int address, int length);
  void Read2(int address, int length, uint8_t buffer[]);
private:
uint8_t OversamplingSetting;
        bool Oversample;
int ConversionWaitTimeMs;
int LastTemperatureData;
int LastTemperatureTime;
int AcceptableTemperatureLatencyForPressure;

int Calibration_AC1;
        int Calibration_AC2;
        int Calibration_AC3;
        unsigned int Calibration_AC4;
        unsigned int Calibration_AC5;
        unsigned int Calibration_AC6;
        int Calibration_B1;
        int Calibration_B2;
        int Calibration_MB;
        int Calibration_MC;
        int Calibration_MD;
};
#endif



Grüße

Willi

wisbo

Teil 2:

BMP180.cpp

Code: [Select]

/*
BMP180.h - Header file for the BMP180 Barometric Pressure Sensor Arduino Library.
Copyright (C) 2012 Love Electronics Ltd (loveelectronics.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Datasheet for BMP180:
http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf

*/

#include "BMP180.h"
#include "Arduino.h"

BMP180::BMP180()
{
  ConversionWaitTimeMs = 5;
  OversamplingSetting = 0;
  Oversample = false;

  LastTemperatureTime = -1000;
  LastTemperatureData = 0;

  AcceptableTemperatureLatencyForPressure = 1000;

  SetResolution(BMP180_Mode_Standard, false);
}

uint8_t BMP180::EnsureConnected()
{
uint8_t data = Read(Reg_ChipId, 1)[0];

if(data == ChipIdData)
IsConnected = 1;
else
IsConnected = 0;

return IsConnected;
}

void BMP180::Initialize()
{
uint8_t* buffer = Read(Reg_CalibrationStart, Reg_CalibrationEnd - Reg_CalibrationStart + 2);
// This data is in Big Endian format from the BMP180.
    Calibration_AC1 = (buffer[0] << 8) | buffer[1];
    Calibration_AC2 = (buffer[2] << 8) | buffer[3];
    Calibration_AC3 = (buffer[4] << 8) | buffer[5];
    Calibration_AC4 = (buffer[6] << 8) | buffer[7];
    Calibration_AC5 = (buffer[8] << 8) | buffer[9];
    Calibration_AC6 = (buffer[10] << 8) | buffer[11];
    Calibration_B1 = (buffer[12] << 8) | buffer[13];
    Calibration_B2 = (buffer[14] << 8) | buffer[15];
    Calibration_MB = (buffer[16] << 8) | buffer[17];
    Calibration_MC = (buffer[18] << 8) | buffer[19];
    Calibration_MD = (buffer[20] << 8) | buffer[21];
}

void BMP180::PrintCalibrationData()
{
Serial.print("AC1:\t"); Serial.println(Calibration_AC1);
Serial.print("AC2:\t"); Serial.println(Calibration_AC2);
Serial.print("AC3:\t"); Serial.println(Calibration_AC3);
Serial.print("AC4:\t"); Serial.println(Calibration_AC4);
Serial.print("AC5:\t"); Serial.println(Calibration_AC5);
Serial.print("AC6:\t"); Serial.println(Calibration_AC6);
Serial.print("B1:\t"); Serial.println(Calibration_B1);
Serial.print("B2:\t"); Serial.println(Calibration_B2);
Serial.print("MB:\t"); Serial.println(Calibration_MB);
Serial.print("MC:\t"); Serial.println(Calibration_MC);
Serial.print("MD:\t"); Serial.println(Calibration_MD);
}

int BMP180::GetUncompensatedTemperature()
{
    // Instruct device to perform a conversion.
    Write(Reg_Control, ControlInstruction_MeasureTemperature);
    // Wait for the conversion to complete.
    delay(5);
    uint8_t* data = Read(Reg_AnalogConverterOutMSB, 2);
    int value = (data[0] << 8) | data[1];
    return value;
}

long BMP180::GetUncompensatedPressure()
{
    long pressure = 0;
    int loops = Oversample ? 3 : 1;

    for (int i = 0; i < loops; i++)
    {
        // Instruct device to perform a conversion, including the oversampling data.
        uint8_t CtrlByte = ControlInstruction_MeasurePressure + (OversamplingSetting << 6);
        Write(Reg_Control, CtrlByte);
        // Wait for the conversion
        delay(ConversionWaitTimeMs);
        // Read the conversion data.
        uint8_t buffer[3];
Read2(Reg_AnalogConverterOutMSB, 3, buffer);

        // Collect the data (and push back the LSB if we are not sampling them).
        pressure = ((((long)buffer[0] <<16) | ((long)buffer[1] <<8) | ((long)buffer[2])) >> (8-OversamplingSetting));
    }
    return pressure / loops;
}

float BMP180::CompensateTemperature(int uncompensatedTemperature)
{
    int temperature;
    int x2;
long x1;
x1 = (((long)uncompensatedTemperature - (long)Calibration_AC6) * (long)Calibration_AC5) >> 15;
    x2 = ((long)Calibration_MC << 11) / (x1 + Calibration_MD);
    int param_b5 = x1 + x2;
    temperature = (int)((param_b5 + 8) >> 4);  /* temperature in 0.1 deg C*/
    float fTemperature = temperature;
fTemperature /= 10.0;

    // Record this data because it is required by the pressure algorithem.
    LastTemperatureData = param_b5;
    LastTemperatureTime = millis();

    return fTemperature;
}

long BMP180::CompensatePressure(long uncompensatedPressure)
{
int msSinceLastTempReading = millis() - LastTemperatureTime;
    // Check to see if we have old temperature data.
    if (msSinceLastTempReading > AcceptableTemperatureLatencyForPressure)
        GetTemperature(); // Refresh the temperature.

    // Data from the BMP180 datasheet to test algorithm.
    /*OversamplingSetting = 0;
    uncompensatedPressure = 23843;
    LastTemperatureData = 2399;
    Calibration_AC1 = 408;
    Calibration_AC2 = -72;
    Calibration_AC3 = -14383;
    Calibration_AC4 = 32741;
    Calibration_AC5 = 32757;
    Calibration_AC6 = 23153;
    Calibration_B1 = 6190;
    Calibration_B2 = 4;
    Calibration_MB = -32767;
    Calibration_MC = -8711;
    Calibration_MD = 2868;*/

    // Algorithm taken from BMP180 datasheet.
    long b6 = LastTemperatureData - 4000;
    long x1 = (Calibration_B2 * (b6 * b6 >> 12)) >> 11;
    long x2 = Calibration_AC2 * b6 >> 11;
    long x3 = x1 + x2;
    long b3 = ((Calibration_AC1 * 4 + x3) << OversamplingSetting) + 2;
    b3 = b3 >> 2;
    x1 = Calibration_AC3 * b6 >> 13;
    x2 = (Calibration_B1 * (b6 * b6 >> 12)) >> 16;
    x3 = ((x1 + x2) + 2) >> 2;
    long b4 = Calibration_AC4 * (x3 + 32768) >> 15;
    unsigned long b7 = (((uncompensatedPressure - b3)) * (50000 >> OversamplingSetting));
    long p;
    if (b7 < 0x80000000)
{
p = ((b7 * 2) / b4);   
}
    else
{
        p = ((b7 / b4) * 2);
}

    x1 = (p >> 8) * (p >> 8);
    x1 = (x1 * 3038) >> 16;
    x2 = (-7357 * p) >> 16;
    p = p + ((x1 + x2 + 3791) >> 4);

    return p;
}

void BMP180::SoftReset()
{
    Write(Reg_SoftReset, SoftResetInstruction);
    delay(100);
}

float BMP180::GetTemperature()
{
    return CompensateTemperature(GetUncompensatedTemperature());
}

long BMP180::GetPressure()
{
    return CompensatePressure(GetUncompensatedPressure());
}

float BMP180::GetAltitude(float currentSeaLevelPressureInPa)
{
    // Get pressure in Pascals (Pa).
    float pressure = GetPressure();
    // Calculate altitude from sea level.
    float altitude = 44330.0 * (1.0 - pow(pressure / currentSeaLevelPressureInPa, 0.1902949571836346));
    return altitude;
}

uint8_t BMP180::SetResolution(uint8_t sampleResolution, bool oversample)
{
    OversamplingSetting = sampleResolution;
    Oversample = oversample;
    switch (sampleResolution)
    {
        case 0:
            ConversionWaitTimeMs = 5;
            break;
        case 1:
            ConversionWaitTimeMs = 8;
            break;
        case 2:
            ConversionWaitTimeMs = 14;
            break;
        case 3:
            ConversionWaitTimeMs = 26;
            break;
        default:
            return ErrorCode_1_Num;
    }
}

void BMP180::Write(int address, int data)
{
  Wire.beginTransmission(BMP180_Address);
  Wire.write(address);
  Wire.write(data);
  Wire.endTransmission();
}

uint8_t* BMP180::Read(int address, int length)
{
  Wire.beginTransmission(BMP180_Address);
  Wire.write(address);
  Wire.endTransmission();
 
  Wire.beginTransmission(BMP180_Address);
  Wire.requestFrom(BMP180_Address, length);

  uint8_t buffer[length];
  while(Wire.available())
  {
  for(uint8_t i = 0; i < length; i++)
  {
  buffer[i] = Wire.read();
  }
  }
  Wire.endTransmission();

  return buffer;
}

void BMP180::Read2(int address, int length, uint8_t buffer[])
{
  Wire.beginTransmission(BMP180_Address);
  Wire.write(address);
  Wire.endTransmission();
 
  Wire.beginTransmission(BMP180_Address);
  Wire.requestFrom(BMP180_Address, length);

  while(Wire.available())
  {
  for(uint8_t i = 0; i < length; i++)
  {
  buffer[i] = Wire.read();
  }
  }
  Wire.endTransmission();
}

char* BMP180::GetErrorText(int errorCode)
{
if(ErrorCode_1_Num == 1)
return ErrorCode_1;

return "Error not defined.";
}



Grüße

Willi

wisbo

#10
Mar 19, 2014, 07:31 pm Last Edit: Mar 19, 2014, 07:40 pm by wisbo Reason: 1
VirtualWire ist zu groß um hier zu posten, hier ist der korrekte Link:
http://www.pjrc.com/teensy/td_libs_VirtualWire.html
Grüße

Willi

pylon

VirtualWire ist wahrscheinlich auch die Version, die Du einsetzt.

Bitte verwende die hier gepostete Version der BMP180-Bibliothek nicht mehr, die ist furchtbar schlecht programmiert (die Read-Methode ist zum Beispiel schlicht falsch in der Reihenfolge der I2C-Ansteuerung). Schreibe Deinen Sketch mal auf die andere Bibliothek um, vielleicht löst das bereits Dein Problem. Wenn Du dann noch die von mir vorgeschlagene Änderung machst, dürften zumindest weitere Hinweise vorhanden sein, warum Du Probleme hast.

SkobyMobil

Hallo,
Betriebsspannung bei Sensor und I2C sind gleich? Hast Du den I2C Bus richtig
aufgebaut?
Hier gibt es ganz gute Info
https://learn.sparkfun.com/tutorials/bmp180-barometric-pressure-sensor-hookup-/all
Gruß und Spaß
Andreas
die zweite Maus bekommt den Speck...

wisbo

So, ich habe jetzt die Sparfun-Library hier.
Werde ich morgen mal testen.
Die Verdrahtung ist korrekt, einzeln arbeiten die Teile problemlos, nur eben nicht zusammen.
Danke euch allen schonmal für die Hilfe, ich melde mich wieder.
Grüße

Willi

wisbo

Es funktioniert!

Mit der  Sparfun-Library lief es auf Anhieb.
Ich danke allen Beteiligten für die Hilfe.
Grüße

Willi

Go Up