Bootstrap

物联网开发129 - Micropython ESP32 C3连接BMP180压力传感器模块

一、目的

        这一节我们来学习如何使用合宙ESP32 C3,连接BMP180压力传感器模块,使用ST7735屏幕进行显示。下面我们一起来学习一下吧!

        前面我们学习了BMP280压力传感器模块,大家先看一下这个文章,我们在这个的基础上再来学习BMP180。

物联网开发124 - Micropython ESP32 C3连接AHT20温湿度传感器和BMP280压力传感器模块_esp32 bmp280-CSDN博客文章浏览阅读1.5k次。使用合宙ESP32 C3,连接AHT20温湿和BMP280压力传感器模块,使用ST7735屏幕进行显示_esp32 bmp280https://blog.csdn.net/zhusongziye/article/details/132634685?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522172085301216800213014023%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=172085301216800213014023&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-132634685-null-null.nonecase&utm_term=280&spm=1018.2226.3001.4450

二、环境

        ESP32 C3开发板(MicroPython v1.19.1 on 2022-06-18)+ BMP180压力传感器模块 + BMP280压力传感器模块 + TFT ST7735屏幕 + 几根杜邦线 + Win10商业版

        ESP32 C3和各模块接线方法:

ESP32 C3连接ST7735屏幕的方法,请参考物联网开发124这个文章。

        BMP180和BMP280接线如下:

模块介绍:

1百帕(hpa)=100帕斯卡(pa),h就是hundred的意思,就是100,所以1h=100,即1hpa等于100pa。百帕是一个气压单位。世界气象组织决定,今后气压单位既可用“百帕”,也可用“毫巴”,两者暂时并用,最后逐步统一使用“百帕”。简写符号hPa,即为100个帕,正好与1毫巴相等。按国际标准组织规定:1帕=1牛顿/平方米,标准大气压=760mm汞柱=76cm汞柱=1.01325×10^5Pa=10.336m水柱。


标准大气压值的规定,是随着科学技术的发展,经过几次变化的。最初规定在摄氏温度0℃、纬度45°、晴天时海平面上的大气压强为标准大气压,其值大约相当于760mm汞柱高。后来发现,在这个条件下的大气压强值并不稳定,它受风力、温度等条件的影响而变化。于是就规定760mm汞柱高为标准大气压值。但是后来又发现760mm汞柱高的压强值也是不稳定的,汞的密度大小受温度的影响而发生变化;g值也随纬度而变化,为了确保标准大气压是一个定值,1954年第十届国际计量大会决议声明,规定标准大气压值为,1标准大气压=101325 N/㎡。

三、bmp180驱动

'''
bmp180 is a micropython module for the Bosch BMP180 sensor. It measures
temperature as well as pressure, with a high enough resolution to calculate
altitude.
'''
from ustruct import unpack as unp
from machine import I2C, Pin
import math
import time

# BMP180 class
class BMP180():
    
    #Init i2c:协议 addr:bmp地址 oversample:过采样设置0-3 Baseline:海拔基线 默认101325
    def __init__(self, i2c, addr, oversample, Baseline):

        # create i2c obect
        self._bmp_i2c = i2c
        self._bmp_addr = addr
        self.oversample = oversample
        self.Baseline = Baseline
        
        self.oversample_sett = self.oversample #过采样0-3
        self.baseline = self.Baseline#基线 海拔线 101325 默认
        self.chip_id = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xD0, 2)
        
        # read calibration data from EEPROM
        self._AC1 = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xAA, 2))[0]
        self._AC2 = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xAC, 2))[0]
        self._AC3 = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xAE, 2))[0]
        self._AC4 = unp('>H', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xB0, 2))[0]
        self._AC5 = unp('>H', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xB2, 2))[0]
        self._AC6 = unp('>H', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xB4, 2))[0]
        self._B1 = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xB6, 2))[0]
        self._B2 = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xB8, 2))[0]
        self._MB = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xBA, 2))[0]
        self._MC = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xBC, 2))[0]
        self._MD = unp('>h', self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xBE, 2))[0]

        # settings to be adjusted by user
        self.oversample_setting = 3
        self.baseline = 101325.0

        # output raw
        self.UT_raw = None
        self.B5_raw = None
        self.MSB_raw = None
        self.LSB_raw = None
        self.XLSB_raw = None
        self.gauge = self.makegauge() # Generator instance
        for _ in range(128):
            next(self.gauge)
            time.sleep_ms(1)

    def compvaldump(self):
        '''
        Returns a list of all compensation values
        '''
        return [self._AC1, self._AC2, self._AC3, self._AC4, self._AC5, self._AC6, 
                self._B1, self._B2, self._MB, self._MC, self._MD, self.oversample_setting]

    # gauge raw
    def makegauge(self):
        '''
        Generator refreshing the raw measurments.
        '''
        delays = (5, 8, 14, 25)
        while True:
            self._bmp_i2c.writeto_mem(self._bmp_addr, 0xF4, bytearray([0x2E]))
            t_start = time.ticks_ms()
            while (time.ticks_ms() - t_start) <= 5: # 5mS delay
                yield None
            try:
                self.UT_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF6, 2)
            except:
                yield None
            self._bmp_i2c.writeto_mem(self._bmp_addr, 0xF4, bytearray([0x34+(self.oversample_setting << 6)]))
            t_pressure_ready = delays[self.oversample_setting]
            t_start = time.ticks_ms()
            while (time.ticks_ms() - t_start) <= t_pressure_ready:
                yield None
            try:
                self.MSB_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF6, 1)
                self.LSB_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF7, 1)
                self.XLSB_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF8, 1)
            except:
                yield None
            yield True

    def blocking_read(self):
        if next(self.gauge) is not None: # Discard old data
            pass
        while next(self.gauge) is None:
            pass

    @property
    def oversample_sett(self):
        return self.oversample_setting

    @oversample_sett.setter
    def oversample_sett(self, value):
        if value in range(4):
            self.oversample_setting = value
        else:
            print('oversample_sett can only be 0, 1, 2 or 3, using 3 instead')
            self.oversample_setting = 3

    @property
    def temperature(self):
        '''
        Temperature in degree C.
        '''
        next(self.gauge)
        try:
            UT = unp('>H', self.UT_raw)[0]
        except:
            return 0.0
        X1 = (UT-self._AC6)*self._AC5/2**15
        X2 = self._MC*2**11/(X1+self._MD)
        self.B5_raw = X1+X2
        return (((X1+X2)+8)/2**4)/10

    @property
    def pressure(self):
        '''
        Pressure in mbar.
        '''
        next(self.gauge)
        self.temperature  # Populate self.B5_raw
        try:
            MSB = unp('B', self.MSB_raw)[0]
            LSB = unp('B', self.LSB_raw)[0]
            XLSB = unp('B', self.XLSB_raw)[0]
        except:
            return 0.0
        UP = ((MSB << 16)+(LSB << 8)+XLSB) >> (8-self.oversample_setting)
        B6 = self.B5_raw-4000
        X1 = (self._B2*(B6**2/2**12))/2**11
        X2 = self._AC2*B6/2**11
        X3 = X1+X2
        B3 = ((int((self._AC1*4+X3)) << self.oversample_setting)+2)/4
        X1 = self._AC3*B6/2**13
        X2 = (self._B1*(B6**2/2**12))/2**16
        X3 = ((X1+X2)+2)/2**2
        B4 = abs(self._AC4)*(X3+32768)/2**15
        B7 = (abs(UP)-B3) * (50000 >> self.oversample_setting)
        if B7 < 0x80000000:
            pressure = (B7*2)/B4
        else:
            pressure = (B7/B4)*2
        X1 = (pressure/2**8)**2
        X1 = (X1*3038)/2**16
        X2 = (-7357*pressure)/2**16
        return pressure+(X1+X2+3791)/2**4

    @property
    def altitude(self):
        '''
        Altitude in m.
        '''
        try:
            p = -7990.0*math.log(self.pressure/self.baseline)
        except:
            p = 0.0
        return p

四、st7735屏幕驱动

        和物联网开发124那篇文章是一样的。这里不再贴了,大家在文章的第一节链接进去找哈。。。

五、操作字体文件方法库

        和物联网开发124那篇文章是一样的。这里不再贴了,大家在文章的第一节链接进去找哈。。。

六、BMP280驱动

from micropython import const
from machine import I2C

class BMP280():
    
    def __init__(self, i2c,address):
        self.i2c = i2c
        self.address = address
        
        self.tb = bytearray(1)
        self.rb = bytearray(1)
        
        self.dig_T1 = self.get2Reg(0x88)
        self.dig_T2 = self.short(self.get2Reg(0x8A))
        self.dig_T3 = self.short(self.get2Reg(0x8C))
        self.dig_P1 = self.get2Reg(0x8E)
        self.dig_P2 = self.short(self.get2Reg(0x90))
        self.dig_P3 = self.short(self.get2Reg(0x92))
        self.dig_P4 = self.short(self.get2Reg(0x94))
        self.dig_P5 = self.short(self.get2Reg(0x96))
        self.dig_P6 = self.short(self.get2Reg(0x98))
        self.dig_P7 = self.short(self.get2Reg(0x9A))
        self.dig_P8 = self.short(self.get2Reg(0x9C))
        self.dig_P9 = self.short(self.get2Reg(0x9E))
        
        self.mode = 3
        self.osrs_p = 3
        self.osrs_t = 1
        self.setReg(0xF4, 0x2F)
        self.setReg(0xF5, 0x0C)
        self.filter = 3
        self.T = 0
        self.P = 0
        self.version = '1.0'
        
    def	short(self,	dat):
        if dat > 32767:
            return dat - 65536
        else:
            return dat

    # set reg
    def	setReg(self, reg, dat):
        self.tb[0] = dat
        self.i2c.writeto_mem(self.address, reg, self.tb)

    # get reg
    def	getReg(self, reg):
        self.i2c.readfrom_mem_into(self.address, reg, self.rb)
        return self.rb[0]

    # get two reg
    def	get2Reg(self, reg):
        return self.getReg(reg) + self.getReg(reg+1) * 256

    def get(self):
        adc_T = (self.getReg(0xFA)<<12) + (self.getReg(0xFB)<<4) + (self.getReg(0xFC)>>4)
        var1 = (((adc_T>>3)-(self.dig_T1<<1))*self.dig_T2)>>11
        var2 = (((((adc_T>>4)-self.dig_T1)*((adc_T>>4) - self.dig_T1))>>12)*self.dig_T3)>>14
        t = var1+var2
        self.T = ((t * 5 + 128) >> 8)/100
        var1 = (t>>1) - 64000
        var2 = (((var1>>2) * (var1>>2)) >> 11 ) * self.dig_P6
        var2 = var2 + ((var1*self.dig_P5)<<1)
        var2 = (var2>>2)+(self.dig_P4<<16)
        var1 = (((self.dig_P3*((var1>>2)*(var1>>2))>>13)>>3) + (((self.dig_P2) * var1)>>1))>>18
        var1 = ((32768+var1)*self.dig_P1)>>15
        if var1 == 0:
            return  # avoid exception caused by division by zero
        adc_P = (self.getReg(0xF7)<<12) + (self.getReg(0xF8)<<4) + (self.getReg(0xF9)>>4)
        p=((1048576-adc_P)-(var2>>12))*3125
        if p < 0x80000000:
            p = (p << 1) // var1
        else:
            p = (p // var1) * 2
        var1 = (self.dig_P9 * (((p>>3)*(p>>3))>>13))>>12
        var2 = (((p>>2)) * self.dig_P8)>>13
        self.P = p + ((var1 + var2 + self.dig_P7) >> 4)
        return [self.T, self.P]

    # get Temperature in Celsius
    def getTemp(self):
        self.get()
        return self.T

    # get Pressure in Pa
    def getPress(self):
        self.get()
        return self.P

    # Calculating absolute altitude
    def	getAltitude(self):
        return 44330*(1-(self.getPress()/101325)**(1/5.255))

    # sleep mode
    def poweroff(self):
        self.setReg(0xF4, 0)

    # normal mode
    def poweron(self):
        self.setReg(0xF4, 0x2F)

七、示例代码

from machine import Pin,SPI,I2C
from st7735 import ST7735,color
from ufont import BMFont

from bmp180 import BMP180
from bmp280 import BMP280

import time

font = BMFont("fonts/unifont-14.0.04.bmf")

spi = SPI(1,baudrate = 60_000_000,polarity = 0,sck = Pin(2),mosi = Pin(3),miso = None)
tft = ST7735(spi,rst = 10,dc = 6,cs = 7,bl = 8, width = 160, height = 80,rotate = 1,rgb = True)

i2c = I2C(0,scl = Pin(5),sda = Pin(4),freq = 400_000)

bmp1 = BMP180(i2c,0x77,3,101325)
bmp2 = BMP280(i2c,0x76)

def BMP():
    
    #180
    temp1 = bmp1.temperature
    pres1 = bmp1.pressure
    alti1 = bmp1.altitude
    
    #280
    temp2 = bmp2.getTemp()
    pres2 = bmp2.getPress()
    alti2 = bmp2.getAltitude()
    
    font.text(tft,"温度: %.2f %.2f"%(temp1,temp2),0,16,color(255,255,255),font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
    font.text(tft,"压力: %.2f"%(pres1),0,32,color(255,255,255),font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
    font.text(tft,"压力: %.2f"%(pres2),0,48,color(255,255,255),font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
    font.text(tft,"海拔: %.2f %.2f"%(alti1,alti2),0, 64,color(255,255,255),font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
    
#     print("温度: %.2f %.2f"%(temp1,temp2))
#     print("压力: %.2f %.2f"%(pres1,pres2))
#     print("海拔: %.2f %.2f"%(alti1,alti2))
#     time.sleep(1)
    
def main():
    
    font.text(tft,"BMP180&BMP280",24, 0,color(0,255,0),font_size = 16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = False)
    
    while True:
       BMP()
        
if __name__ == "__main__":
    main()

八,演示效果

九、模块购买

BMP180和BMP280购买链接:

商品详情icon-default.png?t=N7T8https://detail.tmall.com/item.htm?id=615945142918&spm=a1z09.2.0.0.3eb62e8dhNEsPk&_u=dp01rch60f0&skuId=4424117277184

BMP180资料下载链接:https://pan.baidu.com/s/1omMQgzUgw_98QXgGk3kYSQ 

提取码:8888

 
BMP280资料下载链接:https://pan.baidu.com/s/1TyQGJQ6R30hntzGr1SaSNg 
提取码:8888

;