If you need to integrate an Arduino with pressure sensor capabilities, your hardware choice dictates your entire circuit topology. For ambient atmospheric, weather, or altitude tracking, the digital I2C Bosch BMP390 is the definitive pick. If you are measuring high-pressure liquid or gas lines (up to 100 PSI), you must use an analog sensor like the NXP MPX5700AP. For 90% of embedded maker projects, the BMP390 is the correct default due to its built-in temperature compensation and digital filtering.
This guide focuses on wiring, coding, and debugging the BMP390 on a 5V Arduino Nano, including the mandatory logic-level translation required to prevent silicon damage.
The Decision: Digital I2C vs. Analog Pressure Sensors
Do not guess which sensor topology you need. Use this decision matrix to select the exact part number before ordering.
| Criteria | Digital I2C (Bosch BMP390) | Analog (NXP MPX5700AP) |
|---|---|---|
| Measurement Type | Absolute barometric (air/gas) | Gauge/Differential (liquids/high-pressure gas) |
| Pressure Range | 300 to 1250 hPa (0.3 to 1.25 bar) | 15 to 700 kPa (0.15 to 7 bar / ~100 PSI) |
| Output Signal | Digital I2C/SPI (24-bit ADC) | Analog voltage (0.5V to 4.5V) |
| Wiring Complexity | High (Requires logic level shifting on 5V) | Low (Direct to ADC, needs 5V excitation) |
| Best Application | Weather stations, drone altitude, HVAC draft | Water pump monitoring, pneumatic lines, scuba |
Hardware Specs and Parts List
The BMP390 operates strictly at 3.3V logic and power. Connecting it directly to the 5V I2C pins of a standard Arduino Nano will destroy the sensor's internal ESD protection diodes within seconds. You must use a bi-directional logic level converter.
Spec Sheet: Bosch BMP390
| Operating Voltage | 1.65V to 3.6V (VDD), 1.2V to 3.6V (VDDIO) |
| I2C Address | 0x77 (Default) or 0x76 (if SDO pad is bridged to GND) |
| Absolute Accuracy | ±0.5 hPa (approx. ±4 meters altitude) |
| Current Draw | ~730 µA at 1Hz sampling rate |
Exact Parts List
- Microcontroller: Arduino Nano V3 (ATmega328P, 5V logic)
- Sensor: Adafruit BMP390 Breakout Board (#4816)
- Level Shifter: BSS138 Bi-directional Logic Level Converter (4-channel)
- Wiring: 22 AWG solid core jumper wires, half-size solderless breadboard
Pin Mapping and Wiring Steps
Proper I2C wiring requires separating the high-voltage (5V) and low-voltage (3.3V) domains. The BSS138 converter handles this translation safely.
| Arduino Nano (5V) | Logic Level Converter | BMP390 Breakout (3.3V) |
|---|---|---|
| 5V Pin | HV (High Voltage) | — |
| 3.3V Pin | LV (Low Voltage) | VIN |
| GND | GND (Both sides) | GND |
| A4 (SDA) | HV1 | — |
| — | LV1 | SDA |
| A5 (SCL) | HV2 | — |
| — | LV2 | SCL |
Numbered Wiring Procedure
- Power the Rails: Connect the Nano 5V to the breadboard red rail (HV side) and Nano 3.3V to a secondary red rail (LV side). Connect Nano GND to the blue rails.
- Mount the Converter: Straddle the BSS138 module across the breadboard center trench. Wire HV to 5V, LV to 3.3V, and both GND pins to the common ground rail.
- Wire the I2C Lines: Run a wire from Nano A4 to HV1. Run a wire from HV1's counterpart (LV1) to the BMP390 SDA pin. Repeat for A5 (SCL) through HV2/LV2.
- Verify Voltages: Before plugging in the sensor, power the Nano and use a multimeter to verify the LV rail reads exactly 3.3V (±0.1V). If it reads 5V, your level shifter is wired backward and will fry the sensor.
Complete Arduino Code with Error Handling
This code targets the Arduino Nano V3 (ATmega328P). It uses the Adafruit BMP3XX library. Install it via the Arduino Library Manager before compiling.
#include <Wire.h>
#include <Adafruit_BMP3XX.h>
// Pin definitions for Arduino Nano V3 I2C
#define BMP_SDA A4
#define BMP_SCL A5
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BMP3XX bmp;
void setup() {
Serial.begin(115200);
// Wait for serial port to connect (useful for native USB boards, harmless on Nano)
while (!Serial) delay(10);
Serial.println("Initializing BMP390 Pressure Sensor...");
// Explicitly define I2C pins and set fast mode clock
Wire.begin(BMP_SDA, BMP_SCL);
Wire.setClock(400000);
// Error handling: Check for sensor presence
if (!bmp.begin_I2C()) {
Serial.println("ERROR: Could not find a valid BMP3 sensor, check wiring!");
Serial.println("Halt. Run I2C Scanner to verify address 0x77.");
while (1) {
delay(1000); // Infinite loop to prevent spamming serial monitor
}
}
// Configure oversampling for maximum precision
bmp.setTemperatureOversampling(BMP3_OVERSAMPLING_8X);
bmp.setPressureOversampling(BMP3_OVERSAMPLING_4X);
// Set IIR filter coefficient to smooth out mechanical vibrations
bmp.setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_3);
Serial.println("Sensor initialized successfully.");
}
void loop() {
if (!bmp.performReading()) {
Serial.println("Failed to perform reading :(");
return;
}
Serial.print("Temperature = ");
Serial.print(bmp.temperature);
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bmp.pressure / 100.0);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(bmp.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.println("-----------------------");
delay(2000);
}
Debugging: "Could not find a valid BMP3 sensor"
If your serial monitor outputs the exact string: Could not find a valid BMP3 sensor, check wiring!, the Wire library failed to receive an ACKnowledge (ACK) bit from the sensor at address 0x77. Do not blindly rewrite the code; follow this ranked diagnostic path.
The First 3 Things to Check
- Measure the LV Side Voltage: Put your multimeter probes on the BMP390 VIN and GND pins. If you read 5V, the level shifter is bypassed or wired backward. Disconnect immediately; the sensor is likely damaged.
- Run an I2C Scanner: Upload the standard Arduino 'I2C Scanner' sketch. If it returns
No I2C devices found, you have a physical continuity break on SDA/SCL. If it returns0x76, the SDO pad on your breakout is bridged to GND. Changebmp.begin_I2C()tobmp.begin_I2C(0x76)in the code. - Check Pull-Up Resistor Conflicts: The Adafruit breakout includes 10kΩ pull-up resistors on the 3.3V side. If you are daisy-chaining multiple I2C sensors, the parallel resistance drops (e.g., two 10k resistors = 5k). At 400kHz I2C clock speeds, strong pull-ups can cause signal ringing. If the scanner fails intermittently, drop
Wire.setClock(400000);toWire.setClock(100000);.
Extending and Simplifying the Build
Once the baseline serial output is stable, you can scale the project up or strip it down based on your deployment environment.
How to Extend: Add a Local Display
To make the project standalone, add a 128x64 SSD1306 OLED display. Because the OLED is also an I2C device, you can wire it to the same HV1/HV2 lines on the level shifter (using HV3/HV4 for the display). Ensure you use the Adafruit_SSD1306 library and initialize it at address 0x3C. Keep the total I2C bus capacitance under 400pF to maintain signal integrity at 400kHz.
How to Simplify: Eliminate the Logic Level Converter
If you want to bypass the BSS138 level shifter entirely to save space and wiring complexity, switch your microcontroller to a native 3.3V board. The Arduino Nano 33 IoT or the ESP32 DevKit V1 operate at 3.3V logic natively. With a 3.3V board, you wire the BMP390 SDA/SCL directly to the microcontroller's I2C pins, power it from the 3.3V out, and completely remove the level shifter from the BOM. If using an ESP32, remember to explicitly define your I2C pins in Wire.begin(SDA_PIN, SCL_PIN) as the default hardware I2C pins vary by ESP32 silicon revision.






