Hi, friends. Today (tonight) I am going to share my library that communicates with the Bosh BMP085 Temperature and Pressure Digital Sensor. This Library presupposes the use of I2C.h library from the XC8 compiler. The same library can be used with the XC16 compiler. There are a few comments in portuguese (I am too lazy to erase them
), but the functions are described in english. Functions for communication, temperature calculation and pressure are all working.
I hope you enjoy.
ps: My next post will present you a library to use de ADLX345 Accelerometer. It is almost finished.
Finzi
#include <plib/i2c.h>
#include <math.h>
//Barômetro e sensor de temperatura Digital
#define BMP085_ADDRESS_READ 0xEF
#define BMP085_ADDRESS_WRITE 0xEE
#define BMP085_CONTROL_RESGISTER 0xF4
#define BMP085_CONTROL_RESGISTER_DATA_TEMP 0x2E
#define BMP085_CONTROL_RESGISTER_DATA_PRESS 0x34
#define BMP085_RESULT_RESGISTER_MSB 0xF6
#define OVERSAMP_UL (unsigned char) 0 //Ultra low Power, tempo aquisiçào de 4.5ms, ruído de 0.5m
#define OVERSAMP_STD (unsigned char) 1 //Padrão, tempo aquisiçào de 7.5ms, ruído de 0.4m
#define OVERSAMP_HRES (unsigned char) 2 //Padrão, tempo aquisiçào de 13.5ms, ruído de 0.3m
#define OVERSAMP_UHRES (unsigned char) 3 //Padrão, tempo aquisiçào de 25,5ms, ruído de 0.25m
const char OSS = OVERSAMP_UHRES; //Define o modo de oversampling
#define _XTAL_FREQ 48000000
#define USE_OR_MASKS
//Variáveis globais de calibração usadas nos cálculos
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
//int mb;
int mc;
int md;
long b5;
void writeI2CByte(unsigned char addrDev)
{
char status;
//Escreve o endereço do Dispositivo
status = WriteI2C( addrDev);
//Verifica se houve algum problema
if(status == (char) -1) {
// data = SSPBUF; //limpa do buffer
SSPCON1bits.WCOL=0; //limpa o bit de colisão
}
}
long readNBytes_BMP085(unsigned char addr, char numBytes)
{
char res[3], div;
long ret = 0;
res[2] = 0; res[1] = 0; res[0] = 0;
//1. Iniciar o barramento i2C
StartI2C();
//1.1 Aguarda a condição de START estar concluída
while(SSPCON2bits.SEN);
//2. Lê qualquer informação inicialmente existente no buffer para limpar o BUFFER FULL status
// data = SSPBUF;
//3. Escreve o endereço do dispositivo e indica que será feita uma operação de escrita
writeI2CByte(BMP085_ADDRESS_WRITE); IdleI2C();
//4. Escreve o endereço do registro que será lido
writeI2CByte(addr); IdleI2C();
//5. Envia uma condição de RESTART para o BMP
RestartI2C();
//5.1 Aguarda a condição de RESTART estar concluída
while(SSPCON2bits.SEN);
//6. Escreve o endereço do dispositivo e indica que será feita uma operação de leitura
writeI2CByte(BMP085_ADDRESS_READ); IdleI2C();
//7. Executa a leitura de 2 bytes referentes ao dado da EEPROM no endereço fornecido
while(getsI2C(res,numBytes)); //garante que a leitura será feita
IdleI2C();
//8. Envia o fim de transação por meio de um NACK
NotAckI2C();
//8.1 Aguarda pelo conclusão do comando
while( SSPCON2bits.ACKEN!=0);
//9. Conclui a comunicação i2C
StopI2C();
//9.1 Aguarda a condição de STOP estar concluída
while(SSPCON2bits.SEN);
//10. Monta o dado inteiro. O MSB é retornado primeiro
if(numBytes == 2) div = 8; //Leitura de temperatura em apenas 2 bytes
else div = (8 - OSS); //Leitura de pressão
ret = ( ( ((long) res[0]) << 16) + (((long)res[1]) << 8) + ((long)res[2]) ) >> div ;
return(ret);
}
void getCalibrationData_BMP085()
{
ac1 = (int) readNBytes_BMP085(0xAA,2);
ac2 = (int) readNBytes_BMP085(0xAC,2);
ac3 = (int) readNBytes_BMP085(0xAE,2);
ac4 = (unsigned int) readNBytes_BMP085(0xB0,2);
ac5 = (unsigned int) readNBytes_BMP085(0xB2,2);
ac6 = (unsigned int) readNBytes_BMP085(0xB4,2);
b1 = (int) readNBytes_BMP085(0xB6,2);
b2 = (int) readNBytes_BMP085(0xB8,2);
// mb = (int) readNBytes_BMP085(0xBA,2);
mc = (int) readNBytes_BMP085(0xBC,2);
md = (int) readNBytes_BMP085(0xBE,2);
}
void sendStartConvCMD_BMP085(unsigned char cmd)
{
//1. Inicia comunicação i2C
StartI2C();
//1.1 Espera até que a condição de START esteja concluída
while (SSPCON2bits.SEN);
//2. Escreve o endereço do dispositivo e indica que será feita uma operação de escrita
writeI2CByte(BMP085_ADDRESS_WRITE); IdleI2C();
//3. Escreve o endereço do registro que receberá o comando de conversão da temperatura
writeI2CByte(BMP085_CONTROL_RESGISTER); IdleI2C();
//4. Escreve o conteúdo do registro indicando o tipo de conversão a ser iniciada
writeI2CByte(cmd); IdleI2C();
//5. Concluir a comunicação
StopI2C();
//5.1 Aguarda a condição de STOP estar concluída
while(SSPCON2bits.SEN);
}
long readUT_BMP085()
{
long ut;
sendStartConvCMD_BMP085(BMP085_CONTROL_RESGISTER_DATA_TEMP);
//2. Aguarda pelo tempo de conversão da temperatura
__delay_ms(5); //mínimo de 4.5ms
//3. Efetuar a leitura da temperatura no registrador MSB de resultados
ut = (long ) readNBytes_BMP085(BMP085_RESULT_RESGISTER_MSB, 2);
return(ut);
}
long calcTemperature_BMP085(long ut)
{
long x1, x2;
x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
x2 = ((long)mc << 11)/(x1 + md);
b5 = x1 + x2;
return ((b5 + 8L)>>4);
}
long readUP_BMP085()
{
long up;
//1. Envia o comando de conversão de pressão com base no que foi selecionado para o modo OSS
sendStartConvCMD_BMP085(BMP085_CONTROL_RESGISTER_DATA_PRESS + ((unsigned char)(OSS << 6)));
//2. Aguarda pelo tempo de conversão da pressão
switch(OSS)
{
case OVERSAMP_UL: __delay_ms(6); break;
case OVERSAMP_STD: __delay_ms(8); break;
case OVERSAMP_HRES: __delay_ms(15); break;
case OVERSAMP_UHRES: __delay_ms(14); __delay_ms(14); break;
}
//3. Efetuar a leitura da pressão no registrador MSB de resultados
if(OSS == 0)
up = readNBytes_BMP085(BMP085_RESULT_RESGISTER_MSB, 2);
else
up = readNBytes_BMP085(BMP085_RESULT_RESGISTER_MSB, 3);
return(up);
}
long calcPressure_BMP085(long up)
{
long x1, x2, x3, b3, b6, p;
unsigned long b4, b7;
b6 = b5 - 4000;
// Calculate B3
x1 = (b2 * (b6 * b6)>>12)>>11;
x2 = (ac2 * b6)>>11;
x3 = x1 + x2;
b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
// Calculate B4
x1 = (ac3 * b6)>>13;
x2 = (b1 * ((b6 * b6)>>12))>>16;
x3 = ((x1 + x2) + 2)>>2;
b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
b7 = ((unsigned long)(up - b3) * (50000>>OSS));
if (b7 < 0x80000000)
p = (b7<<1)/b4;
else
p = (b7/b4)<<1;
x1 = (p>>8) * (p>>8);
x1 = (x1 * 3038)>>16;
x2 = (-7357 * p)>>16;
p += (x1 + x2 + 3791)>>4;
return p;
}