본문 바로가기

라즈베리파이

라즈베리파이 BMP180 대기압 측정센서 C와 Python 코드

반응형


라즈베리파이 BMP180 대기압 측정센서 실습 : BMP180 : 고도센서, 기압센서, 온도센서 라즈베리파이 실습코드 

라즈베리파이 I2C 핀 사용법

이미지출처 : https://thepihut.com/blogs/raspberry-pi-tutorials/18025084-sensors-pressure-temperature-and-altitude-with-the-bmp180

라즈베리파이와 BMP180 대기압 측정센서 연결도 

라즈베리파이에서 $i2cdetect -y 1 명령으로 센서의 주소를 확인한다. 

파이선 코드와 C코드를 모두 아래에 나타내었다.

Python 코드는 아래를 참고한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#!/usr/bin/env python
 
import smbus
import time
 
MODE_ULTRALOWPOWER     = 0
MODE_STANDARD          = 1
MODE_HIGHRES           = 2
MODE_ULTRAHIGHRES      = 3
 
# BMP180의 레지스터
REGISTER_AC1 = 0xAA  
REGISTER_AC2 = 0xAC 
REGISTER_AC3 = 0xAE
REGISTER_AC4 = 0xB0
REGISTER_AC5 = 0xB2
REGISTER_AC6 = 0xB4
REGISTER_B1  = 0xB6
REGISTER_B2  = 0xB8
REGISTER_MB  = 0xBA
REGISTER_MC  = 0xBC
REGISTER_MD  = 0xBE
 
REGISTER_CONTROL           = 0xF4
REGISTER_TEMPDATA          = 0xF6
REGISTER_PRESSUREDATA      = 0xF6
 
COMMAND_READTEMP       = 0x2E
COMMAND_READPRESSURE   = 0x34
mode = MODE_STANDARD
 
# 보정 데이터 11개
AC1 = 0
AC2 = 0
AC3 = 0
AC4 = 0
AC5 = 0
AC6 = 0
B1 = 0
B2 = 0
MB = 0
MC = 0
MD = 0
 
#BMP180의 I2C 통신 주소
address = 0x77 
 
#레지스터에서 1바이트를 읽음
def read_byte(adr):
    return bus.read_byte_data(address, adr)
 
#레지스터에서 2바이트를 읽음
def read_word(adr):
    high = bus.read_byte_data(address, adr)
    low = bus.read_byte_data(address, adr+1)
    val = (high << 8+ low
    return val
 
#레지스터에서 2바이트를 읽은 후 보정함
def read_word_2c(adr):
    val = read_word(adr)
    if (val >= 0x8000):
        return -((65535 - val) + 1)
    else:
        return val
 
#레지스터에서 보정 데이터를 읽어서 저장해 둠
def init_Calibration_Data():
    global AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD
    AC1 = read_word_2c(REGISTER_AC1)
    AC2 = read_word_2c(REGISTER_AC2)
    AC3 = read_word_2c(REGISTER_AC3)
    AC4 = read_word_2c(REGISTER_AC4)
    AC5 = read_word_2c(REGISTER_AC5)
    AC6 = read_word_2c(REGISTER_AC6)
    B1 = read_word_2c(REGISTER_B1)
    B2 = read_word_2c(REGISTER_B2)
    MB = read_word_2c(REGISTER_MB)
    MC = read_word_2c(REGISTER_MC)
    MD = read_word_2c(REGISTER_MD)
    print "  AC1:", AC1,"  AC2:", AC2,"  AC3:", AC3,"  AC4:", AC4,"  AC5:", AC5,"  AC6:", AC6
    print "  B1:", B1,"  B2:", B2,"  MB:", MB,"  MC:", MC,"  MD:", MD
 
 
#BMP180에서 보정전 온도 데이터를 읽음
def read_raw_Temperature():
    bus.write_byte_data(address, REGISTER_CONTROL, COMMAND_READTEMP)
    time.sleep(0.0045)  # Sleep 4.5ms
    raw = read_word_2c(REGISTER_TEMPDATA)
    print "Raw Temperature: 0x%04X (%d)" % (raw & 0xFFFF, raw)
    return raw
 
#BMP180에서 보정전 기압 데이터를 읽음
def read_raw_Pressure():
    bus.write_byte_data(address, REGISTER_CONTROL, COMMAND_READPRESSURE + (mode << 6))
    time.sleep(0.03)  # Sleep 30ms
    msb = read_byte(REGISTER_PRESSUREDATA)
    lsb = read_byte(REGISTER_PRESSUREDATA + 1)
    nxt = read_byte(REGISTER_PRESSUREDATA + 2)
    raw = ((msb << 16+ (lsb << 8+ nxt) >> (8 - mode)
    print "Raw Pressure: 0x%04X (%d)" % (raw & 0xFFFF, raw)
    return raw
 
 
#온도를 보정함
def calibrate_Temp(raw):
    UT = 0
    X1 = 0
    X2 = 0
    B5 = 0
    temp = 0.0
    X1 = ((raw - AC6) * AC5) >> 15
    X2 = (MC << 11/ (X1 + MD)
    B5 = X1 + X2
    temp = ((B5 + 8>> 4/ 10.0
    print "Calibrated temperature = %f C" % temp
    return temp
 
 
#기압을 보정함
def calibrate_Pressure(raw):
    UT = 0
    UP = 0
    B3 = 0
    B5 = 0
    B6 = 0
    X1 = 0
    X2 = 0
    X3 = 0
    p = 0
    B4 = 0
    B7 = 0
 
    UT = read_raw_Temperature()
    UP = raw
 
    # True Temperature Calculations
    X1 = ((UT - AC6) * AC5) >> 15
    X2 = (MC << 11/ (X1 + MD)
    B5 = X1 + X2
 
    # Pressure Calculations
    B6 = B5 - 4000
    X1 = (B2 * (B6 * B6) >> 12>> 11
    X2 = (AC2 * B6) >> 11
    X3 = X1 + X2
    B3 = (((AC1 * 4 + X3) << mode) + 2/ 4
 
    X1 = (AC3 * B6) >> 13
    X2 = (B1 * ((B6 * B6) >> 12)) >> 16
    X3 = ((X1 + X2) + 2>> 2
    B4 = (AC4 * (X3 + 32768)) >> 15
    B7 = (UP - B3) * (50000 >> mode)
 
    if (B7 < 0x80000000):
        p = (B7 * 2/ B4
    else:
        p = (B7 / B4) * 2
 
    X1 = (p >> 8* (p >> 8)
    X1 = (X1 * 3038>> 16
    X2 = (-7357 * p) >> 16
 
    p = p + ((X1 + X2 + 3791>> 4)
    print "Pressure = ", p
    return p
 
#기압을 읽은 후 보정함
def read_Pressure():
    raw = read_raw_Pressure()
    p = calibrate_Pressure(raw)
    return p
 
#온도를 읽은 후 보정함
def read_Temperature():
    raw = read_raw_Temperature()
    t = calibrate_Temp(raw)
    return t
 
 
#고도를 구함. 해수면 대기압은 값이 주어지지 않으면 표준값 사용
def read_Altitude(seaLevelPressure=101325):
    altitude = 0.0
    pressure = float(read_Pressure())
    altitude = 44330.0 * (1.0 - pow(pressure / seaLevelPressure, 0.1903))
    print "Altitude = ",  altitude
    return altitude
 
# smbus 초기화 함수. Revision2에서는 파라미터 1을 사용
bus = smbus.SMBus(1)
 
init_Calibration_Data()
temp = read_Temperature()
pressure = read_Pressure()
altitude = read_Altitude()
 
print "======== Result ======="
print "Temperature : ", temp, " C"
print "Pressure = ", pressure, "(", pressure / 100" hPa)"
print "Altitude : ", altitude, " Meter"
 
 

C 코드는 아래를 참고한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#include <stdio.h>
#include <stdbool.h>
#include <signal.h>
#include <math.h>
#include <wiringPi.h>
 
#define MODE_ULTRALOWPOWER  0
#define MODE_STANDARD        1
#define MODE_HIGHRES        2
#define MODE_ULTRAHIGHRES    3 
 
// BMP180 Registers
#define REGISTER_AC1 0xAA  
#define REGISTER_AC2 0xAC 
#define REGISTER_AC3 0xAE
#define REGISTER_AC4 0xB0
#define REGISTER_AC5 0xB2
#define REGISTER_AC6 0xB4
#define REGISTER_B1  0xB6
#define REGISTER_B2  0xB8
#define REGISTER_MB  0xBA
#define REGISTER_MC  0xBC
#define REGISTER_MD  0xBE
 
#define REGISTER_CONTROL        0xF4
#define REGISTER_TEMPDATA        0xF6
#define REGISTER_PRESSUREDATA    0xF6
 
#define COMMAND_READTEMP        0x2E
#define COMMAND_READPRESSURE    0x34
 
int mode = MODE_STANDARD;
 
// Calibration data
int AC1 = 0;
int AC2 = 0;
int AC3 = 0;
int AC4 = 0;
int AC5 = 0;
int AC6 = 0;
int B1 = 0;
int B2 = 0;
int MB = 0;
int MC = 0;
int MD = 0;
 
int dID = 0x77;    // BMP180 device address
int fd = 0;    // i2c device handle
bool loop = true;
 
void my_ctrl_c_handler(int sig){ // can be called asynchronously
    close(fd);
    exit(0);
}
 
short read_word_2c(int addr)
{
    char low, high;
    short val;
    high = (char)wiringPiI2CReadReg8(fd, addr) ;
    low  = (char)wiringPiI2CReadReg8(fd, addr + 1) ;
    val = (high << 8+ low;
 
    if (val >= 0x8000)
        return -((65535 - val) + 1);
    else
        return val;
}
 
void init_Calibration_Data()
{
    AC1 = (int)read_word_2c(REGISTER_AC1);
    AC2 = (int)read_word_2c(REGISTER_AC2);
    AC3 = (int)read_word_2c(REGISTER_AC3);
    AC4 = (int)read_word_2c(REGISTER_AC4);
    AC5 = (int)read_word_2c(REGISTER_AC5);
    AC6 = (int)read_word_2c(REGISTER_AC6);
    B1 = (int)read_word_2c(REGISTER_B1);
    B2 = (int)read_word_2c(REGISTER_B2);
    MB = (int)read_word_2c(REGISTER_MB);
    MC = (int)read_word_2c(REGISTER_MC);
    MD = (int)read_word_2c(REGISTER_MD);
    printf ("  AC1:%d  AC2:%d  AC3:%d  AC4:%d  AC5:%d  AC6:%d \n", AC1, AC2, AC3, AC4, AC5, AC6);
    printf ("  B1:%d  B2:%d  MB:%d  MC:%d  MD:%d\n", B1,B2, MB, MC, MD);
}
 
int read_raw_Temperature()
{
    int raw;
    wiringPiI2CWriteReg8(fd, REGISTER_CONTROL, COMMAND_READTEMP);
    delay(5);  // Sleep 4.5ms
    raw = read_word_2c(REGISTER_TEMPDATA);
    printf ("Raw Temperature: 0x%04X (%d)\n" ,raw & 0xFFFF, raw);
    return raw;
}
 
int read_raw_Pressure()
{
    int msb, lsb, nxt;
    int raw;
    wiringPiI2CWriteReg8(fd, REGISTER_CONTROL, COMMAND_READPRESSURE + (mode << 6));
    delay(30);  // Sleep 30ms
    msb = (char)wiringPiI2CReadReg8(fd, REGISTER_PRESSUREDATA);
    lsb = (char)wiringPiI2CReadReg8(fd, REGISTER_PRESSUREDATA + 1);
    nxt = (char)wiringPiI2CReadReg8(fd, REGISTER_PRESSUREDATA + 2);
    raw = ((msb << 16+ (lsb << 8+ nxt) >> (8 - mode);
    printf"Raw Pressure: 0x%04X (%d)\n" , raw & 0xFFFF, raw);
    return raw ;
}
 
float calibrate_Temp(int raw)
{
    int UT = 0;
    int X1 = 0;
    int X2 = 0;
    int B5 = 0;
    float temp = 0.0;
    X1 = ((raw - AC6) * AC5) >> 15;
    X2 = (MC << 11/ (X1 + MD);
    B5 = X1 + X2;
    temp = ((B5 + 8>> 4/ 10.0;
    printf ("Calibrated temperature = %f C\n",  temp);
    return temp;
}
 
int calibrate_Pressure(int raw)
{
    int UT = 0;
    int UP = 0;
    int B3 = 0;
    int B5 = 0;
    int B6 = 0;
    int X1 = 0;
    int X2 = 0;
    int X3 = 0;
    int P = 0;
    int B4 = 0;
    int B7 = 0;
 
 
    UT = read_raw_Temperature();
    UP = raw;
 
    // True Temperature Calculations
    X1 = ((UT - AC6) * AC5) >> 15;
    X2 = (MC << 11/ (X1 + MD);
    B5 = X1 + X2;
 
    // Pressure Calculations
    B6 = B5 - 4000;
    X1 = (B2 * (B6 * B6) >> 12>> 11;
    X2 = (AC2 * B6) >> 11;
    X3 = X1 + X2;
    B3 = (((AC1 * 4 + X3) << mode) + 2/ 4;
 
    X1 = (AC3 * B6) >> 13;
    X2 = (B1 * ((B6 * B6) >> 12)) >> 16;
    X3 = ((X1 + X2) + 2>> 2;
    B4 = (AC4 * (X3 + 32768)) >> 15;
    B7 = (UP - B3) * (50000 >> mode);
 
    P = (B7 / B4) * 2;
 
    X1 = (P >> 8* (P >> 8);
    X1 = (X1 * 3038>> 16;
    X2 = (-7357 * P) >> 16;
 
    P = P + (float)((X1 + X2 + 3791>> 4);
 
    printf"Pressure = %f\n ", P);
    return P;
}
 
 
 
int read_Pressure()
{
    int raw;
    int p;
    raw = read_raw_Pressure();
    p = calibrate_Pressure(raw);
    return p;
}
 
float read_Temperature()
{
    int raw;
    float t;
    raw = read_raw_Temperature();
    t = calibrate_Temp(raw);
    return t;
}
 
 
float read_Altitude(int Level)
{
    float altitude = 0.0, pressure, seaLevelPressure;
    if(0 == Level) seaLevelPressure=101325.0;
    else seaLevelPressure = (float)Level;
    pressure = read_Pressure();
    altitude = 44330.0 * (1.0 - pow(pressure / seaLevelPressure, 0.1903));
    printf"Altitude = %f\n",  altitude);
    return altitude;
}
 
int main()
{
    float temp,  altitude;
    int pressure;
    signal(SIGINT, my_ctrl_c_handler);    //Ctrl + C Handler
    
    if((fd=wiringPiI2CSetup(dID))<0){
        printf("error opening i2c channel\n\r");
        return 0;
    }
    init_Calibration_Data();
    temp = read_Temperature();
    pressure = read_Pressure();
    altitude = read_Altitude(0);
    printf"======== Result =======\n");
    printf ("Temperature : %f C \n", temp);
    printf ("Pressure : %d Pa(%f hPa) \n", pressure, (float)pressure / 100.);
    printf ("Altitude : %f Meter \n", altitude);
    return 0;
}
 


반응형