Hello,
I'm am building a wireless weather station using the Bosch BME280 sensor
Instead of using the standard library I'll rather code the entire thing by myself using the compensation formula provided in the datasheet.
This expression is given in the datasheet:
var2 = (((P >> 2) * dig_P8) >> 13;
Written as is it gives me an unexpected result (gives 493779, with uint32_t P = 97724 and int32_t dig_P8 = -10230 )
But splitting the expression works well (gives -30509)
var2 = (((P >> 2) * dig_P8);
var2 >>= 13;
Why?
system
March 23, 2016, 7:23pm
2
Why?
Because of 16 bit signed integer arithmetic, probably.
We'd know for sure if you'd posted your code.
Here it is, since I'm a beginner the code is messy
The interesting part is a few lines above the end of the function "compute_pressure"
#include <Wire.h>
#define BME280_address 0x77
uint16_t      dig_T1;
signed short int  dig_T2;
signed short int  dig_T3;
uint16_t      dig_P1;
int32_t      dig_P2;
int32_t      dig_P3;
int32_t      dig_P4;
int32_t      dig_P5;
int32_t      dig_P6;
int32_t      dig_P7;
int32_t      dig_P8;
int32_t      dig_P9;
unsigned char   dig_H1;
signed short int  dig_H2;
unsigned char   dig_H3;
signed short    dig_H4;
signed short    dig_H5;
signed char    dig_H6;
long signed int  t_fine;
uint32_t      raw_P;
byte        BME280_calib [31] = {};
void setup() {
Wire.begin();
Serial.begin(9600);
Â
Wire.beginTransmission(0x77);
Wire.write(0x88);
Wire.endTransmission();
Wire.requestFrom(BME280_address,25);
for (int i=0; i <25; i++)
 {
  BME280_calib[i] = Wire.read();
 }
Wire.beginTransmission(0x77);
Wire.write(0xE1);
Wire.endTransmission();
Wire.requestFrom(BME280_address,3);
for (int i=25; i <31; i++)
 {
  BME280_calib[i] = Wire.read();
 }
 dig_T1 = BME280_calib [1] << 8 | BME280_calib [0];
 dig_T2 = BME280_calib [3] << 8 | BME280_calib [2];
 dig_T3 = BME280_calib [5] << 8 | BME280_calib [4];
 dig_P1 = BME280_calib [7] << 8 | BME280_calib [6];
 dig_P2 = BME280_calib [9] << 8 | BME280_calib [8];
 dig_P3 = BME280_calib [11]<< 8 | BME280_calib [10];
 dig_P4 = BME280_calib [13]<< 8 | BME280_calib [12];
 dig_P5 = BME280_calib [15]<< 8 | BME280_calib [14];
 dig_P6 = BME280_calib [17]<< 8 | BME280_calib [16];
 dig_P7 = BME280_calib [19]<< 8 | BME280_calib [18];
 dig_P8 = BME280_calib [21]<< 8 | BME280_calib [20];
 dig_P9 = BME280_calib [23]<< 8 | BME280_calib [22];
 dig_H1 = BME280_calib [24];
 dig_H2 = BME280_calib [26]<< 8 | BME280_calib [25];
 dig_H3 = BME280_calib [27];
 dig_H4 = BME280_calib [28];
 dig_H5 = BME280_calib [29];
 dig_H6 = BME280_calib [30];
/*
Serial.print("dig_P1 = ");
Serial.println (dig_P1);
Serial.print("dig_P2 = ");
Serial.println (dig_P2);
Serial.print("dig_P3 = ");
Serial.println (dig_P3);
Serial.print("dig_P4 = ");
Serial.println (dig_P4);
Serial.print("dig_P5 = ");
Serial.println (dig_P5);
Serial.print("dig_P6 = ");
Serial.println (dig_P6);
Serial.print("dig_P7 = ");
Serial.println (dig_P7);
Serial.print("dig_P8 = ");
Serial.println (dig_P8);
Serial.print("dig_P9 = ");
Serial.println (dig_P9);
*/
}
void loop() {
//get raw temperature:
uint32_t raw_T;
Wire.beginTransmission(0x77);
Wire.write(0xF4);
Wire.write (0x25);
Wire.endTransmission();
Wire.beginTransmission(0x77);
Wire.write(0xFA);
Wire.endTransmission();
Wire.requestFrom(BME280_address,3);
raw_T = Wire.read();
raw_T <<= 8;
raw_T = raw_T | Wire.read();
raw_T <<= 8;
raw_T = raw_T | Wire.read();
raw_T >>= 4;
//compute temperature:
int32_t var1, var2, poub1, poub2;
float T;
//raw_T = raw_T >> 4;
//var1Â = ((raw_T>>3 -dig_T1<<1) * dig_T2) >> 11;
poub1 = raw_T >> 3;
poub2 = dig_T1<<1;
var1 = poub1 - poub2;
var1 = var1 * dig_T2;
var1 = var1 >> 11;
//var2Â = ((((raw_T>>4 -dig_T1) * (raw_T>>4 -dig_T1)) >> 12) * dig_T3) >> 14;/*
poub1 = raw_T >> 4;
poub1 = poub1 - dig_T1;
poub1 = poub1 * poub1;
poub1 = poub1 >> 12;
poub1 = poub1 * dig_T3;
var2 = poub1 >>14;
t_fine = var1 + var2;
TÂ = (t_fine * 5 + 128) >> 8;
T= T/100;
Serial.print ("T= ");
Serial.print (T);
Serial.println ("degC");
//get raw pressure:
Wire.beginTransmission(0x77);
Wire.write(0xF7);
Wire.endTransmission();
Wire.requestFrom(BME280_address,3);
raw_P = Wire.read();
raw_P <<= 8;
raw_P = raw_P | Wire.read();
raw_P <<= 8;
raw_P = raw_P | Wire.read();
raw_P >>= 4;
compute_pressure();
delay (5000);
}
void compute_pressure(){
Â
#define alt 290.0
int32_t var1, var2;
uint32_t P;
float P_atm, var3;
//formules de compensation datasheet BME280:
var1 = (t_fine >> 1) - 64000;
var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * dig_P6;
var2 = var2 + ((var1 * dig_P5) << 1);
var2 = (var2 >>2) + (dig_P4 << 16);
var1 = (((dig_P3 * ((var1 >> 2) * (var1 >> 2)) >> 13) >> 3) + ((dig_P2 * var1) >> 1)) >> 18;
var1 = ((var1 + 32768) * dig_P1) >> 15;
if (var1 == 0)
 {}
Â
P = ((1048576 - raw_P) - (var2 >> 12)) * 3125;
if (P < 0x80000000)
{
 P = (P << 1) / var1;
}
else  //JAMAIS TESTEÂ
{
 P = (P / var1) * 2;
}
var1 = (dig_P9 * ((P >> 3) * (P >> 3) >> 13)) >> 12;
var2 = ((P >> 2) * dig_P8);
var2 >>= 13;
P = P + ((var1 + var2 + dig_P7) >> 4);
P_atm = P;
P_atm /= 100;
//pression au niveau de la mer, formule datasheet BMP180:
var3 = 1 - (alt / 44330);
var3 = pow (var3,5.255);
P_atm = P_atm / var3;
Serial.print ("P_atm = ");
Serial.print (P_atm);
Serial.println ("hPa");
}
system
March 23, 2016, 10:38pm
4
Would be easier to debug if all the right shifts (>>11) were replaced by divisions (/ 2048) then put the right shifts back after its working OK.
outsider:
Would be easier to debug if all the right shifts (>>11) were replaced by divisions (/ 2048) then put the right shifts back after its working OK.
No. The compiler will optimize a /2048 to a shift anyway. But yes, it would make it easier to read if you left it instead of putting it back.
Is there a difference between right shifting an unsigned quantity vs. a signed quantity? Because the expression ((P >> 2) * dig_P8) may have been evaluated to an unsigned because P is unsigned. But var2 is signed. When you separated it you made the >>13 signed, since var2 is signed.
I only ask, because the firewall has deprived me of any chance of research.
DrAzzy
March 23, 2016, 11:54pm
7
aarg:
No. The compiler will optimize a /2048 to a shift anyway. But yes, it would make it easier to read if you left it instead of putting it back.
int x=10000;
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
x = x>>1;
Serial.println(x);
}
1946 bytes compiled size
int x=10000;
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
x = x/2;
Serial.println(x);
}
1952 bytes compiled size.
So it looks like the compiler isn't as smart as we might expect.... (this shocked me when I came across it too - I also expected it to be optimized out)
DrAzzy:
So it looks like the compiler isn't as smart as we might expect.... (this shocked me when I came across it too - I also expected it to be optimized out)
The compiler is probably smart enough to figure out you can't substitute bit shifting as division on signed ints I'm guessing
DrAzzy:
So it looks like the compiler isn't as smart as we might expect....
x = x >> 1;
000000c0 <loop>:
c0: 60 91 00 01 lds r22, 0x0100
c4: 70 91 01 01 lds r23, 0x0101
c8: 75 95 asr r23
ca: 67 95 ror r22
cc: 70 93 01 01 sts 0x0101, r23
d0: 60 93 00 01 sts 0x0100, r22
d4: 4a e0 ldi r20, 0x0A ; 10
d6: 50 e0 ldi r21, 0x00 ; 0
d8: 84 e2 ldi r24, 0x24 ; 36
da: 91 e0 ldi r25, 0x01 ; 1
dc: 0c 94 11 02 jmp 0x422 ; 0x422 <_ZN5Print7printlnEii>
x = x / 2;
000000c0 <loop>:
c0: 60 91 00 01 lds r22, 0x0100
c4: 70 91 01 01 lds r23, 0x0101
c8: 77 ff sbrs r23, 7
ca: 02 c0 rjmp .+4 ; 0xd0 <loop+0x10>
cc: 6f 5f subi r22, 0xFF ; 255
ce: 7f 4f sbci r23, 0xFF ; 255
d0: 75 95 asr r23
d2: 67 95 ror r22
d4: 70 93 01 01 sts 0x0101, r23
d8: 60 93 00 01 sts 0x0100, r22
dc: 4a e0 ldi r20, 0x0A ; 10
de: 50 e0 ldi r21, 0x00 ; 0
e0: 84 e2 ldi r24, 0x24 ; 36
e2: 91 e0 ldi r25, 0x01 ; 1
e4: 0c 94 15 02 jmp 0x42a ; 0x42a <_ZN5Print7printlnEii>