当前位置: 首页 > news >正文

STM32CubeMX + HAL 库:基于 I²C 通信的 BMP280气压海拔测量

1. 概述

1.1 实验目的

        本实验基于 STM32CubeMX 与 HAL 库,利用硬件 I²C 接口实现对 BMP280 高精度气压与温度传感器的测量与数据处理。实验内容涵盖 BMP280 的初始化配置、寄存器读写机制、气压与温度数据的获取及物理量计算等关键环节。通过对实验驱动代码与测试结果的完整展示,读者不仅能够深入理解 STM32 硬件 I²C 总线的应用方法,还能掌握数字气压传感器的通信特性与补偿算法,实现由气压推算高度的应用过程。该实验为智能硬件系统中的 环境监测、气象观测、无人机高度控制 与 物联网终端设备 开发提供实践参考与技术支撑。

1.2 气压传感器

此芯片是温湿度传感器和气压传感器二合一的

传感器型号压力范围 (hPa)压力精度 / 误差压力分辨率高度分辨率接口方式应用场景
BMP180300 ~ 1100±1.0 hPa0.01 hPa~8 mI²C手机、导航、气象
BMP280300 ~ 1100±0.12 hPa0.01 hPa~1 mI²C / SPI可穿戴设备、环境监测
BME280300 ~ 1100±0.12 hPa0.01 hPa~1 mI²C / SPI气象站、IoT
LPS22HB260 ~ 1260±0.1 hPa0.01 hPa~0.8 mI²C / SPI手机、IoT
LPS33HW260 ~ 1260±0.1 hPa0.01 hPa~0.8 mI²C / SPI潜水表、防水应用
BMP388300 ~ 1250±0.08 hPa0.0023 hPa~0.66 mI²C / SPI无人机、运动追踪
DPS310300 ~ 1200±0.06 hPa0.002 hPa~0.5 mI²C / SPI无人机、GPS 辅助
BMP390300 ~ 1250±0.03 hPa0.002 hPa~0.25 mI²C / SPI高精度定位、智能穿戴
MS561110 ~ 1200±0.1 hPa0.012 hPa~10 cmI²C / SPI航模、气象、无人机

 1.3 读取原理

        BMP280 内部 ADC 会输出未经补偿的原始温度值 adc_T 和原始压力值 adc_P。为了获得准确的测量结果,需要结合芯片出厂时写入的校准系数进行补偿:首先利用温度校准系数 dig_T1 ~ dig_T3 对原始温度值进行补偿,得到准确温度及中间变量 t_fine;随后再结合 t_fine 与压力校准系数 dig_P1 ~ dig_P9 对原始压力值进行补偿,计算出精确的气压值。这些校准系数均需通过 I²C 接口从芯片内部寄存器中读取。

       在完成温度和压力的补偿计算后,即可得到精确的大气压值。基于此压力,再结合国际标准大气模型所推导的气压—高度公式,便能够换算出对应的海拔高度,从而实现由传感器原始数据到实际环境物理量的完整转换过程。

注:BMP280的IIC固定7位地址是0x77

2. VSCode

2.1 BMP280.c

/* =========================================================* BMP280.c* Driver for BMP280 Pressure & Temperature Sensor* ========================================================= */#include "BMP280.h"
#include "stdio.h"
#include <math.h>/* 静态变量 */
static int32_t bmp280RawPressure = 0;
static int32_t bmp280RawTemperature = 0;
static BMP280_Calib_TypeDef bmp280Cal;/* === HAL I2C 封装函数 === */
static HAL_StatusTypeDef BMP280_Read(uint8_t reg, uint8_t *buf, uint16_t len)
{return HAL_I2C_Mem_Read(&hi2c1, BMP280_I2C_ADDR, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 100);
}static HAL_StatusTypeDef BMP280_Write(uint8_t reg, uint8_t value)
{return HAL_I2C_Mem_Write(&hi2c1, BMP280_I2C_ADDR, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, 100);
}/* === 校准数据读取 === */
static void BMP280_ReadCalibData(void)
{uint8_t buf[24];BMP280_Read(BMP280_DIG_T1_LSB_REG, buf, 24);bmp280Cal.dig_T1 = (uint16_t)(buf[1] << 8 | buf[0]);bmp280Cal.dig_T2 = (int16_t)(buf[3] << 8 | buf[2]);bmp280Cal.dig_T3 = (int16_t)(buf[5] << 8 | buf[4]);bmp280Cal.dig_P1 = (uint16_t)(buf[7] << 8 | buf[6]);bmp280Cal.dig_P2 = (int16_t)(buf[9] << 8 | buf[8]);bmp280Cal.dig_P3 = (int16_t)(buf[11] << 8 | buf[10]);bmp280Cal.dig_P4 = (int16_t)(buf[13] << 8 | buf[12]);bmp280Cal.dig_P5 = (int16_t)(buf[15] << 8 | buf[14]);bmp280Cal.dig_P6 = (int16_t)(buf[17] << 8 | buf[16]);bmp280Cal.dig_P7 = (int16_t)(buf[19] << 8 | buf[18]);bmp280Cal.dig_P8 = (int16_t)(buf[21] << 8 | buf[20]);bmp280Cal.dig_P9 = (int16_t)(buf[23] << 8 | buf[22]);
}/* === 初始化 === */
uint8_t BMP280_Init(void)
{uint8_t id;/* 读 ID */BMP280_Read(BMP280_CHIPID_REG, &id, 1);if (id != 0x58) return 0;  // BMP280 ID 固定为 0x58/* 读校准参数 */BMP280_ReadCalibData();/* 设置采样 & 正常模式 */uint8_t ctrl = (BMP280_OVERSAMP_16X << 5) | (BMP280_OVERSAMP_8X << 2) | BMP280_NORMAL_MODE;BMP280_Write(BMP280_CTRLMEAS_REG, ctrl);/* 配置滤波 (IIR=16, standby=0.5ms) */uint8_t cfg = (0x04 << 2);BMP280_Write(BMP280_CONFIG_REG, cfg);return id;
}/* === 读取原始数据 === */
static void BMP280_ReadRaw(void)
{uint8_t data[6];BMP280_Read(BMP280_PRESSURE_MSB_REG, data, 6);bmp280RawPressure = (int32_t)((((uint32_t)data[0]) << 12) |(((uint32_t)data[1]) << 4) |((uint32_t)data[2] >> 4));bmp280RawTemperature = (int32_t)((((uint32_t)data[3]) << 12) |(((uint32_t)data[4]) << 4) |((uint32_t)data[5] >> 4));
}/* === 温度补偿 === */
static int32_t BMP280_CompensateT(int32_t adcT)
{int32_t var1, var2, T;var1 = ((((adcT >> 3) - ((int32_t)bmp280Cal.dig_T1 << 1))) * ((int32_t)bmp280Cal.dig_T2)) >> 11;var2 = (((((adcT >> 4) - ((int32_t)bmp280Cal.dig_T1)) *((adcT >> 4) - ((int32_t)bmp280Cal.dig_T1))) >> 12) *((int32_t)bmp280Cal.dig_T3)) >> 14;bmp280Cal.t_fine = var1 + var2;T = (bmp280Cal.t_fine * 5 + 128) >> 8;return T;  // ℃*100
}/* === 压力补偿 === */
static uint32_t BMP280_CompensateP(int32_t adcP)
{int64_t var1, var2, p;var1 = ((int64_t)bmp280Cal.t_fine) - 128000;var2 = var1 * var1 * (int64_t)bmp280Cal.dig_P6;var2 = var2 + ((var1 * (int64_t)bmp280Cal.dig_P5) << 17);var2 = var2 + (((int64_t)bmp280Cal.dig_P4) << 35);var1 = ((var1 * var1 * (int64_t)bmp280Cal.dig_P3) >> 8) +((var1 * (int64_t)bmp280Cal.dig_P2) << 12);var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)bmp280Cal.dig_P1) >> 33;if (var1 == 0) return 0;p = 1048576 - adcP;p = (((p << 31) - var2) * 3125) / var1;var1 = (((int64_t)bmp280Cal.dig_P9) * (p >> 13) * (p >> 13)) >> 25;var2 = (((int64_t)bmp280Cal.dig_P8) * p) >> 19;p = ((p + var1 + var2) >> 8) + (((int64_t)bmp280Cal.dig_P7) << 4);return (uint32_t)p;  // Pa
}/* === 压力转海拔 === */
static float BMP280_PressureToAltitude(float pressure)
{return 44330.0f * (1.0f - powf(pressure / 101325.0f, 0.1903f));
}/* === 对外接口 === */
void BMP280GetData(float *pressure, float *temperature, float *asl)
{BMP280_ReadRaw();*temperature = BMP280_CompensateT(bmp280RawTemperature) / 100.0f;*pressure    = BMP280_CompensateP(bmp280RawPressure) / 256000.0f;  // kPa*asl         = BMP280_PressureToAltitude(*pressure * 1000.0f);
}

2.2 BMP280.h

#ifndef __BMP280_H
#define __BMP280_H#include "i2c.h"/* 外部 I2C 句柄 */ 
extern I2C_HandleTypeDef hi2c1;
/* === I2C 地址 === */
#define BMP280_I2C_ADDR        (0x77 << 1)   // 7-bit 地址,左移一位给 HAL 用/* === 校准寄存器起始地址 === */
#define BMP280_DIG_T1_LSB_REG           0x88   // 从这里开始顺序读 24 字节/* === 芯片 ID === */
#define BMP280_CHIPID_REG               0xD0/* === 控制与配置寄存器 === */
#define BMP280_CTRLMEAS_REG             0xF4
#define BMP280_CONFIG_REG               0xF5/* === 数据寄存器 === */
#define BMP280_PRESSURE_MSB_REG         0xF7   // 连续读 6 字节: P(3) + T(3)/* === 电源模式 === */
#define BMP280_SLEEP_MODE               (0x00)
#define BMP280_FORCED_MODE              (0x01)
#define BMP280_NORMAL_MODE              (0x03)/* === 过采样设置 === */
#define BMP280_OVERSAMP_1X              (0x01)
#define BMP280_OVERSAMP_2X              (0x02)
#define BMP280_OVERSAMP_4X              (0x03)
#define BMP280_OVERSAMP_8X              (0x04)
#define BMP280_OVERSAMP_16X             (0x05)/* === 校准参数结构体 === */
typedef struct
{uint16_t dig_T1;int16_t  dig_T2;int16_t  dig_T3;uint16_t dig_P1;int16_t  dig_P2;int16_t  dig_P3;int16_t  dig_P4;int16_t  dig_P5;int16_t  dig_P6;int16_t  dig_P7;int16_t  dig_P8;int16_t  dig_P9;int32_t  t_fine;
} BMP280_Calib_TypeDef;/* === 外部接口 === */
uint8_t BMP280_Init(void);
void BMP280GetData(float* pressure, float* temperature, float* asl);#endif /* __BMP280_H */

2.3 main

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "BMP280.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
float pressure, temperature, altitude;
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_I2C1_Init();/* USER CODE BEGIN 2 */if (BMP280_Init() == 0) {printf("BMP280 Init Failed!\r\n");while (1);}printf("BMP280 Init OK!\r\n");/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */BMP280GetData(&pressure, &temperature, &altitude);printf("Temp: %.2f C, Pressure: %.2f KPa, Altitude: %.2f m\r\n",temperature, pressure, altitude);HAL_Delay(1000);}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

3 实验结果

        通过串口打印出通过BMP280测量到的温度、压强、海拔高度如上所述,其温度偏高,下图位使用ATH20温湿度传感器测量的值与之对比,结果如下

http://www.xdnf.cn/news/1444933.html

相关文章:

  • 【超详细】别再看零散的教程了!一篇搞定Gitee从注册、配置到代码上传与管理(内含避坑指南最佳实践)
  • PS大神级AI建模技巧!效率翻倍工作流,悄悄收藏!
  • Wan系列模型解析--详细架构图
  • 机器学习在Backtrader多因子模型中的应用
  • 美团龙猫利用expat库实现的保存xml指定范围数据到csv的C程序
  • TypeScript 泛型入门(新手友好、完整详解)
  • XSENS VISION NAVIGATOR助力智能城市自动化清洁机器人精确导航
  • TLSF内存算法适配HTOS
  • 【Unity UGUI Canvas(画布)(1)】
  • 【音视频】FMP4 介绍
  • 【正点原子K210连载】第三十一章 音频FFT实验 摘自【正点原子】DNK210使用指南-CanMV版指南
  • 【论文阅读】-《THE JPEG STILL PICTURE COMPRESSION STANDARD》
  • Android 接入deepseek
  • 关于ES中文分词器analysis-ik快速安装
  • k8s使用StatefulSet(有状态)部署单节点 MySQL方案(使用本地存储)
  • 【Bug】Nexus无法正常启动的五种解决方法
  • SuperMap GIS基础产品FAQ集锦(20250901)
  • Elasticsearch 数字字段随机取多值查询缓慢-原理分析与优化方案
  • 504 Gateway Timeout:服务器作为网关或代理时未能及时获得响应如何处理?
  • 揭秘设计模式:优雅地为复杂对象结构增添新功能-访问者模式
  • go语言面试之Goroutine详解
  • Linux使用-Linux系统管理
  • WPF里的几何图形Path绘制
  • 硬件驱动C51单片机——裸机(1)
  • 三、Scala方法与函数
  • 【面试场景题】1GB 大小HashMap在put时遇到扩容的过程
  • 安卓系统中IApplicationThread.aidl对应的是哪个类
  • 智慧交通管理信号灯通信4G工业路由器应用
  • 【小白笔记】移动硬盘为什么总比电脑更容易满?
  • 【LeetCode热题100道笔记】括号生成