Merhaba değerli forum sakinleri,
Stm32f4 discovery kartımla I2C protokolünü öğrenmek üzere projeler yapıyorum. Geçenlerde BMP180 basınç sensörünü kullanmaya çalıştım. Haberleşmemi bir yandan lojik analizörle dinliyor, iletişimde bir hata olup olmadığına bakıyorum. Yazdığım I2C kütüphanesi çalışıyor hiç bir hata yok veri doğru bir şekilde gidip geliyor fakat basınç değeri yanlış hesaplanıyor. Amacım basınç değerinden deniz seviyesine göre yükseklik bulmak. Yükseklik bulma formülü doğru çalışıyor ancak basınç değeri yanlış olduğu için doğru değil tabii. Aşağıya yazmış olduğum kodları atıyorum. I2C ve delay için kurduğum timer doğru çalıştığı için onların konfigurasyonunu atmayacağım.
main fonksiyonu bu şekilde:
int main(void){
CLK_Config();
GPIO_Config();
I2C1_Config();
TIM14_Config();
int16_t calib_data[11];
long temp_data;
long pressure_data;
long altitude;
bmp_get_calib(&calib_data);
bmp_calc(&calib_data, 3, &temp_data, &pressure_data, &altitude);
while (1)
{
}
}
Bmp180 C dosyası:
#include "Bmp180.h"
#include "math.h"
void bmp_get_calib(int16_t *data){
uint8_t calib_val[22];
multi_byte_read(bmp_addr, bmp_calib, &calib_val, 22);
int16_t AC1 = (calib_val[0]<<8) + calib_val[1];
int16_t AC2 = (calib_val[2]<<8) + calib_val[3];
int16_t AC3 = (calib_val[4]<<8) + calib_val[5];
int16_t AC4 = (calib_val[6]<<8) + calib_val[7];
int16_t AC5 = (calib_val[8]<<8) + calib_val[9];
int16_t AC6 = (calib_val[10]<<8) + calib_val[11];
int16_t B1 = (calib_val[12]<<8) + calib_val[13];
int16_t B2 = (calib_val[14]<<8) + calib_val[15];
int16_t MB = (calib_val[16]<<8) + calib_val[17];
int16_t MC = (calib_val[18]<<8) + calib_val[19];
int16_t MD = (calib_val[20]<<8) + calib_val[21];
data[0] = AC1;
data[1] = AC2;
data[2] = AC3;
data[3] = AC4;
data[4] = AC5;
data[5] = AC6;
data[6] = B1;
data[7] = B2;
data[8] = MB;
data[9] = MC;
data[10] = MD;
}
void bmp_calc(int16_t *calib_data, uint8_t oss, long *temp_data, long *pressure_data, long *altitude){
uint8_t raw_temp_data[2]; //raw temp data
uint8_t raw_pressure_data[3]; //raw pressure data
long pre_pressure_data;
float sea_level_press = 1013.25;
write_byte(bmp_addr, bmp_config, bmp_config_temp); //setup reading for temp
delay_us(5); //wait 4.5ms
multi_byte_read(bmp_addr, bmp_out_msb, &raw_temp_data, 2); //reading temp values
long UT = ((raw_temp_data[0]<<8) + raw_temp_data[1]); //converting UT val
switch (oss) { //switch case depended by over sampling settings
case 0:
write_byte(bmp_addr, bmp_config, bmp_config_pres0); //ultra low power mode and setup for pressure
delay_us(5);
break;
case 1:
write_byte(bmp_addr, bmp_config, bmp_config_pres1); //standard mode and setup for pressure
delay_us(8);
break;
case 2:
write_byte(bmp_addr, bmp_config, bmp_config_pres2); //high resolution mode and setup for pressure
delay_us(15);
break;
case 3:
write_byte(bmp_addr, bmp_config, bmp_config_pres3); //ultra high resolution mode and setup for pressure
delay_us(30);
break;
default:
while(1);
break;
}
multi_byte_read(bmp_addr, bmp_out_msb, &raw_pressure_data, 3); //reading raw pressure values
long UP = ((raw_pressure_data[0]<<16) + (raw_pressure_data[1]<<8) + (raw_pressure_data[2])) >> (8-oss); //converting raw to UP val
long X1 = (UT-(uint16_t)calib_data[5]) * (uint16_t)calib_data[4]/pow(2,15); //
long X2 = calib_data[9] * pow(2,11) / (X1 + calib_data[10]); // All 4 lines for calculating true temperature value
long B5 = X1 + X2; //
*temp_data = (B5 + 8) / pow(2,4); //
long B6 = B5 - 4000; //
X1 = (calib_data[7] * (B6 * B6 / pow(2,12))) / pow(2,11); //
X2 = calib_data[1] * B6 / pow(2,11); //
long X3 = X1 + X2; //
long B3 = (((calib_data[0] * 4 + X3) << oss) + 2) / 4; //
X1 = calib_data[2] * B6 / pow(2,13); //
X2 = (calib_data[6] * (B6 * B6 / pow(2,12))) / pow(2,16); //
X3 = ((X1 + X2) + 2) / pow(2,2); //
unsigned long B4 = (uint16_t)calib_data[3] * (unsigned long)(X3 + 32768) / pow(2,15); //
unsigned long B7 = ((unsigned long) UP - B3) * (50000 >> oss); // All those lines for calculating true pressure value
if(B7 < 0x80000000){ //
pre_pressure_data = (B7 * 2) / B4; //
} //
else{ //
pre_pressure_data = (B7 / B4) * 2; //
} //
X1 = (pre_pressure_data / pow(2,8)) * (pre_pressure_data / pow(2,8)); //
X1 = (X1 * 3038) / pow(2,16); //
X2 = (-7357 * pre_pressure_data) / pow(2,16); //
pre_pressure_data = pre_pressure_data + (X1 + X2 + 3791) / pow(2,4); //
*pressure_data = pre_pressure_data; //pressure in Pa
*altitude = 44330 * (1-pow(((pre_pressure_data/100) / sea_level_press),1 / 5.255));
}
Bmp180 H dosyası
#include "stm32f4xx.h"
#define bmp_addr 0xEE //Bmp180 device address without Read Bit
#define bmp_out_xlsb 0xF8 //This bit field using by 19 bit pressure measurement
#define bmp_out_lsb 0xF7 //This bit field using by temperature and pressure measurement
#define bmp_out_msb 0xF6 //This bit field using by temperature and pressure measurement
#define bmp_config 0xF4 //This bit field used for configure Bmp180
#define bmp_soft_rst 0xE0 //This bit field used for software reset to Bmp180 write to 0xB6
#define bmp_id 0xD0 //This bit field contains Bmp180 id
#define bmp_calib 0xAA //This bit field going until address reach 0xBF and contains calibration value
#define bmp_config_temp 0x2E
#define bmp_config_pres0 0x34
#define bmp_config_pres1 0x74
#define bmp_config_pres2 0xB4
#define bmp_config_pres3 0xF4
void bmp_get_calib(int16_t *data);
void bmp_calc(int16_t *calib_data, uint8_t oss, long *temp_data, long *pressure_data, long *altitude);
Bu resim ise ham sıcaklık ve basınç değerlerinin nasıl doğru değerlere çevrilmesi gerektiğini gösteriyor. Doğru basınç hesaplama son kutucukta anlatılıyor. Şimdiden herkese teşekkürler.
(https://i.ibb.co/qgjMXC6/BST-BMP180-DS000-09-Page15.png) (https://ibb.co/qgjMXC6)