행복한 하루

라즈베리파이 제로 프로젝트(15) – Pioneer600 모듈 (BMP280) 본문

RaspberryPi/Raspberry Pi Zero

라즈베리파이 제로 프로젝트(15) – Pioneer600 모듈 (BMP280)

변화의 물결 2021. 3. 7. 22:15

 

안녕하세요.

 

 이번에는 부착된 기압을 측정하는 센서를 이용해보도록 하겠습니다.

Pioneer600 소스상에는 BMP180도 있고 BMP280도 있습니다. 그러나 실제 장착된 것은 BMP280이므로 이 모듈로 확인해보겠습니다.

  (소스코드가 Pioneer600 제품에서만 동작되는 것이 아니라, I2C로 BMP280 모듈을 연결하면 사용할 수 있으니 소스코드를 참고하시면 조금이나마 도움되지 않을까 합니다.)  

1. 기압 센서 란

 - BMP180 센서 테스트하면서 찾은 자료가 있어 링크로 대신하겠습니다.

https://remnant24c.tistory.com/175

 

아두이노 나노를 이용한 GY-68(BMP180)기압/온도센서 테스트

안녕하세요. 이번에는 대기압 측정하는 BMP180 센서를 테스트해보았습니다. 사실 거리측정 센서를 통해서 높이를 측정 가능할 거라고 생각했는데 기압으로도 높이를 측정해서 고도로 표시된다고

remnant24c.tistory.com

 

2. BMP280 스펙

  - Pressure range 300 … 1100 hPa (equiv. to +9000…-500 m above/below sea level)

  - Package 8-pin LGA metal-lid Footprint : 2.0 × 2.5 mm², height: 0.95 mm

  - Relative accuracy ±0.12 hPa, equiv. to ±1 m (950 … 1050 hPa @25°C)

  - Absolute accuracy typ. ±1 hPa (950... 1050 hPa, 0...+40 °C)

  - Temperature coefficient offset 1.5 Pa/K, equiv. to 12.6 cm/K (25... 40°C @900hPa)

  - Digital interfaces I²C (up to 3.4 MHz) SPI (3 and 4 wire, up to 10 MHz)

  - Current consumption 2.7 µA @ 1 Hz sampling rate

  - Temperature range -40 … +85 °C

 

3. BMP180과 BMP280 차이

  - 아래의 표에서도 알 수 있듯이 BMP280이 사이즈도 작아지고, 정확도와 통신 지원하는 것도 향상되었다는 것을 알 수 있습니다.

< best-microcontroller-projects 참조>

 4. 회로도

  - I2C로 통신하도록 되어 있고 기본 주소는 0x76으로 되어 있습니다.

회로도

  - 핀 설명 (Pin Description)

Pin Description

 

 

 5. 연결하기

   - I2C 통신 장점 중 하나가 통신선만 연결하면 여러 모듈을 주소로 접근할 수 있다는 것입니다. 그래서 이전 내용과 같이 I2C로 핀으로 연결하면 됩니다.

 

  - 핀 배열이 동일하기 때문에 쉽게 연결할 수 있습니다. (1, 3, 5, 9)

 

핀 연결

  6. 소스 확인

  - 소스가 약간 복잡할 수 있는데, wiringPi 기준으로 크게 보면 bmp280.h 파일에 레지스터 주소를 선언해두었고, bmp280에 구현이 되어 있습니다.

 

  - bmp280.c 에는 I2C_readByte(), I2C_readU16(), I2C_readS16()  함수가 있는데 바이트 형태 8bit로 받을지 16bit(LSB, MSB) 구분해서 처리할지, 부호 있는 값인지에 따라서 구현이 되어 있습니다.

 

- load_calibration()  해더 파일에 정의된 주소로 보정 값들을 읽어 출력해줍니다.

 

- BSP_BMP280_Init()  bmp280 모드 등 초기 설정 값을 칩에다가 전달해줍니다. (모드 상세한 내용은 데이터 시트를 참조해야 합니다. 아래 첨부파일 참고)

 

- compensate_temperature(), compensate_pressure()   읽어 드린 ADC 온도와 기압 값에 보정 값을 넣어 계산 후 출력할 온도와 기압 값을 리턴해줍니다.

 

- 메인 함수에서 get_temperature_and_pressure() 함수에 포인터로 전달해서 값을 읽어와서 출력해줍니다.

#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <math.h>
#include "bmp280.h"

short dig_T2,dig_T3,dig_P2,dig_P3,dig_P4,dig_P5,dig_P6,dig_P7,dig_P8,dig_P9;
unsigned short dig_T1,dig_P1;
int t_fine;
int fd;

/******************* BMP280 Driver Interface *****************************/
char I2C_readByte(int reg)
{
        return (char)wiringPiI2CReadReg8(fd,reg);
}

unsigned short I2C_readU16(int reg)
{
        int MSB,LSB;
        LSB = I2C_readByte(reg);
        MSB = I2C_readByte(reg + 1);
        int value = (MSB << 8) +LSB;
        return (unsigned short)value;
}
short I2C_readS16(int reg)
{
        int result;
        result = I2C_readU16(reg);
        if (result > 32767)result -= 65536;
        return (short)result;
}
void I2C_writeByte(int reg,int val)
{
        wiringPiI2CWriteReg8(fd,reg,val);
}

/******************* BMP280 operation functions *****************************/
void load_calibration()
{
        /* read the temperature calibration parameters */
        dig_T1 = I2C_readU16(BMP280_DIG_T1_LSB_REG);
        dig_T2 = I2C_readS16(BMP280_DIG_T2_LSB_REG);
        dig_T3 = I2C_readS16(BMP280_DIG_T3_LSB_REG);

        /* read the pressure calibration parameters */
        dig_P1 = I2C_readU16(BMP280_DIG_P1_LSB_REG);
        dig_P2 = I2C_readS16(BMP280_DIG_P2_LSB_REG);
        dig_P3 = I2C_readS16(BMP280_DIG_P3_LSB_REG);
        dig_P4 = I2C_readS16(BMP280_DIG_P4_LSB_REG);
 		dig_P4 = I2C_readS16(BMP280_DIG_P4_LSB_REG);
        dig_P5 = I2C_readS16(BMP280_DIG_P5_LSB_REG);
        dig_P6 = I2C_readS16(BMP280_DIG_P6_LSB_REG);
        dig_P7 = I2C_readS16(BMP280_DIG_P7_LSB_REG);
        dig_P8 = I2C_readS16(BMP280_DIG_P8_LSB_REG);
        dig_P9 = I2C_readS16(BMP280_DIG_P9_LSB_REG);

        printf("dig_T1 = %d\r\n",dig_T1);
        printf("dig_T2 = %d\r\n",dig_T2);
        printf("dig_T3 = %d\r\n",dig_T3);
        printf("dig_P1 = %d\r\n",dig_P1);
        printf("dig_P2 = %d\r\n",dig_P2);
        printf("dig_P3 = %d\r\n",dig_P3);
        printf("dig_P4 = %d\r\n",dig_P4);
        printf("dig_P5 = %d\r\n",dig_P5);
        printf("dig_P6 = %d\r\n",dig_P6);
        printf("dig_P7 = %d\r\n",dig_P7);
        printf("dig_P8 = %d\r\n",dig_P8);
        printf("dig_P9 = %d\r\n",dig_P9);

}

unsigned char BSP_BMP280_Init(void)
{
        unsigned char id,ctrlmeas, config;

        id = I2C_readByte(BMP280_ID_REG);

        if(id == BMP280_ID_Value)
        {
                load_calibration();

                ctrlmeas = 0xFF; //BMP280_T_MODE_1 << 5 | BMP280_P_MODE_1 << 2 | BMP280_SLEEP_MODE;
                config = 0x14;   //BMP280_T_SB1 << 5 | BMP280_FILTER_MODE_1 << 2;

                I2C_writeByte(BMP280_CTRL_MEAS_REG, ctrlmeas);
                I2C_writeByte(BMP280_CONFIG_REG, config);

                return 0;
        }
        else
        {
                printf("Read BMP280 id error!\r\n");
                return 1;
        }
}
/* Returns pressure in Pa as double. Output value of "6386.2"equals 96386.2 Pa = 963.862 hPa */ 
void get_temperature_and_pressure(double *temperature, double *pressure)
{
        unsigned char lsb, msb, xlsb;
         int adc_P,adc_T;

        xlsb = I2C_readByte(BMP280_TEMP_XLSB_REG);
        lsb =  I2C_readByte(BMP280_TEMP_LSB_REG);
        msb =  I2C_readByte(BMP280_TEMP_MSB_REG);

        adc_T = (msb << 12) | (lsb << 4) | (xlsb >> 4);
        //adc_T = 415148;
        * temperature = compensate_temperature(adc_T);

        xlsb = I2C_readByte(BMP280_PRESS_XLSB_REG);
        lsb =  I2C_readByte(BMP280_PRESS_LSB_REG);
        msb =  I2C_readByte(BMP280_PRESS_MSB_REG);

        adc_P = (msb << 12) | (lsb << 4) | (xlsb >> 4);
        //adc_P = 51988;
        * pressure = compensate_pressure(adc_P);
}

int main(int argc,char **argv)
{
        double temp,press;
        printf("BMP180 Test Program ...\n");
        if(wiringPiSetup() < 0) return 1;
        fd = wiringPiI2CSetup(BMP280_I2C_ADDRESS);
        load_calibration();
        while(1)
        {
                get_temperature_and_pressure(&temp,&press);
                printf("Temperature = %.2f C Pressure = %.3f kPa \r\n",temp,press/1000);
                delay(1000);
        }
        return 0;
}

 

- BMP280.h

#ifndef _BMP280_
#define _BMP280_

//i2c address
#define BMP280_I2C_ADDRESS           0x76          //SDO = 0

//Registers  value
#define  BMP280_ID_Value             0x58
#define  BMP280_RESET_VALUE          0xB6

/* BMP280 Registers definition  */
#define BMP280_TEMP_XLSB_REG         0xFC                 /*Temperature XLSB Register */
#define BMP280_TEMP_LSB_REG          0xFB         /*Temperature LSB Register */
#define BMP280_TEMP_MSB_REG          0xFA         /*Temperature LSB Register */
#define BMP280_PRESS_XLSB_REG        0xF9                 /*Pressure XLSB  Register */
#define BMP280_PRESS_LSB_REG         0xF8                 /*Pressure LSB Register */
#define BMP280_PRESS_MSB_REG         0xF7                 /*Pressure MSB Register */
#define BMP280_CONFIG_REG            0xF5         /*Configuration Register */
#define BMP280_CTRL_MEAS_REG         0xF4         /*Ctrl Measure Register */
#define BMP280_STATUS_REG            0xF3         /*Status Register */
#define BMP280_RESET_REG             0xE0                 /*Softreset Register */
#define BMP280_ID_REG                0xD0         /*Chip ID Register */

/*calibration parameters */
#define BMP280_DIG_T1_LSB_REG        0x88
#define BMP280_DIG_T1_MSB_REG        0x89
#define BMP280_DIG_T2_LSB_REG        0x8A
#define BMP280_DIG_T2_MSB_REG        0x8B
#define BMP280_DIG_T3_LSB_REG        0x8C
#define BMP280_DIG_T3_MSB_REG        0x8D
#define BMP280_DIG_P1_LSB_REG        0x8E
#define BMP280_DIG_P1_MSB_REG        0x8F
#define BMP280_DIG_P2_LSB_REG        0x90
#define BMP280_DIG_P2_MSB_REG        0x91
#define BMP280_DIG_P3_LSB_REG        0x92
#define BMP280_DIG_P3_MSB_REG        0x93
#define BMP280_DIG_P4_LSB_REG        0x94
#define BMP280_DIG_P4_MSB_REG        0x95
#define BMP280_DIG_P5_LSB_REG        0x96
#define BMP280_DIG_P5_MSB_REG        0x97
#define BMP280_DIG_P6_LSB_REG        0x98
#define BMP280_DIG_P6_MSB_REG        0x99
#define BMP280_DIG_P7_LSB_REG        0x9A
#define BMP280_DIG_P7_MSB_REG        0x9B
#define BMP280_DIG_P8_LSB_REG        0x9C
#define BMP280_DIG_P8_MSB_REG        0x9D
#define BMP280_DIG_P9_LSB_REG        0x9E
#define BMP280_DIG_P9_MSB_REG        0x9F

#endif   

 

-Makefile  

bmp280:bmp280.c bmp280.h
        gcc -Wall bmp280.c -o bmp280 -lwiringPi -lm
clean:
        rm bmp280  

7. 실행결과

  - 컴파일해서 실행파일을 만듭니다.

pi@raspberrypi:~/Pioneer600/BMP280/wiringPi $ make clean && make

 

  - 프로그램을 실행합니다. 그러면 각종 보정값과 기압, 온도가 나옵니다.

pi@raspberrypi:~/Pioneer600/BMP280/wiringPi $ ./bmp280

 

실행 결과

 

  - 그런데 가지고 있는 모듈이 고장인지 값이 변하지 않았습니다. (당황);;;  그래서 지난번에 테스트한 BMP180 모듈을 가지고 확인해보았습니다.

 

  - BMP180 소스로 이동해서 소스 컴파일 후 실행해보았습니다.

BMP180 테스트

 

pi@raspberrypi:~/Pioneer600/BMP180/wiringPi $ make clean && make

pi@raspberrypi:~/Pioneer600/BMP180/wiringPi $ ./bmp180

 

BMP180 실행 결과

 

  - BMP180, BMP280 모듈을 좀 더 정확한 값으로 사용하려면 현재 측정하는 곳의 해발고도 혹은 해면기압 등을 넣어 추가 보정을 해주어야 합니다.

 

감사합니다.

 

 

<참조 사이트>

1. How to use the BMP280 Barometric Pressure Chip

https://www.best-microcontroller-projects.com/bmp280.html

2. Pioneer600

https://www.waveshare.com/wiki/Pioneer600  

 

BST-BMP280-DS001-11.pdf
1.42MB

 

 

"쿠팡 파트너스 활동을 통해 일정액의 수수료를 받을 수 있음"

Comments