Let's use an Adafruit CLUE to bring this all together and demonstrate how a pressure based altimeter works, and also why calibration is important.
Download the Project Bundle
Your project will use a specific set of CircuitPython libraries and the code.py file. To get everything you need, click on the Download Project Bundle link below, and uncompress the .zip file.
Hook your CLUE to your computer via a known good USB data+power cable. It should show up as a thumb drive named CIRCUITPY.
Using File Explorer/Finder (depending on your Operating System), drag the contents of the uncompressed bundle directory onto your board's CIRCUITPY drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.
Once the code restarts, the altimeter should start and show up on the CLUE screen. Head on to the next pages for instructions on how to use the altimeter code.
# SPDX-FileCopyrightText: 2020 Carter Nelson for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import struct
import displayio
import terminalio
from microcontroller import nvm
from adafruit_display_text import label
import adafruit_imageload
from adafruit_clue import clue
# ==| USER CONFIG |=====================
USE_METRIC = False
DISPLAY_UPDATE = 1
HOLD_TO_SET = 1
FONT = terminalio.FONT
BLUE = 0x53E4FF
ORANGE = 0xFCDF03
RED = 0xFA0000
DEBOUNCE = 0.05
SAMPLES = 10
DELAY = 0.05
STD_SLP = 1013.25
# ==| USER CONFIG |=====================
# configure pressure sensor (see Table 15 in datasheet)
clue._pressure.mode = 0x03 # normal
clue._pressure.overscan_pressure = 0x05 # x16
clue._pressure.overscan_temperature = 0x02 # x2
clue._pressure.iir_filter = 0x02 # 4
clue._pressure.standby_period = 0x01 # 62.5 ms
# restore saved sea level pressure from NVM
slp = struct.unpack("f", nvm[0:4])[0]
clue.sea_level_pressure = slp if 0 < slp < 2000 else STD_SLP
# --------------------------------------------------------------------
# D I S P L A Y S E T U P
# --------------------------------------------------------------------
# create main display group
splash = displayio.Group()
clue.display.root_group = splash
# background
bg_bmp, bg_pal = adafruit_imageload.load(
"images/network23.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette
)
for i, color in enumerate(bg_pal):
if color == 0xFF0000:
bg_pal.make_transparent(i)
break
background = displayio.TileGrid(bg_bmp, pixel_shader=bg_pal)
# a group for both altitude readouts
alti_readouts = displayio.Group(scale=6)
# altitude (corrected)
alti_disp = label.Label(FONT, text="12345", color=ORANGE)
alti_disp.anchor_point = (0, 0)
alti_disp.anchored_position = (7, 2)
# altitude (uncorrected)
alt2_disp = label.Label(FONT, text="12345", color=ORANGE)
alt2_disp.anchor_point = (0, 0)
alt2_disp.anchored_position = (7, 15)
# add both alti's to group
alti_readouts.append(alti_disp)
alti_readouts.append(alt2_disp)
# barometric pressure and temperature
aux_data = label.Label(FONT, text="P: 1234.56 T: 123.4", color=BLUE)
aux_data.anchor_point = (0, 0)
aux_data.anchored_position = (16, 212)
# calibration mode indicator
cal_mode = label.Label(FONT, text=" ", color=RED, scale=4, x=150, y=200)
# add everything to splash
splash.append(background)
splash.append(alti_readouts)
splash.append(aux_data)
splash.append(cal_mode)
# --------------------------------------------------------------------
# H E L P E R F U N C T I O N S
# --------------------------------------------------------------------
def compute_altitude(barometric_pressure, sea_level_pressure):
"""Compute altitude (m) from barometric pressure (hPa) and sea level pressure (hPa)."""
# https://www.weather.gov/media/epz/wxcalc/pressureAltitude.pdf
return 44307.69396 * (1 - pow((barometric_pressure / sea_level_pressure), 0.190284))
def compute_sea_level_pressure(barometric_pressure, altitude):
"""Compute sea level pressure (hPa) from barometric pressure (hPa) and altitude (m)."""
return barometric_pressure * pow((1 - (altitude / 44307.69396)), -5.2553)
def average_readings(samples=10, delay=0.05):
"""Return averaged readings for pressure and temperature."""
pressure = 0
temperature = 0
for _ in range(samples):
pressure += clue.pressure
temperature += clue.temperature
time.sleep(delay)
return pressure / samples, temperature / samples
def recalibrate(current_sea_level_pressure=None):
"""Enter current altitude."""
cal_mode.text = "CAL"
alt2_disp.text = "-----"
# wait for release if still being held
while clue.button_a and clue.button_b:
pass
# get current value
altitude = int(alti_disp.text)
done = False
while not done:
now = time.monotonic()
# increase
if clue.button_a and not clue.button_b:
altitude -= 1
time.sleep(DEBOUNCE)
# decrease
elif clue.button_b and not clue.button_a:
altitude += 1
time.sleep(DEBOUNCE)
# hold both to set
elif clue.button_a and clue.button_b:
while clue.button_a and clue.button_b:
if time.monotonic() - now > HOLD_TO_SET:
print("done")
done = True
break
alti_disp.text = "{:5d}".format(altitude)
cal_mode.text = " "
# change clue settings
if not USE_METRIC:
altitude *= 0.3048
# get current local pressure
barometric_pressure, _ = average_readings(SAMPLES, DELAY)
# compute sea level pressure and set
clue.sea_level_pressure = compute_sea_level_pressure(barometric_pressure, altitude)
# store in NVM for later use
nvm[0:4] = struct.pack("f", clue.sea_level_pressure)
def update_display():
"""Update the display with latest info."""
barometric_pressure, temperature = average_readings(SAMPLES, DELAY)
altitude = compute_altitude(barometric_pressure, clue.sea_level_pressure)
alt2tude = compute_altitude(barometric_pressure, STD_SLP)
if not USE_METRIC:
altitude *= 3.28084 # ft
alt2tude *= 3.28084
# barometric_pressure *= 0.0145038 # psi
temperature = 32 + 1.8 * temperature # deg F
alti_disp.text = "{:5d}".format(int(altitude))
alt2_disp.text = "{:5d}".format(int(alt2tude))
aux_data.text = "P: {:7.2f} T: {:5.1f}".format(barometric_pressure, temperature)
# --------------------------------------------------------------------
# M A I N L O O P
# --------------------------------------------------------------------
last_update = time.monotonic()
while True:
now = time.monotonic()
# update display with latest info
if now - last_update > DISPLAY_UPDATE:
update_display()
last_update = now
# hold both to recalibrate
if clue.button_a and clue.button_b:
# accumulate hold time
while clue.button_a and clue.button_b:
if time.monotonic() - now > HOLD_TO_SET:
print("set")
recalibrate(clue.sea_level_pressure)
break
# wait for release if still being held
while clue.button_a and clue.button_b:
pass
Page last edited February 24, 2025
Text editor powered by tinymce.