In this project, we’ll build a compact altimeter using the MS5611 precision pressure sensor and a Seeed Studio XIAO ESP32-C3 microcontroller.

We'll display temperature, pressure, and altitude on a small OLED screen, and use a rotary encoder with a button to calibrate and switch units between meters and feet!

Supplies

Step 1: Enclosure Design and 3D Printing

I utilised Fusion 360 to plan and design my project, which required careful space optimisation. I needed to fit all the parts into the smallest form factor possible while ensuring practicality, including sufficient space for wiring and easy assembly. First, I imported all 3d models of the parts and tried different configurations by placing the parts in various positions. Once I found the optimal configurations, I built the enclosure around them. All design files are provided below

I printed the main body in orange PLA, also the knobe and front plate are printed using Black

Step 2: Code

Here’s what the code will do:

  • Main Screen:
  • Display temperature, pressure, and calculated altitude.
  • Settings Menu (after long-press on encoder button):
  • Calibration: Adjust the displayed altitude based on the real-world reading.
  • Units: Switch altitude display between meters and feet.
  • Back: Return to main screen.

https://github.com/jarzebski/Arduino-MS5611 : We are using this library for MS5611. Make sure to install this to IDE before flashing this code to XAIO

#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <MS5611.h> // https://github.com/jarzebski/Arduino-MS5611
#include <EEPROM.h>
#include <Arduino.h> // Required for ESP32 and IRAM_ATTR
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C // See datasheet for Address
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
MS5611 ms5611;
// Rotary Encoder Inputs - Using the working code's definitions
#define ENCODER_PIN_A D0 // D0
#define ENCODER_PIN_B D1 // D1
#define ENCODER_BUTTON_PIN D2 // D2
// EEPROM Addresses
#define EEPROM_REFERENCE_PRESSURE 0
#define EEPROM_UNITS 8
// Menu States
enum MenuState {
MAIN_PAGE,
SETTINGS_MENU,
CALIBRATION_PAGE,
UNITS_PAGE
};
MenuState currentMenuState = MAIN_PAGE;
// Calibration Variables
double currentReferencePressure;
float currentSetAltitude = 0; // User-defined altitude for calibration
// Units Variable (0 for meters, 1 for feet)
uint8_t currentUnits = 0;
// Encoder Variables - Using the working code's logic
volatile long encoderCount = 0;
int lastStateCLK;
String currentDir = "";
unsigned long lastButtonPress = 0;
unsigned long buttonDebounceTime = 1000; // Debounce delay for button in ms
byte buttonPressCount = 0;
// Function Prototypes
void displayMainPage();
void displaySettingsMenu(int selectedOption);
void displayCalibrationPage();
void displayUnitsPage(int selectedOption);
void readEncoder();
void readButton();
void saveCalibration();
void loadCalibration();
void saveUnits();
void loadUnits();
float calculateAltitude(double pressure);
float convertToFeet(float meters);
void setupEncoder();
void setupButton();
void setup() {
Serial.begin(115200);
// Initialize MS5611 sensor
Serial.println("Initialize MS5611 Sensor");
while (!ms5611.begin()) {
Serial.println("Could not find a valid MS5611 sensor, check wiring!");
delay(500);
}
// Initialize OLED display
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.display();
delay(500);
// Initialize Encoder
setupEncoder();
// Initialize Button
setupButton();
//...
Read more »