零知ESP32--BMP580 气压高度计
项目概述
这是一套可独立运行的气压高度计:ESP32 读取 Bosch BMP580 的温度与气压,用国际气压高度公式换算海拔,再把当前海拔减去上电(或手动清零)时的基准,得到厘米级相对高度。
系统同时提供三条输出通道:
| 通道 | 作用 |
|---|---|
| 240×240 TFT | 现场主显示:相对高度、温度、气压、海拔、垂直速度、约 60 秒趋势、IP 与时钟 |
| 局域网网页 | 手机/电脑看实时数据、历史曲线,可清零、设 P0、下载 CSV |
| 串口 115200 | 调试与命令:z 清零,p= 设海平面气压,a= 按已知海拔校准 |
上电后优先连已配置的 WiFi;连不上则开 SoftAP 热点 BMP580-Altimeter。历史数据每 5 秒写入 LittleFS /log.csv,内存环形缓冲约保留 30 分钟。
能测什么、不能测什么: 这是气压计,不是 IMU。左右晃动、水平平移几乎不改变相对高度;只有垂直方向气压变化才会反映到 Rel 上。使用时请先清零,再垂直举高 1~2 米或走上楼梯。
项目亮点
-
厘米级相对高度
气压 16 倍过采样 + IIR 系数 7 + 软件 EMA + 0.8 cm 死区,显示按 1 cm 取整,适合做“举高 / 上楼”演示。 -
三端同步
屏幕、网页、串口共用同一套滤波后的状态量。网页 500 ms 刷新,屏幕局部刷新避免整屏闪烁。 -
可校准、可掉电保存
海平面气压 P0 存在 NVS(Preferences命名空间bmp580)。支持直接设 P0,也支持输入已知海拔反推 P0。 -
历史可回看、可导出
RAM 环形缓冲 360 点 + 文件/log.csv(上限约 80 KB,超限自动裁掉旧数据)。网页可画气压 / 相对高度历史,并下载 CSV。 -
联网与离线都能用
STA 失败自动 SoftAP;NTP 用CST-8(阿里云 / 腾讯 / pool.ntp.org);WiFi 掉线约每 15 秒重连。 -
现场可清零
GPIO12 按键、串口z、网页按钮三条路径都会把当前海拔设为相对高度零点。
项目难点及解决方案
开发过程中真正卡住过的问题,以及固件里对应的处理,如下。
1. 芯片配置后一直读数为 0
原因: BMP580 的过采样、IIR、输出速率必须在 STANDBY 下改,最后再切 NORMAL。若配置后仍停在待机,或用 dataReady() 死等 DRDY,主循环会永远拿不到有效气压。
解决: configureBmp580() 固定顺序:STANDBY → 写 OSR/IIR/ODR → NORMAL。updateSensor() 直接 performReading(),不依赖 DRDY 门闩。
2. 接上 TFT 后 I2C 丢了
原因: ST7789 走硬件 SPI。部分板上 tft.init() 之后 SDA/SCL 状态异常,BMP580 突然无应答。
解决: 每次初始化总线先 recoverI2CPins():释放引脚、必要时补时钟脉冲,再 Wire.begin(21, 22)。只探测 0x46 / 0x47,最多重试 3 次。
3. 串口“突然停了”
原因: ESP32 硬件 I2C 在 loop 里被高频轮询会卡死;扫描地址 0x7E 会踩到 I3C,同样可能挂死。
解决: 读传感器间隔至少 100 ms;Wire.setTimeOut(30);探测只扫 BMP580 两个地址。
4. 温度 127.5 ℃、气压 1305 hPa 等垃圾值
原因: 总线毛刺或芯片未真正进入测量时,寄存器可能吐出越界值。
解决: isReadingSane() 要求温度在 −20~85 ℃、气压在 300~1250 hPa。连续失败 3 次则 recoverBmp580() 重新 begin + 配置。
5. 240×240 方屏画面偏左、右侧一条白边
原因: 很多 ST7789 驱动芯片显存是 240×320。TFT_eSPI 按 320 宽报尺寸,UI 若按 0,0 画 240 宽,有效像素会落在显存左侧,屏幕上看就是偏了。
解决: UI 锁定 240×240;TFT_OFF_X/Y = -1 时自动用 (nativeW - 240) 做偏移(常见为 80,0),再用 setViewport() 把后续绘制裁在方屏里。仍偏可把 TFT_OFF_X 改成 0 或 80。
6. GPIO12 清零键上电异常
原因: GPIO12 是 ESP32 的 strapping 脚。上电时若被按住拉低,可能影响启动。
解决: 按键接 GND,内部上拉;上电时不要按住。运行后再按才清零。
7. 屏幕不能显示中文
原因: TFT_eSPI 默认字体是 ASCII,没有完整 CJK 点阵。
解决: 屏幕标签用英文(Rel / T / P / ALT / Vz);中文放在网页端。
8. 网页曲线发糊
原因: Canvas 用 CSS 拉伸,未按 devicePixelRatio 设置实际像素。
解决: sizeCanvas() 按 DPR 设 canvas.width/height,再 setTransform 用 CSS 像素画线。
目录
6.1. 串口提示找不到 BMP580(0x46/0x47)
一、硬件系统部分
1.1 硬件清单
| 序号 | 名称 | 规格 / 备注 |
|---|---|---|
| 1 | 主控 | 零知ESP32 |
| 2 | 气压传感器 | BMP580 模块,必须 3.3V,走 I2C |
| 3 | 彩屏 | 240×240 ST7789 SPI TFT |
| 4 | 杜邦线 / 面包板 | 建议电源线稍粗,GND 共地 |
| 6 | USB 线 | 供电 + 烧录 + 串口 |
可选:已知海拔的参考点(用于 a= 校准),以及 2.4 GHz WiFi。
供电注意: BMP580 不要接 5V。CSB 必须保持高电平,模块才会停在 I2C 而不是 SPI。
1.2 接线方案
BMP580(I2C)
| BMP580 引脚 | 接到 | 说明 |
|---|---|---|
| VIN / VCC | ESP32 3.3V | 禁止 5V |
| GND | GND | 与屏幕、按键共地 |
| SDA / SDI | GPIO21 | I2C_SDA |
| SCL / SCK | GPIO22 | I2C_SCL |
| CS / CSB | 3.3V 或模块已拉高 | 保持 I2C |
| SDO | 悬空 → 地址 0x47;接地 → 0x46 | 固件两种都试 |
内部 INPUT_PULLUP,按下为低电平。上电时不要按住。
1.3 硬件连接图

实物接线时记住三件事:
- 所有模块共地。
- BMP580 与屏幕不要抢同一组数据脚: 传感器走 I2C(21/22),屏幕走 SPI(18/23/15/13/4)。
- 先不接屏幕也能用串口验证传感器;屏幕正常后再并上 TFT。
1.4 实物连接图

二、软件架构设计
固件以单文件草图的形式组织,整体逻辑可划分为六个层次:

2.1 系统初始化
setup() 顺序不能随便调换:屏幕会动 SPI,必须在屏幕起来之后再专门恢复 I2C,否则容易“屏亮了、气压没了”。
| 步骤 | 函数 | 做什么 |
|---|---|---|
| 1 | Serial.begin(115200) |
调试口 |
| 2 | loadPrefs() |
读出已保存的 P0、WiFi 账号 |
| 3 | setupLittleFS() |
挂载文件系统,载入 /log.csv |
| 4 | pinMode(BUTTON_PIN, INPUT_PULLUP) |
清零键 |
| 5 | setupDisplay() |
tft.init()、旋转、计算 80 像素偏移、setViewport(240,240) |
| 6 | initBmp580() |
恢复总线 → 探测 0x47/0x46 → STANDBY 配置 → NORMAL → 读首帧 |
| 7 | setupWiFi() |
最多等 12 s;失败则 SoftAP |
| 8 | setupWeb() |
注册 /、/api/*、/log.csv |
| 9 | 把 IP 写到屏幕底部 | STA 用局域网 IP,AP 用 192.168.4.1 |
WiFi 请在源码里改这两行(不要把密码提交到公开仓库):
const char *WIFI_SSID = "你的WiFi名称";
const char *WIFI_PASS = "你的WiFi密码";
2.2 主循环逻辑
loop() 不做长 delay,只在末尾 delay(2) 让出 CPU。各任务用时间戳分流。
关键节拍:
- 100 ms: 传感器。对应 ODR 10 Hz,再快没有意义,还会把 I2C 打挂。
- 500 ms: 串口一行、屏幕更新、网页火花图用的 72 点环形缓冲。
- 5 s: 落盘一条历史。360 条 × 5 s ≈ 30 分钟。
- 15 s: STA 断开后尝试
WiFi.begin。 - 30 s: NTP 仍未同步则再
configTzTime。
相对高度死区 0.8 cm:只有 |新值 − 当前 Rel| ≥ 0.008 m 才更新显示,避免最后一位乱跳。
三、代码拆分讲解
源码虽在一个 .ino 里,可按职责拆开读。
3.1 配置与全局状态
文件开头宏决定硬件脚、屏幕几何、日志容量:
I2C_SDA/SCL、BUTTON_PINSCREEN_W/H = 240,TFT_ROTATION 3,TFT_OFF_X/Y = -1自动偏移LOG_INTERVAL_MS = 5000,LOG_RAM_N = 360,文件最大约 80 KB- 运行时核心量:
temperatureC、pressureHpa、altitudeM、relativeM、verticalMs、seaLevelHpa、zeroAltitudeM
网页 HTML 以 PROGMEM 原始字符串嵌在固件里,ESP32 当 Web 服务器直接吐页面,不需要外置站点。
3.2 气压 ↔ 海拔
国际标准气压高度公式(温度按 ISA 近似):
[
h = 44330 \times \left(1 - \left(\frac{P}{P_0}\right)^{0.190295}\right)
]
反推海平面气压(已知当地海拔 (h)):
[
P_0 = P \big/ \left(1 - \frac{h}{44330}\right)^{5.255}
]
对应 pressureToAltitude()、seaLevelFromAltitude()。相对高度:
Rel = 当前海拔 − 清零时海拔
上电第一次有效读数会自动把基准海拔设为当前值,所以开机 Rel 从 0 附近开始。
3.3 BMP580 驱动封装
| 函数 | 作用 |
|---|---|
recoverI2CPins() |
释放被拉死的 SDA,补 16 个时钟 |
beginI2CBus() |
100 kHz + 30 ms 超时 |
scanI2C() |
只探 0x47、0x46 |
configureBmp580() |
待机写入 OSR/IIR/ODR 后进 NORMAL |
initBmp580() |
最多 3 轮,成功则记下地址并留下首帧 |
recoverBmp580() |
读失败后的软复位路径 |
updateSensor() |
滤波、死区、垂直速度 |
垂直速度:(\Delta Rel / \Delta t),再做 0.25 * 新值 + 0.75 * 旧值,只作趋势参考,精度不如 Rel。
3.4 人机接口
串口
| 命令 | 效果 |
|---|---|
z 或 zero |
相对高度清零 |
p=1013.25 |
设置 P0(hPa)并写入 NVS |
a=50 |
把当前气压当作海拔 50 m,反推 P0 并保存 |
按键: GPIO12 低电平且已有有效样本 → zeroRelativeAltitude()。
网页 API
| 路径 | 说明 |
|---|---|
GET / |
看板 HTML |
GET /api/data |
当前 T/P/Alt/Rel/Vz/P0/时间 |
GET /api/zero |
清零 |
GET /api/sealevel?hpa= |
设 P0 |
GET /api/calibrate?alt= |
按海拔校准 |
GET /api/history |
历史 JSON |
GET /api/clear |
清空记录 |
GET /log.csv |
下载文件 |
- NVS
bmp580:p0、ssid、pass - LittleFS
/log.csv: 表头ts,t,p,alt,rel。文件过大时丢掉大约前 40%,保留后段 - RAM
logRam[360]: 网页历史曲线优先读这里,重启后由 CSV 回填
未对上 NTP 时,时间戳用 millis()/1000,网页上显示 T+…s,曲线底部不会画时钟刻度。
3.6 显示
屏幕采用“静态底 + 局部刷新”:
drawStaticLayout()画卡片外壳和标签(只在需要时重画)updateDisplay()比较上次字符串,数字没变就不擦- Rel 上升绿色、下降黄色、接近 0 蓝色
- 底部火花图 72 点,对应约 36 秒~1 分钟的 Rel(随 500 ms 节拍)
网页主数字是相对高度厘米;温度 / 气压 / 海拔 / 垂直速度四宫格;下方实时趋势 + 历史双曲线(气压绿、Rel 蓝),并按 devicePixelRatio 锐化。
3.7 网络
STA 12 s 内连上 → 保存账号、NTP、mDNS bmp580.local
STA 失败 → SoftAP BMP580-Altimeter / 12345678,默认 http://192.168.4.1
之后 → maintainWifi() 维持 STA 与 NTP
手机连 SoftAP 后,地址以串口打印为准。Windows 上 .local 有时无效,直接用 IP 更稳。
四、操作过程及数据展示
4.1 操作步骤
-
改 WiFi 与确认引脚
打开BMP580_Altimeter.ino,填写WIFI_SSID/WIFI_PASS。确认 I2C、按键与 TFT_eSPIUser_Setup一致。 -
接线检查
BMP580 只接 3.3V;CSB 为高;SDA/SCL 没有和屏幕 MOSI/SCLK 接反。 -
编译烧录
串口监视器 115200。正常时应看到类似:ESP32 + BMP580 气压高度计 BMP580 芯片应答成功,地址 0x47 首帧数据 T=xx.xx C P=xxxx.xx hPa WiFi 已连接,浏览器打开 http://192.168.x.x 也可尝试 http://bmp580.local 就绪。 -
看屏幕
右上角LIVE表示传感器在更新。中间大号为相对高度(cm)。底部左侧 IP,右侧时钟(NTP 成功为绿色,否则--:--)。 -
清零再做高度实验
按 GPIO12,或串口输入z,或网页点「相对高度清零」。然后垂直举高模块或走上楼梯,Rel 应变大;左右晃不应有明显变化。 -
打开网页
浏览器访问串口给出的 IP 或http://bmp580.local。若页面还是旧版,强制刷新(Ctrl+F5)。 -
看历史与导出
等待数分钟后点「刷新历史」。需要存档时下载log.csv。不要的数据可「清空记录」。
4.2 数据展示说明
串口一行示例:
T=26.31 C P=1008.452 hPa Alt=39.12 m Rel=+123 cm Vz=+0.15 m/s 2026-08-25 14:12:03
| 字段 | 含义 |
|---|---|
| T | 滤波后温度 |
| P | 滤波后气压 |
| Alt | 相对海平面 P0 的海拔 |
| Rel | 相对清零点的高度,厘米 |
| Vz | 垂直速度估计 |
| 时间 | NTP 成功为日历时间,否则为上电秒数 |
屏幕: 主视觉是 Rel;四宫格为 T / P / ALT / Vz;底部短曲线看最近 Rel 是否在爬升。
网页: 顶部时钟与 NTP/I2C 状态;大号 cm;历史图左侧有纵轴刻度,底部有时分。曲线发糊时刷新页面;没有时间刻度说明还没对上 NTP。
4.3 演示视频
零知ESP32--BMP580 气压高度计
五、技术原理
5.1 工作原理
BMP580 是压阻式气压传感器:膜片随外界气压形变,片上 ADC 读出原始值,再用出厂校准系数补偿得到温度(℃)和气压(hPa)。
海拔不是直接测出来的。在标准大气假设下,气压随高度近似指数下降,因此可用 (P) 和海平面参考 (P_0) 反算几何高度。本项目:
- 芯片以约 10 Hz 产出补偿后的 T、P。
- 软件对 T 做轻量平滑(新值 20%),对 P 做更重的 EMA(新值 12%),压掉通风和人手热干扰。
- 用公式得到绝对海拔
altitudeM。 - 记住清零瞬间的海拔
zeroAltitudeM,差值为相对高度。 - 小于 0.8 cm 的跳动丢弃,显示时四舍五入到 1 cm。
误差来源(做实验时心里有数):
- (P_0) 不准 → 绝对海拔整体偏移,但相对高度几乎不受影响(演示请用 Rel)。
- 天气、空调、关门会造成 hPa 级慢漂,长时间 Rel 会爬。
- 温度突变会通过气压补偿耦合进高度,所以不要把模块对着热风口。
- 本方案没有 GPS / 超声波交叉验证,适合教学与室内相对高度,不适合做航空级高度表。
5.2 工作模式配置
Bosch BMP5xx 常见电源模式:
| 模式 | 含义 | 本固件 |
|---|---|---|
| STANDBY | 停测,才能改 OSR / IIR / ODR | 配置阶段使用 |
| NORMAL | 按 ODR 连续测量 | 运行阶段使用 |
| FORCED | 测一次再睡 | 未使用 |
当前寄存器配置(configureBmp580()):
| 参数 | 取值 | 用意 |
|---|---|---|
| 温度过采样 | 2× | 温度变化慢,2 倍足够,还给气压留带宽 |
| 气压过采样 | 16× | 压低量化噪声,换厘米级稳定性 |
| 气压使能 | 开 | 高度只来自气压 |
| IIR | 系数 7 | 片内再滤一档,抑制短时扰动 |
| ODR | 10 Hz | 与 100 ms 轮询匹配,人眼跟得上,I2C 也不过载 |
| 电源模式 | NORMAL | 连续出数 |
配置时序必须是:
STANDBY → 写 OSR / IIR / ODR → NORMAL → 延时约 50 ms → 读首帧
I2C 地址由 SDO 决定:悬空常用 0x47,接地为 0x46。CSB 若被拉低,芯片会切到 SPI,I2C 初始化会失败——这是接线里最容易忽略的一点。
六、常见问题指引
6.1. 串口提示找不到 BMP580(0x46/0x47)
检查 3.3V 而不是 5V;SDA/SCL 有没有和屏幕接反;CSB 是否为高;模块杜邦线是否松。可先卸下屏幕再初始化,确认是传感器问题还是 SPI 冲突。
6.2. 芯片应答成功,但一直没有有效气压
供电是否稳定;CSB 是否在测量时仍保持高。固件会提示检查 3.3V 与 CSB。看 configureBmp580() 是否完整执行进了 NORMAL。
6.3. 读数乱跳或出现 127 ℃ / 上千 hPa
多为 I2C 被干扰。固件会丢弃非法值并在连续失败后重建总线。加短线、共地、远离电机。不要在 loop 里自行加密集扫描。
6.4. 历史为空或下载 CSV 失败
分区要带 spiffs/LittleFS。串口若打印 “LittleFS 启动失败”,历史只在内存,掉电即无。文件超过约 80 KB 会自动裁旧。
更多推荐



所有评论(0)