Измерване на атмосферно налягане чрез Arduino и BMP085

BMP085 е сензор за измерване на атмосферно налягане. Може да се намери запоен върху брейкаут борд с два PullUp резистора от 4,7k и 0,1uF кондензатор. Платката има изходни пинове на разстояние 2.56mm, които я правят лесна за използване с платка бредборд. Сензорът се захранва с 1.8 до 3.6V постоянно напрежение и осъществява комуникация с микроконтролер по I2C.

Комуникацията се осъществява по линиите SDA и SCL и може да започне 10ms след захранване на сензора. Микроконтролерът трябва да изпълни условието START, като свали от HIGH (високо ниво) на LOW (ниско ниво) линията SDA, докато SCL е HIGH. След всеки 8 бита, сензорът отговаря със сигнал ACK и след последния такъв сигнал, микроконтролерът трябва да прекъсне комуникацията с условието STOP. То се изпълнява като линията SDA се вдигне от LOW на HIGH, докато SCL е HIGH.

Адресът на сензора е 1110111x, като последния бит е 1 за операция Read и 0 за операция Write.

Измерването започва след изпращането на адреса за операция Write, указател към регистъра с адрес 0xF4 и един байт с контролни данни. Тези данни могат да са следните:

  • 0x34 - измерва налягането с много ниска консумация (4.5ms)
  • 0x74 - стандартен режим на измерване (7.5ms)
  • 0xB4 - измерване с висока резолюция (13.5ms)
  • 0xF4 - измерване с много висока резолюция (25.5ms)

Различните режими на измерване имат времетраене от 4.5 до 25.5 ms.

За да получи резултатът от измерването, микроконтролерът трябва да изпрати адреса за операция Write и указател към регистър 0xF6. След ACK от сензора, микроконтролерът трябва да рестартира комуникацията и да изпрати адреса за операция Read. Сензорът връща 2 байта, като микроконтролерът трябва да потвърди първия с ACK, а втория с NAK и да прекъсне комуникацията със STOP.

Стойността на атмосферното налягане в паскали се изчислява чрез допълнителни кофиценти, които са записани в EEPROM паметта на сензора и могат да се прочетат от микроконтролер по I2C интерфейса. Коефицентите могат да се вземат и от дейташита на продукта:

Алгоритъмът за компенсация на стойността получена от сензора е следният:

UP е некомпенсираната стойност прочетена от сензора,а oss показва режима на измерване и може да приема стойностите:

  • oss = 0 - за минимална консумация
  • oss = 1 - стандартен режим
  • oss = 2 - измерване с висока резолюция
  • oss = 3 - много висока резолюция

Променливата p присвоява стойността на атмосферното налягане в Pa. За да се превърне в hPa трябва да се умножи по 0.01.

Пример

Даденият по-долу код осъществява комуникация със сензора по линии SDA и SCL. Arduino прочита стойността за атмосферното налягане, компенсира отклонението и по зададения алгоритъм и извежда я като hPa в Serial Monitor.

Vcc и GND пиновете на сензора се свързват съответно към 3.3V и GND, a SCL и SDA към А5 и А4.

За да се програмира Arduino с дадения по-долу код, трябва да се инсталира библиотека, написана от Peter Fleury. Файловете, които са необходими на Arduino могат да се изтеглят от тук. Библиотеката се разархивира в libraries от "arduino-00xx" директорията.

След като се инсталира библиотеката, кода който трябва да се зареди на Arduino е следният:

// библиотека за комуникация по I2C 
#include <i2cmaster.h> 

//// адрес, на който се открива BMP085 
int dev = 0xEE; // 11101110

//// коефиценти за калибриране на BMP085
short ac1 = 408;                  // AC1
short ac2 = -72;                  // AC2
short ac3 = -14383;               // AC3
unsigned short ac4 = 32741;       // AC4
unsigned short ac5 = 32757;       // AC5
unsigned short ac6 = 23153;       // AC6
short b1 = 6190;                  // B1
short b2 = 4;                     // B2
short mb = -32767;                // MB
short mc = -8711;                 // MC
short md = 2868;                  // MD

//// променливи за изчисляване на налягането
long  pval; // присвоява резултата 
long  x1, x2, x3, b3, b5, b6, p;
unsigned long  b4, b7;
short oss = 0; // режим на измерване

void setup() { // начални инициализации

  Serial.begin(9600);  // започва серийна комуникация с PC
  delay(10);  // изчаква 10ms за да се установи сензора
  i2c_init();  // започва комуникация по I2C шината  
}

void loop() { // програмен цикъл

  // изпълнява условието START ..
  // изпраща адреса на сензора с последен бит за операция "Write" ..
  // изчаква ACK от сензора
  i2c_start_wait(dev + I2C_WRITE); 
  // изпраща адреса на регистър 0x74 ..
  // изчаква ACK от сензора
  i2c_write(0xF4);   
  // изпраща контролони данни за измерване с ниска консумация(oss=0) ..
  // изчаква ACK от сензора
  i2c_write(0x34);    
  // прекъсва комуникацията  
  i2c_stop();  
  // изчаква да завърши измерването  
  delay(30);

  // изпълнява условието START ..
  // изпраща адреса на сензора с последен бит за операция "Write" ..
  // изчаква ACK от сензора
  i2c_start_wait(dev + I2C_WRITE); 
  // изпраща адреса на регистър 0xF6 ..
  // изчаква ACK от сензора
  i2c_write(0xF6);   
  // изпълнява условието START ..
  // изпраща адреса на сензора с последен бит за операция "Read" ..
  // изчаква ACK от сензора
  i2c_rep_start(dev + I2C_READ);   
  // прочита първия байт и го присвоява на променлива от тип long ..
  // връща ACK на сензора
  unsigned long up = i2c_readAck();         
  // прави байта старши за променливата
  up = up <<  8;           
  // прочита и присвоява втория байт като младши за променливата ..
  // връща NAK на сензора
  up |= i2c_readNak();     
  // прекъсва комуникацията   
  i2c_stop();         

//// изчислява налягането в Pa 	
  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((long ) ac1 * 4 + x3)<<oss + 2) >> 2;
  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);
  p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  pval = p + ((x1 + x2 + 3791) >> 4);

//// Извежда стойността в Serial Monitor 
  Serial.print("pressure = ");  
  Serial.print((float)pval/100); // превръща с-та в hPa 
  Serial.println(" hPa"); // мерна единица 

// закъснение от 2 сек.
  delay(2000); 
}

Share