Ir ao conteúdo

BMP180 pressão compensada CCS C PIC


Ir à solução Resolvido por test man*~,

Posts recomendados

Postado
Estou usando um BMP180 consigo ler a temperatura não compensada e também a pressão não compensada.

 

Consigo fazer a compensação da temperatura mas a da pressão (somente a da pressão) não está dando certo... Primeiro fiz um código como diz o Datasheet:

0PQ6Ys7.png

(usando divisão em vez de rotação).

 

Não funcionou então resolvi seguir o que o driver do site da bosch diz:


(usando >>15 para /2^15 por exemplo)

 

também não funcionou...

Desconfio que seja mal funcionamento do sensor, dados de calibração incorretos ou eu estou cometendo um erro no código (já refiz ele 3 vezes :()

 

Código (apenas a parte que faz compensação da pressão):




   /**** CALCULANDO A TEMPERATURA COMPENSADA ****/
   X1_S32 = (((signed int32) UT_U32 - (signed int32) AC6_U16_P) * (signed int32) AC5_U16_P) >> 15;
   X2_S32 = ((signed int32) MC_S16_P << 11) / (X1_S32 + MD_S16_P);
   
   B5_S32 = X1_S32 + X2_S32;
   
   T_COMP_S16 = ((B5_S32 + 8) >> 4);
   
   /**** CALCULANDO A PRESSÃO COMPENSADA ****/
   B6_S32 = B5_S32 - 4000;
   
   X1_S32 = (B6_S32 * B6_S32) / (signed int32)4096;//X1_S32 = (B6_S32 * B6_S32) >> 12;
   X1_S32 *= B2_S16_P; 
   X1_S32 /= (signed int32)2048;//X1_S32 >>= 11;
 
   X2_S32 = (AC3_S16_P * B6_S32);
   X2_S32 /= (signed int32) 2048;//X2_S32 >>= 11;
  
   X3_S32 = X1_S32 + X2_S32;
  
   B3_S32 = (((((signed int32)AC1_S16_P) * 4 + X3_S32) << OSS) + 2) / 4;//B3_S32 = (((((signed int32)AC1_S16_P) * 4 + X3_S32) << OSS) + 2) >> 2;
 
   X1_S32 = (AC3_S16_P * B6_S32) / (signed int32)8192;//X1_S32 = (AC3_S16_P * B6_S32) >> 13;
 
   X2_S32 = (B1_S16_P * ((B6_S32 * B6_S32) / (signed int32)4096)) / (signed int32)65536;//X2_S32 = (B1_S16_P * ((B6_S32 * B6_S32) >> 12)) >> 16;
 
   X3_S32 = ((X1_S32 + X2_S32) + 2) / 4;//X3_S32 = ((X1_S32 + X2_S32) + 2) >> 2;
  
   B4_U32 = (AC4_U16_P * (unsigned int32) (X3_S32 + 32768)) / (signed int32)32768;//B4_U32 = (AC4_U16_P * (unsigned int32) (X3_S32 + 32768)) >> 15;
 
   B7_U32 = ((unsigned int32)(UT_U32 - B3_S32) * (50000 >> OSS));
 
   if (B7_U32 < 0x80000000) { 
         P_COMP_S32 = (B7_U32 * 2) / B4_U32;//P_COMP_S32 = (B7_U32 << 1) / B4_U32;
   } 
 
      else {
         P_COMP_S32 = (B7_U32 / B4_U32) * 2;//P_COMP_S32 = (B7_U32 / B4_U32) << 1;
    }
 
 
   X1_S32 = P_COMP_S32 / (signed int32)256;//X1_S32 = P_COMP_S32 >> 8;
   X1_S32 *= X1_S32;
   X1_S32 = (X1_S32 * 3038) / (signed int32)65536;//X1_S32 = (X1_S32 * 3038) >> 16;
 
   X2_S32 = (P_COMP_S32 * -7357) / (signed int32)65536;//X2_S32 = (P_COMP_S32 * -7357) >> 16;
 
   /*pressure in Pa*/
   P_COMP_S32 += (X1_S32 + X2_S32 + (signed int32) 3791) / (signed int32)16;//P_COMP_S32 += (X1_S32 + X2_S32 + 3791) >> 4;



 

Pressão (P_COMP_S32) em PA (pressão muito baixa correspondendo a ~1670m 'acima do nível do mar' sendo que deveria ser ~920m)... A temperatura está ok 243 > 24,3°C: 

2NGazQ4.png

 

Dados de calibração:

DxjTm0h.png

 

Circuito:

Y0Jl4F2.jpg

-

dsZ0Nhj.jpg

 

O que vocês acham que pode ser?

  • Membro VIP
Postado

tá confuso (2me, may be 2you). Use os mesmos nomes do d.s. pra ver.

Rotacionar prum mc é mais fácil do que dividir

Postado
É está meio confuso, mas tentei colocar o máximo de informações... O BMP180 está olhando pra minha cara e rindo de min LOL  :mad:
 
Sim rotacionar é mais fácil... No começo fiz dividindo pois o datasheet diz e ainda tipo:
variavel_signed_int = -8 >> 2; // Não será igual a -2 por causa do complemento de 2, os bits que entram a esquerda são 0's
1111 1110 (-2)0111 1111 >>10011 1111 >>1 (63)

 

Os nomes estão iguais ao do driver e do datasheet... Só adicionei algumas coisas para indicar se a variavel é signed ou 
unsigned e o seu tamanho.
 
X1_S32 -> X1 SIGNED 32 bits o driver do site da bosch também faz isso...AC1_S16_P -> AC1_SIGNED 16 bits_DADO DE CALIBRAÇÃO
 
Pensando bem... Será que pode ser o compilador? Ontem fiz um teste convertendo a biblioteca da adafruit (lady ada <3), que é usada no Arduíno, e o problema não foi resolvido...

>>>> EDIT:
Bizarro demais...
Vou fazer o código no MikroC e ver se consigo fazer a compensação corretamente... Já vi algumas pessoas reclamarem do type cast (acho que é isso) do CCS, talvez esse é o problema...
Postado

@test man*~,

 

Que vergonha, ein ?????? kkkkkkk

 

O sensor está rindo por voce ter trocado o AVR pelo PIC kkkkk

 

Tá a fim de reinventar a roda ? :lol:

 

 

http://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=12914&highlight=bmp180

 

Olhe a maneira que o autor fêz  as contas .... é bem rudimentar, um passo de cada vez, mas fácil de entender....

 

Paulo

  • Curtir 2
Postado

O sensor está rindo por voce ter trocado o AVR pelo PIC kkkkk

 

HAHAHAHAHA  @aphawk Eu não troquei... Eu uso os dois, para cada coisa eu uso um (No meu coração há espaço para os dois HAHAHAAHAHA.)... Os próximos serão MPU6050 > HCM5883L > PCF8574+LCD > PCA9685. Ainda quero montar um braço com 6 DOF, uma plataforma autoestabilizada e um rastreador automotivo... Variarei entre um e outro...

Não subestime os PIC24F/dsPIC e os PIC32MX/MZ.

 

Olhe a maneira que o autor fêz  as contas .... é bem rudimentar, um passo de cada vez, mas fácil de entender....

 

O primeiro código que eu fiz estava assim, uma conta por linha... Quando peguei o driver no site da Bosch resolvi fazer igual para facilitar o Debug.

 

Tá a fim de reinventar a roda ? :lol:

 

KKKKKKKK  :D. Eu gosto de pegar o componente, ler o datasheet e fazer o meu próprio código. Pensa bem, você pega o componente monta o circuito, usa o código que outra pessoa fez, vê ele funcionando, pensa: "legal..." e acabou :huh: ... Meio sem graça HEHEHE! 

__________

 

Testei para ver se o código estava correto... Fiz os parâmetros de calibração, temperatura não compensada e pressão não compensada serem iguais ao exemplo do Datasheet (tirei o BMP180 do circuito).
 
Os resultados foram iguais aos do Datasheet (código escrito corretamente):
 
Dfyb244.png
 
UPhAvRa.png
 
8qzPAuy.png
 
A parte de medição de pressão do sensor está funcionando de forma incorreta :(. :lol:  
 
>>> EDIT:
Edit: Acho que no código postado acima 2 variaveis estão em um lugar incorreto, fui alterando para tentar resolver o problema e acabei com tantos códigos que até me perdi...
Postado

Faz alguns anos eu fiz um código pro BMP85, que é muito pareçido, e olha, achei um absurdo ter de fazer tanta conta prá ajustar o danado.

Os sensores mais atuais são muito mais "amigáveis" ..... mas infelizmente nenhum é tão parato quanto esse BMP180.

 

Mas tem algo que eu acho melhor avisar.... esse sensor é muito sensível á luz, o pessoal de aeromodelismo sempre recomenda cobrir ele para não ter medidas falsas, pois usam esse sensor para saber se o avião está subindo ou está descendo.... Particulamente eu não fiz esse teste mas sabem como é ....

 

Paulo

Postado

Putz aphawk, assim vai parecer que to te perseguindo né cara...rsrsrrs

Mas nao estou.

 

você poderia nos passar o codigo desse BMP085?? Peguei um codigo no forum da CCS mas to achando ele muito simples e queria dar uma olhada no seu.

 

E caso ja tenha trabalhado com: HMC5883L, MPU9250 e MMA7455L tambem to aceitando. 

To tentando trabalhar com todos esses sensores.

 

Att,

Ivan H.

Postado

aphawk, em 04 Set 2015 - 13:31, disse:snapback.png

Mas tem algo que eu acho melhor avisar.... esse sensor é muito sensível á luz, o pessoal de aeromodelismo sempre recomenda cobrir ele para não ter medidas falsas, pois usam esse sensor para saber se o avião está subindo ou está descendo.... Particulamente eu não fiz esse teste mas sabem como é ....

 

@aphawk Testei aqui mas não adiantou a diferença está muito grande agora, está lendo ~66440PA ~3421m sendo que deveria ser ~920m. Sei que a pressão no nível mar varia mas também não é para tanto HAHAHA...

 

@Ivan (eletronic) O código que eu fiz está pronto, só não posso confirmar que está tudo ok pois o meu BMP180 está lendo a pressão incorretamente (EU ACHO!!). Se você quiser eu te passo ele.

 

void main() {    int32 pressao;  float temperatura;  :  :  ler_dados_calibracao(); // <-- Lê os dados de calibração da EEPROM do BMP                          //     essa função deve ser usada uma única vez antes de                          //     ler a emperatura e pressao.    ler_temperatura_pressao_bmp180(temperatura, pressao, ULTRA_BAIXO_CONSUMO);   // a função acima Lê a temperatura e a  pressão  // com modo ultra baixo consumo  :  :}--------Os modos podem ser:ULTRA_BAIXO_CONSUMO  PADRAO              ALTA_RESOLUCAO       ULTRA_ALTA_RESOLUCAO
 
Até bom que você testa o código HEHEH!!!
Postado

@test man*~,

voce se lembrou de corrigir essa sua leitura para uma pressão EQUIVALENTE ao nível do mar ???????

Tem uma fórmula sobre isso, dá uma olhada no meu Tutorial, vai ver no código onde mostro o uso de um sensor desse tipo que depois da leitura tem de usar uma equação para obter o resultado no padrão internacional "ao nivel do mar" !

Ou use esta aqui :

http://keisan.casio.com/exec/system/1224575267

@Ivan (eletronic),

Baixe o meu tutorial no tópico destacado no topo desta página... Lá tem o código e tem também a correção para o nível do mar.

Paulo

Postado

@Ivan (eletronic),

Baixe o meu tutorial no tópico destacado no topo desta página... Lá tem o código e tem também a correção para o nível do mar.

Paulo

Cara não estou achando aqui esse tuto que comentou, o unico link que encontro abre uma pagina de um forum com dois posts vazios. Poderia enviar novamente pf?

O codigo que eu tenho hoje para o BMP085 é:

 

 

//************************************************ 
//  BMP085 Barometric Pressure Sensor 
// 
// 
//  - Written in CCS PCH C using floating point math 
//  - Several integer math versions of this driver exist but the speed improvement is 
//    not warranted in typical weather station type applications 
//  
//  - Based on a paper posted to thebackshed.com by DuinoMiteMegaAn 
// 
//  - Usage: 
//     Call once: bmp085Calibration(); 
//     P_mBar_float = BMP085Pressure(true);  //  calls for temperature first 
//     P_mBar_float = BMP085Pressure(false);  // skips temperature reading, assumes done previously 
//     T_Cent_float = BMP085Temperature(); 
//     t_reading = _Temp;  _Temp set on every temperature reading 
//        Note:   pressure reading is temp compensated so call for temp reading prior to pressure reading periodically or on each reading 
// 
//  Al Testani 
//  08/17/12 
//************************************************ 
 
// place a #use i2c statement in the main program and comment this out if not applicable 
#use i2c(master, sda=PIN_C4, scl=PIN_C3, FAST, FORCE_HW) 
 
#include <math.h> 
 
const int8 OVS_S = 3; // Oversampling Setting (0,1,2,3 from ultra low power, to ultra hi-resolution) 
 
#define BMP085_ADDRESS_W 0xEE        // I2C Write address of BMP085 
#define BMP085_ADDRESS_R 0xEF        // I2C Read address of BMP085
#define P_CORRECTION   1.5           // in mBars - factor to adjust for elevation to match local weather station pressure 
                                     // this value for 14' above sea level (in Boca Raton, Florida) 
 
 
// Calibration values 
signed int16 ac1; 
signed int16 ac2; 
signed int16 ac3; 
int16 ac4; 
int16 ac5; 
int16 ac6; 
signed int16 b1; 
signed int16 b2; 
signed int16 mb; 
signed int16 mc; 
signed int16 md; 
 
// floating point cal factors 
float _c3; 
float _c4; 
float _b1; 
float _c5; 
float _c6; 
float _mc; 
float _md; 
 
// polynomomial constants 
float _x0; 
float _x1; 
float _x2; 
float _y0; 
float _y1; 
float _y2; 
float _p0; 
float _p1; 
float _p2; 
 
float _s;     // T-25, used in pressure calculation - must run temperature reading before pressure reading 
float _Temp;  // set after every temperature or temperature/pressure reading 
 
 
int8 BMP085_Read_Byte(int8 add) 
   { 
   int8 data; 
   
   i2c_start(); 
   i2c_write(BMP085_ADDRESS_W); 
   i2c_write(add); 
   i2c_start(); 
   i2c_write(BMP085_ADDRESS_R); 
   data=i2c_read(0); 
   i2c_stop(); 
   return(data); 
   } 
 
int16 BMP085_Read_Int(int8 add) 
   { 
   int8 msb, lsb; 
   int16 retval; 
   
   i2c_start(); 
   i2c_write(BMP085_ADDRESS_W); 
   i2c_write(add); 
   i2c_start(); 
   i2c_write(BMP085_ADDRESS_R); 
   msb = i2c_read(); 
   lsb = i2c_read(0); 
   i2c_stop(); 
   retval = make16(msb, lsb); 
   return (retval); 
   } 
   
void BMP085_Write_Byte(int8 add, int8 data) 
   { 
      i2c_start(); 
      i2c_write(BMP085_ADDRESS_W); 
      i2c_write(add); 
      i2c_write(data); 
      i2c_stop(); 
   } 
   
void bmp085Calibration() 
   { 
      // read BMP085 EEPROM cal factors 
      ac1 = BMP085_Read_Int(0xAA); 
      ac2 = BMP085_Read_Int(0xAC); 
      ac3 = BMP085_Read_Int(0xAE); 
      ac4 = BMP085_Read_Int(0xB0); 
      ac5 = BMP085_Read_Int(0xB2); 
      ac6 = BMP085_Read_Int(0xB4); 
      b1  = BMP085_Read_Int(0xB6); 
      b2  = BMP085_Read_Int(0xB8); 
      mb  = BMP085_Read_Int(0xBA); 
      mc  = BMP085_Read_Int(0xBC); 
      md  = BMP085_Read_Int(0xBE); 
   
       // calculate floating point cal factors 
      _c3 = 0.0048828125 * ac3;            // 160 * pow2(-15) * ac3; 
      _c4 = 0.000000030517578125 * ac4;    // 1E-3 * pow2(-15) * ac4; 
      _c5 = 0.00000019073486328125 * ac5;  // (pow2(-15)/160) * ac5; 
      _c6 = (float)ac6; 
      _b1 = 0.00002384185791015625 * b1;   // 25600 * pow2(-30) * b1; 
      _mc = 0.08 * mc;                     // (pow2(11) / 25600) * mc; 
      _md = (float)md / 160; 
       
      // calculate polynomial constants 
      _x0 = (float)ac1; 
      _x1 = 0.01953125 * ac2;             // 160 * pow2(-13) * ac2; 
      _x2 = 0.000762939453125 * b2;       // 25600 * pow2(-25) * b2; 
      _y0 = _c4 * 32768;                  //_c4 * pow2(15); 
      _y1 = _c4 * _c3; 
      _y2 = _c4 * _b1; 
      _p0 = 2.364375;  
      _p1 = 0.992984; 
      _p2 = 0.000004421;    
   } 
 
// Read the uncompensated temperature value 
int16 BMP085ReadUT() 
   { 
   int16 ut; 
     
     // Write 0x2E into Register 0xF4 
     BMP085WriteByte(0xF4, 0x2E); 
     delay_ms(5); // Wait at least 4.5ms 
     // Read two bytes from registers 0xF6 and 0xF7 
     ut = BMP085ReadInt(0xF6); 
     return((float)ut); 
   } 
 
// Read the uncompensated pressure value 
int32 bmp085ReadUP() 
   { 
   int8 msb, lsb, xlsb; 
   float p; 
     
     // Write 0x34+(OSS<<6) into register 0xF4 
     // Request a pressure reading w/ oversampling setting 
     BMP085WriteByte(0xF4, (0x34 + (OVS_S<<6)) ); 
     
     // Wait for conversion, delay time dependent on OSS 
     switch (OVS_S) 
     { 
        case 0: delay_ms(5);  break; 
        case 1: delay_ms(8);  break; 
        case 2: delay_ms(14); break; 
        case 3: delay_ms(26); break; 
     }    
     
     // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB) 
      msb  = BMP085ReadByte(0xF6); 
      lsb  = BMP085ReadByte(0xF7); 
      xlsb = BMP085ReadByte(0xF8); 
      p = (256*msb) + lsb + (xlsb/256); 
      return(p); 
   } 
   
float BMP085GetTemp(float _tu) 
   { 
   float alpha, T; 
   
      alpha = _c5 * (_tu - _c6); 
      T = alpha + (_mc/(alpha + _md)); 
      _s = T - 25; 
      return(T); 
   }    
 
float BMP085GetPressure(float _pu) 
   { 
   float x, y, z; 
   float P; 
   
      x = _x2*_s*_s + _x1*_s + _x0; 
      y = _y2*_s*_s + _y1*_s + _y0; 
      z = ((float)_pu - x) / y; 
      P = _p2*z*z + _p1*z + _p0; 
      P += P_CORRECTION; 
      return(P); 
   } 
 
float BMP085Pressure(boolean getTemp) 
   { 
      if (getTemp) 
         _Temp = BMP085GetTemp(BMP085ReadUT());  // creates _s required for pressure calculation 
      return(BMP085GetPressure(BMP085ReadUP())); 
   } 
 
float BMP085Temperature(void) 
    { 
      _Temp = BMP085GetTemp(BMP085ReadUT()); 
      return(_Temp); 
   } 
[spoiler/]
 
Mas não sei to suspeitando um pouco desses calculos 
 
Ps: se alguem puer me lembrar como usa aquele comando spoiler pra "fechar" o codigo postado agradeço.
  • Solução
Postado

você se lembrou de corrigir essa sua leitura para uma pressão EQUIVALENTE ao nível do mar ???????

Tem uma fórmula sobre isso, dá uma olhada no meu Tutorial, vai ver no código onde mostro o uso de um sensor desse tipo que depois da leitura tem de usar uma equação para obter o resultado no padrão internacional "ao nivel do mar" !

 

 

@aphawk, a compensação é feita dentro da função: 

"ler_temperatura_pressao_bmp180();"
Voltei ao seu tutorial e vi que você usa variáveis float, cliquei no link que você indica e vi o arquivo ensinado a usar as variáveis float, o Interessante foi que eu estava procurando por algo assim e não tinha encontrado, você acabou tirando uma dúvida sem eu perguntar.
 
Usando variáveis float a pressão lida vai para ~91524PA o que é ~890m (Pressão at sea level = 115700)... Até que ficou legal mas não perfeito...
 
Vou deixar isso por aqui mesmo e partir para o próximo... É como você disse em um post anterior, seria bacana se o sensor fizesse a compensação internamente e entregasse a variável já no jeito... Mas pelo menos ele é barato :) .
 
Vou ver se uso o módulo bússola agora (polos magnéticos/geométricos, declinação magnética  ^_^ ), vou esperar o 2560 chegar! Tomara que dessa vez não dê fronho!
 
Não está resolvido por completo mas fazer o quê? HEHE!
  • Curtir 1
Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!