# AHT20 (0x38) + BMP280 (0x77) on Raspberry Pi Pico, I2C0 (GP8 SDA, GP9 SCL) from machine import Pin, I2C from time import sleep # ---------- I2C ---------- i2c = I2C(0, sda=Pin(8), scl=Pin(9), freq=100000) AHT_ADDR = 0x38 BMP_ADDR = 0x77 # your chip id 0x58 confirmed BMP280 at 0x77 # --------- AHT20 (T + RH) ---------- def aht20_init(): try: i2c.writeto(AHT_ADDR, b'\xBA') # soft reset sleep(0.02) except OSError: pass i2c.writeto(AHT_ADDR, b'\xBE\x08\x00') # init/calibrate sleep(0.02) def aht20_read(): i2c.writeto(AHT_ADDR, b'\xAC\x33\x00') # trigger # wait until not busy for _ in range(60): status = i2c.readfrom(AHT_ADDR, 1)[0] if (status & 0x80) == 0: break sleep(0.005) raw = i2c.readfrom(AHT_ADDR, 6) hum = ((raw[1]<<12) | (raw[2]<<4) | (raw[3]>>4)) / 1048576.0 * 100.0 tmp = (((raw[3]&0x0F)<<16) | (raw[4]<<8) | raw[5]) / 1048576.0 * 200.0 - 50.0 return tmp, hum # --------- BMP280 (Pressure + Temp) ---------- # Minimal driver (forced mode, x1 oversampling) def _u16(b): return b[0] | (b[1] << 8) def _s16(b): v = _u16(b) return v - 65536 if v & 0x8000 else v # Read calibration constants cal = i2c.readfrom_mem(BMP_ADDR, 0x88, 24) dig_T1 = _u16(cal[0:2]) dig_T2 = _s16(cal[2:4]) dig_T3 = _s16(cal[4:6]) dig_P1 = _u16(cal[6:8]) dig_P2 = _s16(cal[8:10]) dig_P3 = _s16(cal[10:12]) dig_P4 = _s16(cal[12:14]) dig_P5 = _s16(cal[14:16]) dig_P6 = _s16(cal[16:18]) dig_P7 = _s16(cal[18:20]) dig_P8 = _s16(cal[20:22]) dig_P9 = _s16(cal[22:24]) # Configure: ctrl_meas (temp x1, press x1, sleep), config (standby/filter default) # We'll use "forced" mode per read. i2c.writeto_mem(BMP_ADDR, 0xF4, b'\x27') # osrs_t=1, osrs_p=1, mode=3 (normal) i2c.writeto_mem(BMP_ADDR, 0xF5, b'\x00') # config default t_fine = 0 def bmp280_read(): global t_fine # Force a measurement (write mode to forced would be 0x25; normal 0x27 is okay too) # Read raw data: 0xF7..0xFC: press_msb, press_lsb, press_xlsb, temp_msb, temp_lsb, temp_xlsb data = i2c.readfrom_mem(BMP_ADDR, 0xF7, 6) adc_p = ((data[0] << 16) | (data[1] << 8) | data[2]) >> 4 adc_t = ((data[3] << 16) | (data[4] << 8) | data[5]) >> 4 # Temperature compensation (datasheet) var1 = ((adc_t / 16384.0) - (dig_T1 / 1024.0)) * dig_T2 var2 = (((adc_t / 131072.0) - (dig_T1 / 8192.0)) ** 2) * dig_T3 t_fine = int(var1 + var2) T = (var1 + var2) / 5120.0 # Pressure compensation (datasheet) var1p = t_fine / 2.0 - 64000.0 var2p = var1p * var1p * dig_P6 / 32768.0 var2p = var2p + var1p * dig_P5 * 2.0 var2p = var2p / 4.0 + dig_P4 * 65536.0 var1p = (dig_P3 * var1p * var1p / 524288.0 + dig_P2 * var1p) / 524288.0 var1p = (1.0 + var1p / 32768.0) * dig_P1 if var1p == 0: return T, 0.0 # avoid division by zero P = 1048576.0 - adc_p P = (P - var2p / 4096.0) * 6250.0 / var1p var1p = dig_P9 * P * P / 2147483648.0 var2p = P * dig_P8 / 32768.0 P = P + (var1p + var2p + dig_P7) / 16.0 P_hPa = P / 100.0 return T, P_hPa # ----- Altitude from pressure ----- P0_SEA_LEVEL = 1013.25 # set this to your current sea-level pressure for best accuracy def altitude_from_pressure(p_hPa, p0=P0_SEA_LEVEL): return 44330.0 * (1.0 - (p_hPa / p0) ** (1/5.255)) # ---------- Demo ---------- aht20_init() while True: try: Taht, RH = aht20_read() Tbmp, P = bmp280_read() alt = altitude_from_pressure(P, P0_SEA_LEVEL) print("AHT20 -> T = %.2f °C RH = %.1f %%" % (Taht, RH)) print("BMP280 -> T = %.2f °C P = %.2f hPa Alt ≈ %.1f m (P0=%.2f hPa)" % (Tbmp, P, alt, P0_SEA_LEVEL)) print() except OSError as e: print("Read error:", e) sleep(1)
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter