LinkedIn YouTube Facebook
Szukaj

Wstecz
Artykuły

BME280 – czujnik temperatury, wilgotności oraz ciśnienia (część 2)

Proces odczytywania danych z sensora

Kompletny proces odczytywania danych z sensora można podzielić na kilka etapów:

  • Odczytanie danych kalibracji. Można to zrobić jednorazowo na początku programu.
  • Odczytanie danych z rejestrów sensora BME280 za pomocą funkcji BME280_read_PTH.
  • Złożenie danych o odpowiedniej długości z bajtów odczytanych z rejestrów.
  • Obliczenie kompensacji wyników za pomocą specjalnych funkcji wykorzystujących dane kalibracji.

Do składania słowa pomiaru z 8-bitowych danych odczytanych z rejestrów służy funkcja BME280_assembleRawValue pokazana na listingu 10. Funkcja składa 16-bitową wartość z dwu pierwszych bajtów bufora p_data i jeżeli argument has_xlsb jest równy 1 to 16-bitowa wartość jest dodatkowo rozszerzana do 20-bitowej o 4 bity z trzeciego bajtu.

Listing 10. Funkcja składająca daną wielobitową z danych 8-bitowych

uint32_t BME280_assembleRawValue(uint8_t *p_data, uint8_t has_xlsb)
{
  uint32_t value = p_data[0];
  value <<= 8;
  value |= p_data[1];
  if (has_xlsb!=0)
  {
    value <<= 4;
    value |= (p_data[2]>>4);
  }
  return (int32_t) value;
}

Kompletna funkcja BME280_read odczytująca wyniki pomiarów z sensora, a także wyliczania dane z uwzględnieniem kalibracji została pokazana na listingu 11.

Listing 11. Funkcja odczytania i wyliczenia kompensacji pomiarów

/*************************************
 * odczytanie rejestrów wszystkich pomiarów
 * 8 bajtów od adresu BME280_MEASUREMENT_REGISTER = 0xB7
 * obliczenie kompensacji pomiarów na podstawie odczytanych danych kompensacji
 */
void BME280_read(void)
{

  // odczytanie wszystkich pomiarów w jednym cyklu
  uint8_t data[BME280_MEASUREMENT_SIZE];
  BME280_read_PTH(BME280_MEASUREMENT_REGISTER,BME280_MEASUREMENT_SIZE,data);

 
  // składanie pomiarów 
  int32_t p = BME280_assembleRawValue(&data[0],1);
  int32_t t = BME280_assembleRawValue(&data[3],1);
  int32_t h = BME280_assembleRawValue(&data[6],0);

   //kompensacja pomiarów

  _temperature = BME280compensateTemperature(t); // wyliczanie temperatury w pierwszej kolejności 
  _pressure = BME280compensatePressure(p); // Uzycie wyliczonej temperatury do kompencacji cisnienia
  _humidity = BME280compensateHumidity(h); // Uzycie wyliczonej temperatury do kompencacji wilgotnosci


}

Funkcje kompensacji pomiaru

Wyliczanie kompensacji pomiarów należy rozpocząć od temperatury, bo ten pomiar używa się do kompensowania pozostałych dwóch pomiarów: ciśnienia i wilgotności. W tym przypadku wartość temperatury używanej do kompensacji jest zapisywana w zmiennej globalnej _t_fine

Producent sensora podaje w swoich danych technicznych jak należy wyliczać pomiary na podstawie danych kalibracyjnych i mocno sugeruje żeby stosować gotowe procedury przygotowane przez BOSCH Sensortec. Firmowe procedury pokazano na listingach 12, 13 i 14.

Kompensacja pomiaru temperatury

Listing 12. Kompensacja pomiaru temperatury

//kompensacja temperatury
temperature_t BME280compensateTemperature(int32_t adc_T)
{
  double v_x1_u32;
  double v_x2_u32;
  double temperature;

  v_x1_u32  = (((double)adc_T) / 16384.0 - ((double)_dig_T1) / 1024.0) * ((double)_dig_T2);
  v_x2_u32  = ((((double)adc_T) / 131072.0 - ((double)_dig_T1) / 8192.0) * (((double)adc_T) / 131072.0 - ((double)_dig_T1) / 8192.0)) * ((double)_dig_T3);
//_t_fine temperatura do kompensacji pozostałych pomiarów
  _t_fine = (int32_t)(v_x1_u32 + v_x2_u32);
  temperature  = (v_x1_u32 + v_x2_u32) / 5120.0;
  return temperature;
}
Kompensacja pomiaru ciśnienia

Listing 13. Kompensacja pomiaru ciśnienia

//kompensacja cisnienia
pressure_t BME280compensatePressure(int32_t adc_P)
{
  double v_x1_u32;
  double v_x2_u32;
  double pressure;

  v_x1_u32 = ((double)_t_fine / 2.0) - 64000.0;
  v_x2_u32 = v_x1_u32 * v_x1_u32 * ((double)_dig_P6) / 32768.0;
  v_x2_u32 = v_x2_u32 + v_x1_u32 * ((double)_dig_P5) * 2.0;
  v_x2_u32 = (v_x2_u32 / 4.0) + (((double)_dig_P4) * 65536.0);
  v_x1_u32 = (((double)_dig_P3) * v_x1_u32 * v_x1_u32 / 524288.0 + ((double)_dig_P2) * v_x1_u32) / 524288.0;
  v_x1_u32 = (1.0 + v_x1_u32 / 32768.0) * ((double)_dig_P1);
  pressure = 1048576.0 - (double)adc_P;
  // Avoid exception caused by division by zero.
  if (v_x1_u32 != 0) pressure = (pressure - (v_x2_u32 / 4096.0)) * 6250.0 / v_x1_u32;
  else return 0;
  v_x1_u32 = ((double)_dig_P9) * pressure * pressure / 2147483648.0;
  v_x2_u32 = pressure * ((double)_dig_P8) / 32768.0;
  pressure = pressure + (v_x1_u32 + v_x2_u32 + ((double)_dig_P7)) / 16.0;

  return pressure;
}
Kompensacja pomiaru wilgotności

Listing 14. Kompensacja pomiaru wilgotności

//kompensacja wilgotnosci
humidity_t BME280compensateHumidity(int32_t adc_H)
{
  double var_h;

  var_h = (((double)_t_fine) - 76800.0);
  if (var_h != 0)
  {
    var_h = (adc_H - (((double)_dig_H4) * 64.0 + ((double)_dig_H5) / 16384.0 * var_h)) *
      (((double)_dig_H2) / 65536.0 * (1.0 + ((double) _dig_H6) / 67108864.0 *
      var_h * (1.0 + ((double)_dig_H3) / 67108864.0 * var_h)));
  }
  else return 0;
  var_h = var_h * (1.0 - ((double)_dig_H1)*var_h / 524288.0);
  if (var_h > 100.0) var_h = 100.0;
  else if (var_h < 0.0) var_h = 0.0;
  return var_h;
}

Inicjalizacja czujnika BME280

Użycie funkcji obsługi sensora BME280 należy poprzedzić wywołaniem funkcji BME280_int, która zeruje zmienne wyniku temperatury, ciśnienia i wilgotności, otwiera interfejs I2C, zeruje zmienne z danymi kalibracji, odczytuje dane kalibracji, a także programuje rejestr konfiguracji o adresie 0xF5 pokazany na rysunku 9 – listing 15.

Listing 15. Inicjalizacja obsługi sensora BME280

uint8_t BME280_init(void)
{
   ssp_err_t status;
  _temperature = 0;
  _pressure = 0;
  _humidity = 0;
  _t_fine = 0;
  Err = 0;
  status=BME280_BUS_Open();//otwarcie magistrali I2C
  //blad otwarcia magistrali
     if(status != SSP_SUCCESS)
         return (0xFF);

  //zerowanie zmiennych kalibracji
  BME280_clearCalibrationData();
  //odczytanie danych kalibracji
  BME280_readCalibrationData();
  
  BME280_writeConfigRegister(BME280_STANDBY_500_US,BME280_FILTER_OFF,0);                 
  return(Err);

}

Pomiary w trybie Forced

Dla przykładowego pomiaru ciśnienia, wilgotności i temperatury w stacji pogodowej wykorzystamy tryb Forced. W związku z tym dane dotyczące czasu stanu Standby dla trybu NORMAL nie będą miały znaczenia. Wyłączymy filtr IIR, natomiast bit programujący ilość linii interfejsu SPI wyzerujemy (dla I2C nie ma znaczenia).

Pomiar w trybie Forced wymaga za każdym razem wyzwolenia przez wpisanie do rejestru Control (adres 0xF4) trybu Forced (rysunek 10). Ponieważ nie można zaprogramować tylko bitów trybu pracy, to trzeba wpisać do rejestru Control wszystkie dane sterujące pracą sensora. Dla pomiarów do celów pogodowych nie jest konieczna duża dokładność, a więc dla wszystkich czujników nadpróbkowanie wyłączamy (ustawiamy na wartość x1). Na listingu 16 zaprezentowano prostą nieskończoną pętlę pomiarowa, która:

  • Wyzwala pomiar przez wpisanie trybu Forced do rejestru sterującego,
  • Odczytuje wszystkie pomiary, a także wylicza kompensacje,
  • Wyświetla wszystkie trzy pomiary,
  • Odlicza opóźnienie 10 sekund.

Listing 16. Pętla wykonująca pomiary

while(1){
                 BME280_writeControlRegisters(BME280_OVERSAMPLING_1X,BME280_OVERSAMPLING_1X,BME280_OVERSAMPLING_1X,BME280_MODE_FORCED);
                 R_BSP_SoftwareDelay(BSP_DELAY_UNITS_MILLISECONDS, 100);
                 BME280_read();
                 BME280_disp_T();
                 BME280_disp_H ();
                 BME280_disp_P();
                 R_BSP_SoftwareDelay(BSP_DELAY_UNITS_MILLISECONDS, 10000);
}
Funkcje zapisujące rejestry

Na listingach 17 i 18 zaprezentowano funkcje zapisu rejestrów konfiguracji, a także rejestru kontrolnego.

Listing 17. Zapisanie rejestru Config

ssp_err_t BME280_writeConfigRegister(uint8_t t_sb, uint8_t filter, uint8_t spi)
 {
   ssp_err_t status;
   uint8_t data[2];
   data[0] = BME280_CONFIG_REGISTER;
   data[1] = ((t_sb&0x07)<<5) | ((filter&0x07)<<2) | (spi&0x01);


        status = BME280_I2C_Write(data,2,false);
        return (status);

 }

Listing 18. Zapisanie rejestru sterującego

ssp_err_t BME280_writeControlRegisters(uint8_t osrs_t, uint8_t osrs_p, uint8_t osrs_h, uint8_t mode)
 {
   ssp_err_t status;
   uint8_t data[2];
   data[0] = BME280_CTRL_HUM_REGISTER;
   data[1] = (osrs_h&0x07);

      status = BME280_I2C_Write(data,2,false);
      if(status != SSP_SUCCESS)
          return(status);
 
   data[0] = BME280_CTRL_MEAS_REGISTER;
   data[1] = ((osrs_t&0x07)<<5) | ((osrs_p&0x07)<<2) | (mode&0x03);

   status = BME280_I2C_Write(data,2,false);
       return(status);

 }

Program testowy wyświetla zmierzone wartości na wyświetlaczu dołączonym do płytki ewaluacyjnej. Pokazano to na rysunku 27.

Rysunek 27. Wyświetlanie pomiarów z czujnika BME280

Umieszczenie sensora BME280 na płytce ewaluacyjnej ma jedną wadę. Mierzona temperatura przewyższa temperaturę otoczenia, bo obok są źródła ciepła: mikrokontroler, układ debuggera, wyświetlacz z układem podświetlenia, stabilizatory układu zasilania itd. W przypadku mojej płytki z wyświetlaczem mierzona temperatura jest o ok. 4°C wyższa od temperatury otoczenia. W praktycznych realizacjach należałoby odsunąć sensor od płytki, a najlepiej umieścić go poza obudową, w pewnej odległości.

Kalibracja wyniku pomiaru ciśnienia

Wynik pomiaru ciśnienia jest podawany w Pascalach. Żeby go wyświetlać w hPa należy podzielić wynik przez 100. Wartość ciśnienia podawana jest wartościach bezwzględnych. Żeby miało wartość odnoszoną do poziomu morza, trzeba go skorygować. Ciśnienie rośnie na małych wysokościach do 1000 m w dużym przybliżeniu o około 11 Pa na każdy metr wysokości. W rzeczywistości ta zależność jest wykładnicza Jeżeli znamy wysokość pomiaru nad poziomem morza (h), to do zmierzonej wartości trzeba dodać 11*h.

Czujnik BME280 można znaleźć w sklepie Kamami.pl. Oferta obejmuje również moduły z zamontowanym sensorem.
Absolwent Wydziału Elektroniki Politechniki Wrocławskiej, współpracownik miesięcznika Elektronika Praktyczna, autor książek o mikrokontrolerach Microchip i wyświetlaczach graficznych, wydanych nakładem Wydawnictwa BTC. Zawodowo zajmuje się projektowaniem zaawansowanych systemów mikroprocesorowych.