Go Down

Topic: Pressure Sensors MS5611 MS5803 (Read 29275 times) previous topic - next topic

vanja

#15
May 06, 2012, 01:55 pm Last Edit: May 06, 2012, 06:38 pm by vanja Reason: 1
Rather foolishly I did not check the results for below 20C. I obtain the following above 20C

Actual TEMP= 20.07      Actual PRESSURE= 1003.17
Actual ALTITUDE= 85.88m

RAW Temp D2=  8380806 RAW Pressure D1=  8287532

C1 = 54277
C2 = 57096
C3 = 33888
C4 = 33309
C5 = 32729
C6 = 28420

And below 20C
Actual TEMP= 145530.26      Actual PRESSURE= 345737.84
Actual ALTITUDE= -15034990.00m

RAW Temp D2=  8374970 RAW Pressure D1=  8289406

I have been checking the figures and obtain, calculating by hand, the following values for these two instances.
              Above 20    Below 20

dT          2182         -3654
D2          8380806      8374970
c5*2^8       8378624      8378624
c6/8388608 =   0.003387928
TEMP       20.07          19.87

In order to obtain a temperature reading below 20C a negative value must be subtracted from the value 2000 (or 20C) in the line
TEMP = (int64_t)dT * (int64_t)C[6] / 8388608 + 2000;
That is dT must be negative which it indeed is from the readings with a value given by the hand  calculated value of -3654, resulting in an acceptable temperature of 19.87C.

I read P7 of the 5611 datasheet as saying that the calculations are valid for ALL temperatures but they become less accurate below 20C. I was content using this and the sums on P7 as a first approximation. I ran the sketch and put the sensor outside and immediately received a temperature reading 145530.26 shown above. I thought it may have been something to do with the <20C corrections that Leo kindly introduced but obviously that was not the case.  
The error seems to lie in TEMP = (int64_t)dT * (int64_t)C[6] / 8388608 + 2000; not accepting the negative value for dT, in this case the -3654. The error must lie, I think, in the interpretation of the value of dT or (int64_t)dT as all the rest of the values on this line are constants.
Any ideas thoughts?
Best

Juergen_S

I 've added this lines from Fabio's Code to make the Pressure-readings smoother.


#define MOVAVG_SIZE 32

float movavg_buff[MOVAVG_SIZE];
int movavg_i=0;

uint32_t D1 = 0;
uint32_t D2 = 0;
....

Wire.begin();
  Serial.begin(9600); //9600 changed 'cos of timing?
  delay(100);
  initial(ADDRESS);
  //populate movavg_buff before starting loop
  for(int i=0; i<MOVAVG_SIZE; i++) {
   movavg_buff = Pressure;
  }


Serial.print("     Actual TEMP= ");
  Serial.print(Temperature);
  Serial.print("      Actual PRESSURE= ");
  pushAvg(Pressure);
  Serial.print(getAvg(movavg_buff, MOVAVG_SIZE));


void pushAvg (float val) {
  movavg_buff[movavg_i] = val;
  movavg_i = (movavg_i + 1) % MOVAVG_SIZE;
}


float getAvg(float * buff,int size) {
  float sum = 0.0;
  for(int i=0; i<size; i++) {
    sum += buff;
  }
  return sum /size;
}


long getVal(int address, byte code)
....

_Leo_

Juergen, check your code because it's not going to work correctly.
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

Juergen_S

#18
May 12, 2012, 02:57 pm Last Edit: May 21, 2012, 10:51 pm by Juergen_S Reason: 1
]@_Leo

i use my code at a few days, the  calculations of temperature and pressure are correct! The only thing i' ve recognize, is the pressure value grows up after reset to a stable result. This happens through the average code.

Here my complete Code with my LCD EA-DIP204-4, if someone use this code with these Display, he must change these line in the LiquidCrystal cpp.file: int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
                           to int row_offsets[] = { 0x00, 0x20, 0x40, 0x60 };

here a link to this display: http://www.lcd-module.de/pdf/doma/dip204-4.pdf

It's a EA-DIP204J-4NLW. The only problem are the pins, whose are in a distance of 2 mm !

Code: [Select]

#include <Wire.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(9, 8, 7, 6, 5, 4);

#define ADDRESS 0x77 //0x76
#define MOVAVG_SIZE 32

float movavg_buff[MOVAVG_SIZE];
int movavg_i=0;

uint32_t D1 = 0;
uint32_t D2 = 0;
int64_t dT = 0;
int32_t TEMP = 0;
int64_t OFF = 0;
int64_t SENS = 0;
int32_t P = 0;
uint16_t C[7];

float Temperature;
float Pressure;


void setup() {
 // Disable internal pullups, 10Kohms are on the breakout
 PORTC |= (1 << 4);
 PORTC |= (1 << 5);

 Wire.begin();
 Serial.begin(9600); //9600 changed 'cos of timing?
 delay(100);
 initial(ADDRESS);
 //populate movavg_buff before starting loop
 for(int i=0; i<MOVAVG_SIZE; i++) {
  //movavg_buff[i] = Pressure;
 }
 // set up the LCD's number of columns and rows:
 lcd.begin(20, 4);
 {
   lcd.command(0x01);//clear display lcd.command (0x01) / / clear display
   delay(02);
   lcd.command(0x24);//function set RE=1 lcd.command (0x24) / / function set RE = 1
   delay(50);
   lcd.command(0x09);//extendet function set, 4 lines, 5-dot fontwith
   delay(50);
   lcd.command(0x20);//function set RE=0 lcd.command (0x20) / / function set RE = 0
   delay(50);
   lcd.command(0x0C);//control, display on, cursor off, blinken off
   delay(50);
   lcd.command(0x01);//clear display lcd.command (0x01) / / clear display
   delay(20);
   lcd.command(0x06);//entry mode segment bidirectional

 }
}

void loop()
{
 D1 = getVal(ADDRESS, 0x48); // Pressure raw
 D2 = getVal(ADDRESS, 0x58);// Temperature raw

 dT   = D2 - ((uint64_t)C[5] << 8);
 OFF  = ((int64_t)C[2] << 16) + ((dT * C[4]) >> 7);
 SENS = ((int32_t)C[1] << 15) + ((dT * C[3]) >> 8);

 TEMP = (int64_t)dT * (int64_t)C[6] / 8388608 + 2000;

 Temperature = (float)TEMP / 100;

 P  = ((int64_t)D1 * SENS / 2097152 - OFF) / 32768;

 Pressure = (float)P / 100;

 Serial.print("     Actual TEMP= ");
 Serial.print(Temperature);
 Serial.print("      Actual PRESSURE= ");
 pushAvg(Pressure);
 Serial.print(getAvg(movavg_buff, MOVAVG_SIZE));

 Serial.println();  
 Serial.print(" RAW Temp D2=  ");
 Serial.print(D2);
 Serial.print(" RAW Pressure D1=  ");
 Serial.println(D1);
 Serial.println();
 lcd.setCursor(0, 0);
 lcd.print("J");
 lcd.setCursor(1, 0);
 lcd.write(0x7E);
 lcd.setCursor(2, 0);
 lcd.print("rgen Schmidt");
 lcd.setCursor(0, 1);
 lcd.print("Temperatur:");
 lcd.setCursor(12, 1);
 lcd.print(Temperature);
 lcd.setCursor(18, 1);
 lcd.write(0xDC);
 lcd.print("C");
 lcd.setCursor(0, 2);
 lcd.print("Druck hPa:");
 lcd.setCursor(10, 2);
 if ((Pressure)<1000)
 {
   lcd.print(" ");
 }
 lcd.print(getAvg(movavg_buff, MOVAVG_SIZE));

 //  Serial.print(" dT=  ");
 //  Serial.println(dT); can't print int64_t size values
 //Serial.println();
 //Serial.print(" C1 = ");
 //Serial.println(C[1]);
 //Serial.print(" C2 = ");
 //Serial.println(C[2]);
 //Serial.print(" C3 = ");
 //Serial.println(C[3]);
 //Serial.print(" C4 = ");
 //Serial.print(" C5 = ");
 //Serial.println(C[5]);
 //Serial.print(" C6 = ");
 //Serial.println(C[6]);
 //  Serial.print(" C7 = ");
 //  Serial.println(C[7]);
 //Serial.println();

}

void pushAvg (float val) {
 movavg_buff[movavg_i] = val;
 movavg_i = (movavg_i + 1) % MOVAVG_SIZE;
}  

float getAvg(float * buff,int size) {
 float sum = 0.0;
 for(int i=0; i<size; i++) {
   sum += buff[i];
 }
 return sum /size;
}

long getVal(int address, byte code)
{
 unsigned long ret = 0;
 Wire.beginTransmission(address);
 Wire.write(code);
 Wire.endTransmission();
 delay(10);
 // start read sequence
 Wire.beginTransmission(address);
 Wire.write((byte) 0x00);
 Wire.endTransmission();
 Wire.beginTransmission(address);
 Wire.requestFrom(address, (int)3);
 if (Wire.available() >= 3)
 {
   ret = Wire.read() * (unsigned long)65536 + Wire.read() * (unsigned long)256 + Wire.read();
 }
 else {
   ret = -1;
 }
 Wire.endTransmission();
 return ret;
}

void initial(uint8_t address)
{

 Serial.println();
 Serial.println("PROM COEFFICIENTS ivan");

 Wire.beginTransmission(address);
 Wire.write(0x1E); // reset
 Wire.endTransmission();
 delay(10);


 for (int i=0; i<6  ; i++) {

   Wire.beginTransmission(address);
   Wire.write(0xA2 + (i * 2));
   Wire.endTransmission();

   Wire.beginTransmission(address);
   Wire.requestFrom(address, (uint8_t) 6);
   delay(1);
   if(Wire.available())
   {
     C[i+1] = Wire.read() << 8 | Wire.read();
   }
   else {
     Serial.println("Error reading PROM 1"); // error reading the PROM or communicating with the device
   }
   Serial.println(C[i+1]);
 }
 Serial.println();
}

_Leo_

#19
May 12, 2012, 03:22 pm Last Edit: May 12, 2012, 03:27 pm by _Leo_ Reason: 1

//populate movavg_buff before starting loop
 for(int i=0; i<MOVAVG_SIZE; i++) {
  movavg_buff = Pressure;
 }


It should be:
Code: [Select]
//populate movavg_buff before starting loop
 for(int i=0; i<MOVAVG_SIZE; i++) {
  movavg_buff[i] = Pressure; // Pressure is read from the sensor in every loop!!
 }




:)
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

Juergen_S

Hello _Leo

here is my code, i make a mistake to do not use the #-button to insert my code here.

Jürgen

_Leo_

Jürgen,

you misunderstood.

Code: [Select]
"movavg_buff[i] = Pressure;"

Pressure has no value in your code.

You need to write a subroutine that reads the pressure from the sensor. Then call the routine in the loop to populate the buffer.

Example:
Code: [Select]
"movavg_buff[i] = Get_Pressure();"

Leo
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

vanja

Leo can you caste your eye over these results and those in my last post?
Dead on the reference temperature of 20C the temperature changes to a large negative number which seems to be a constant-21329306.00 with the sensor put into the Kuhlschrank.
The code I use is as already posted which I assume you use and Juergen usw.

RAW Temp D2=  8379134 RAW Pressure D1=  8352890
     Actual TEMP= 20.01      Actual PRESSURE= 1019.96

RAW Temp D2=  8379080 RAW Pressure D1=  8352918
     Actual TEMP= 20.00      Actual PRESSURE= 1019.96

RAW Temp D2=  8378778 RAW Pressure D1=  8352956
     Actual TEMP= -21329306.00      Actual PRESSURE= -9499139.00

RAW Temp D2=  8378598 RAW Pressure D1=  8353160
     Actual TEMP= -21329306.00      Actual PRESSURE= -9495526.00

RAW Temp D2=  8378420 RAW Pressure D1=  8353066
     Actual TEMP= -21329306.00      Actual PRESSURE= -9504028.00

RAW Temp D2=  8378290 RAW Pressure D1=  8353288
     Actual TEMP= -21329306.00      Actual PRESSURE= -9503490.00

If I use another 5611 then I get the same thing

RAW Temp D2=  7972696 RAW Pressure D1=  8170442
     Actual TEMP= -21326056.00      Actual PRESSURE= -4003808.25

With this one the Actual TEMP is a constant at-21326056.00 and the raw pressure is half.

(Has it anything to do with the use of int64_t).

Best

c00laris

Hi,
I found the same problemm for temperatures below 20°C. dt then gets negative. The uint_32 then roll to big numbers
I changed dt to int32_t and the line for calculation of dt as follows:
dT   = D2 - ((int32_t)C[5] << 8);
Now it seems to work. ;)
BR
c00laris

You see only a small "jump" due to the change in the compensation at 20.00°C:

Actual TEMP= 19.99      Actual PRESSURE= 975.79
Actual ALTITUDE= 324.33m
RAW Temp D2=  8787722 RAW Pressure D1=  8083108
dT=  -246
TEMP=  1999
T1=  0
OFF=  -1100205905
OFF1=  2
SENS=  1658456444
SENS1=  1



Actual TEMP= 20.00      Actual PRESSURE= 975.73
Actual ALTITUDE= 324.88m
RAW Temp D2=  8788094 RAW Pressure D1=  8082768
dT=  126
TEMP=  2000
T1=  0
OFF=  -1100125650
OFF1=  2
SENS=  1658502323
SENS1=  1



Actual TEMP= 20.00      Actual PRESSURE= 975.73
Actual ALTITUDE= 324.88m
RAW Temp D2=  8788254 RAW Pressure D1=  8082694
dT=  286
TEMP=  2000
T1=  0
OFF=  -1100091132
OFF1=  2
SENS=  1658522055
SENS1=  1



Actual TEMP= 20.01      Actual PRESSURE= 975.75
Actual ALTITUDE= 324.71m
RAW Temp D2=  8788534 RAW Pressure D1=  8082688
dT=  566
TEMP=  2001
T1=  0
OFF=  -1100030727
OFF1=  2
SENS=  1658556587
SENS1=  1



robtillaart

@c00laris
Can you post your final code for future reference?
Thanks,
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

_Leo_


Hi,
I found the same problemm for temperatures below 20°C. dt then gets negative. The uint_32 then roll to big numbers
I changed dt to int32_t and the line for calculation of dt as follows:
dT   = D2 - ((int32_t)C[5] << 8);
Now it seems to work. ;)
BR
c00laris
...


That's a bad idea because C[] can be between 0 - 65535!

To solve the problem in the code you are using use:
Code: [Select]
dT = D2 - ((uint64_t)C[5] << 8);
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

TheMike

#26
Jul 07, 2012, 08:30 pm Last Edit: Jul 07, 2012, 08:47 pm by TheMike Reason: 1
Hi,
I just tested my MS5611 using the following code (Arduino-1.0.1) letting the sensor rest quietly on my desk (weather is fine,..):

Code: [Select]
#include <Wire.h>
#define ADDRESS 0x76 //0x77

uint32_t D1 = 0;
uint32_t D2 = 0;
int64_t dT = 0;
int32_t TEMP = 0;
int64_t OFF = 0;
int64_t SENS = 0;
int32_t P = 0;
uint16_t C[7];

float Temperature;
float Pressure;


void setup() {
// Disable internal pullups, 10Kohms are on the breakout
PORTC |= (1 << 4);
PORTC |= (1 << 5);

 Wire.begin();
 Serial.begin(115200); //9600 changed 'cos of timing?
 delay(100);
 initial(ADDRESS);

}

void loop()
{
 D1 = getVal(ADDRESS, 0x48); // Pressure raw
 D2 = getVal(ADDRESS, 0x58);// Temperature raw

 dT   = D2 - ((uint64_t)C[5] << 8);
 OFF  = ((int64_t)C[2] << 16) + ((dT * C[4]) >> 7);
 SENS = ((int32_t)C[1] << 15) + ((dT * C[3]) >> 8);

 TEMP = (int64_t)dT * (int64_t)C[6] / 8388608 + 2000;

 Temperature = (float)TEMP / 100;
 
 P  = ((int64_t)D1 * SENS / 2097152 - OFF) / 32768;

 Pressure = (float)P;
 
//  Serial.print("     Actual TEMP= ");
//  Serial.print(Temperature);
//  Serial.print("      Actual PRESSURE= ");
 Serial.println(Pressure);

//  Serial.println();  
//  Serial.print(" RAW Temp D2=  ");
//  Serial.print(D2);
//  Serial.print(" RAW Pressure D1=  ");
//  Serial.println(D1);
//  Serial.println();

//  Serial.print(" dT=  ");
//  Serial.println(dT); can't print int64_t size values
//  Serial.println();
//  Serial.print(" C1 = ");
//  Serial.println(C[1]);
//  Serial.print(" C2 = ");
//  Serial.println(C[2]);
//  Serial.print(" C3 = ");
//  Serial.println(C[3]);
//  Serial.print(" C4 = ");
//  Serial.println(C[4]);
//  Serial.print(" C5 = ");
//  Serial.println(C[5]);
//  Serial.print(" C6 = ");
//  Serial.println(C[6]);
//  Serial.print(" C7 = ");
//  Serial.println(C[7]);
//  Serial.println();

//  delay(1000);
}

long getVal(int address, byte code)
{
 unsigned long ret = 0;
 Wire.beginTransmission(address);
 Wire.write(code);
 Wire.endTransmission();
 delay(10);
 // start read sequence
 Wire.beginTransmission(address);
 Wire.write((byte) 0x00);
 Wire.endTransmission();
 Wire.beginTransmission(address);
 Wire.requestFrom(address, (int)3);
 if (Wire.available() >= 3)
 {
   ret = Wire.read() * (unsigned long)65536 + Wire.read() * (unsigned long)256 + Wire.read();
 }
 else {
   ret = -1;
 }
 Wire.endTransmission();
 return ret;
}

void initial(uint8_t address)
{

 Serial.println();
 Serial.println("PROM COEFFICIENTS ivan");

 Wire.beginTransmission(address);
 Wire.write(0x1E); // reset
 Wire.endTransmission();
 delay(10);


 for (int i=0; i<6  ; i++) {

   Wire.beginTransmission(address);
   Wire.write(0xA2 + (i * 2));
   Wire.endTransmission();

   Wire.beginTransmission(address);
   Wire.requestFrom(address, (uint8_t) 6);
   delay(1);
   if(Wire.available())
   {
      C[i+1] = Wire.read() << 8 | Wire.read();
   }
   else {
     Serial.println("Error reading PROM 1"); // error reading the PROM or communicating with the device
   }
   Serial.println(C[i+1]);
 }
 Serial.println();
}


I just sampled the pressure value for 60 seconds, attached you can find an image of the pressure/time dependency. I think the pressure (97436 Pa) is OK for my height, but the pressure noise seems too much for me! The range is 100 Pa, which would correspond to a height variation of more than 12 meters I think.
What characteristic pressure noise do you have? Is there a possibility to get less noise (oversampling,...?) without averaging too much? I would need about 5 reliable values per second...

Best regards,
Mike

_Leo_

The pressure always has to be corrected in relation to the location of measurement.

The "Noise" you are witnessing can be different depending which hardware you are using.
The sensor has fluctuations, which is normal. However if e.g. the I2C bus layout on the PCB board is poorly designed then you will get additional interference noise.
I'm running 3 different manufactured Arduino platforms, all showing different noise levels. Interestingly my Arduino R3 with protoshield has the least interference noise.

Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

TheMike

The noise can be due to many different reasons, that´s clear....but the magnitude makes me a little bit irritated. I have mounted the MS5611 directly besides a BMP085 on my breadboard, both sharing the same I2C bus just with different addresses.
The MS5611 shows a range of +/-50 Pa, while the BMP085 only shows about +/-15 Pa.
I thought the MS5611 should be much better than the BMP085 exhibiting a max. resolution of around 10 to 15 cm, which would be a factor 100 away from my measurements... :-(



_Leo_


The noise can be due to many different reasons, that´s clear....but the magnitude makes me a little bit irritated. I have mounted the MS5611 directly besides a BMP085 on my breadboard, both sharing the same I2C bus just with different addresses.
The MS5611 shows a range of +/-50 Pa, while the BMP085 only shows about +/-15 Pa.
I thought the MS5611 should be much better than the BMP085 exhibiting a max. resolution of around 10 to 15 cm, which would be a factor 100 away from my measurements... :-(


In your post from the 7th July you didn't state that you were comparing it to the BMP085!
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

Go Up