STM32F103 驱动 BMP280 气压温湿度传感器 + OLED 显示教程

目录

一、硬件准备与核心原理说明

[✅ 1. 硬件清单(精准罗列,新手无采购误区)](#✅ 1. 硬件清单(精准罗列,新手无采购误区))

[✅ 2. BMP280 传感器核心特点与工作原理](#✅ 2. BMP280 传感器核心特点与工作原理)

[(1)BMP280 核心特性](#(1)BMP280 核心特性)

(2)核心计算公式

[✅ 3. OLED 显示原理](#✅ 3. OLED 显示原理)

二、硬件接线(重中之重,精准无错版)

[✅ 1. 引脚定义说明](#✅ 1. 引脚定义说明)

[(1)BMP280 模块核心引脚(I2C 模式)](#(1)BMP280 模块核心引脚(I2C 模式))

[(2)OLED 模块核心引脚](#(2)OLED 模块核心引脚)

[✅ 2. 完整接线表(STM32F103C8T6,通用无错)](#✅ 2. 完整接线表(STM32F103C8T6,通用无错))

[✅ 接线注意事项(新手必看,避坑指南)](#✅ 接线注意事项(新手必看,避坑指南))

三、软件准备(开发环境配置)

[✅ 1. 开发环境](#✅ 1. 开发环境)

[✅ 2. STM32CubeMX 配置步骤(图文式步骤,零基础能看懂)](#✅ 2. STM32CubeMX 配置步骤(图文式步骤,零基础能看懂))

[步骤 1:新建工程,选择芯片](#步骤 1:新建工程,选择芯片)

[步骤 2:基础配置(必做)](#步骤 2:基础配置(必做))

[步骤 3:配置硬件 I2C1](#步骤 3:配置硬件 I2C1)

[步骤 4:配置系统时钟树](#步骤 4:配置系统时钟树)

[步骤 5:生成工程代码](#步骤 5:生成工程代码)

四、完整代码编写(可直接复制,注释详尽)

[✅ 步骤 1:导入 0.96 寸 OLED 驱动代码](#✅ 步骤 1:导入 0.96 寸 OLED 驱动代码)

[✅ 步骤 2:编写 BMP280 传感器驱动代码(核心)](#✅ 步骤 2:编写 BMP280 传感器驱动代码(核心))

[✅ 代码编译注意事项(新手必看,解决编译报错)](#✅ 代码编译注意事项(新手必看,解决编译报错))

五、程序下载与测试效果

[✅ 1. 编译下载程序](#✅ 1. 编译下载程序)

[✅ 2. 测试效果](#✅ 2. 测试效果)

六、常见问题解决(新手避坑,最全解决方案)

[❌ 问题 1:OLED 屏幕无任何显示](#❌ 问题 1:OLED 屏幕无任何显示)

[❌ 问题 2:BMP280 初始化失败(程序卡死在 while (1))](#❌ 问题 2:BMP280 初始化失败(程序卡死在 while (1)))

[❌ 问题 3:气压数据显示异常(如气压 0hPa)](#❌ 问题 3:气压数据显示异常(如气压 0hPa))

[❌ 问题 4:数据显示乱码、跳动严重](#❌ 问题 4:数据显示乱码、跳动严重)

七、功能扩展(进阶开发,可选)


本文将详细讲解如何使用STM32F103C8T6 单片机,通过I2C 通信方式驱动 BMP280 高精度气压,大气压强数据,并通过算法精准计算海拔高度,最终将所有数据实时显示在 0.96 寸 I2C OLED 屏幕上。教程基于 STM32 HAL 库开发,代码完整可直接复用、步骤清晰易懂、注释详尽,适合零基础入门学习,也可直接用于气象站、高度计、无人机定高、环境监测等嵌入式项目开发。

一、硬件准备与核心原理说明

✅ 1. 硬件清单(精准罗列,新手无采购误区)

器件名称 数量 重要备注
STM32F103C8T6 最小系统板 1 核心主控,本文所有代码基于此型号开发
BMP280 传感器模块 1 数字型传感器,I2C/SPI 双模,本文用 I2C 模式
0.96 寸 I2C OLED 显示屏 1 分辨率 128*64,SSD1306 驱动芯片,4 针款
杜邦线 若干 公对母 / 公对公均可,建议备 10 根以上
5V/3.3V 供电电源 1 USB 数据线供电即可,给 STM32 最小系统板供电

小提示:BMP280 是 BMP180 的升级款,精度更高、功耗更低,两款传感器驱动逻辑类似,本教程代码稍作修改即可兼容 BMP180。

✅ 2. BMP280 传感器核心特点与工作原理

(1)BMP280 核心特性
  • 通信方式:硬件 I2C / SPI 双接口,本教程选用 I2C(两线通信,接线简单,可与 OLED 共用 I2C 引脚);
  • 检测参数:精准温度 + 大气压强(部分商家标注的湿度为模块集成,BMP280 本体只测压);
  • 测量精度:气压 ±1hPa,海拔高度 ±1 米,满足日常 / 项目开发所有需求;
  • 量程范围:气压 300hPa~1100hPa(对应海拔 - 500 米~9000 米);
  • 供电电压:3.3V(推荐),部分模块兼容 5V,建议用 3.3V 和 STM32 电平匹配,避免烧毁传感器;
  • I2C 默认地址:0x76(传感器 SDO 引脚接 GND 时),若 SDO 接 VCC 则地址为0x77
(2)核心计算公式

BMP280 采集的是原始数据,需通过公式换算成实际物理值,所有公式已封装在代码中,无需手动计算:

  1. 气压:基于校准后的温度,补偿计算出实际大气压强(hPa,1hPa=1 百帕 = 100Pa);
  2. 海拔高度:通过当前气压和海平面标准气压(1013.25hPa) 换算,公式如下:海拔当前气压海平面气压

✅ 3. OLED 显示原理

0.96 寸 OLED 屏采用 SSD1306 驱动芯片,同样为 I2C 通信接口,OLED 的默认 I2C 地址为 0x78(部分为 0x7A)

关键优势:BMP280 和 OLED 的 I2C 地址不同,因此可以共用 STM32 的同一个 I2C 外设,仅需 2 根线即可同时驱动两个设备,极大简化硬件接线!

二、硬件接线(重中之重,精准无错版)

✅ 1. 引脚定义说明

(1)BMP280 模块核心引脚(I2C 模式)
  • VCC :供电引脚,接 3.3V(优先推荐);
  • GND :接地引脚,必须和 STM32、OLED 共地;
  • SCL :I2C 时钟线;
  • SDA :I2C 数据线;
  • SDO :I2C 地址配置脚,接 GND 即可,对应地址 0x76;
  • CSB :SPI/I2C 模式选择脚,接 VCC 为 I2C 模式(接 GND 为 SPI 模式,本文不用);
  • SCK/SDI:SPI 引脚,I2C 模式下悬空即可。
(2)OLED 模块核心引脚
  • VCC :3.3V 供电;
  • GND :共地;
  • SCL :I2C 时钟线;
  • SDA :I2C 数据线。

✅ 2. 完整接线表(STM32F103C8T6,通用无错)

本文选用 STM32 的硬件 I2C1 ,引脚为 PB6 = SCLPB7 = SDA,两个设备完全共用这组引脚,接线如下,建议对照接线,避免接错

外设引脚 STM32 引脚 接线说明
BMP280-VCC 3.3V 传感器供电,严禁接 5V 长期使用
BMP280-GND GND 与 STM32、OLED 共地(必须!)
BMP280-SCL PB0 I2C时钟线
BMP280-SDA PB1 I2C数据线
BMP280-SDO GND 配置地址 0x76
BMP280-CSB VCC 启用 I2C 模式
OLED-VCC 3.3V 屏幕供电
OLED-GND GND 共地
OLED-SCL PB6 I2C时钟线
OLED-SDA PB7 I2C数据线

✅ 接线注意事项(新手必看,避坑指南)

  1. 所有设备必须共地,否则 I2C 通信会出现乱码、设备失联等问题;
  2. BMP280 优先接 3.3V,部分 5V 供电的模块内置稳压,但若直接接 5V 可能导致传感器发热、精度下降;
  3. 严禁将 SCL 和 SDA 引脚接反,接反后设备无法通信,OLED 无显示、传感器初始化失败;
  4. 杜邦线尽量短,避免过长导致信号干扰,影响数据稳定性。

三、软件准备(开发环境配置)

✅ 1. 开发环境

  • 图形化配置工具:STM32CubeMX 6.x 版本
  • 编译下载工具:Keil MDK-ARM 5.x 版本
  • 程序下载器:ST-Link(或 USB 转串口,推荐 ST-Link,下载稳定)

✅ 2. STM32CubeMX 配置步骤(图文式步骤,零基础能看懂)

步骤 1:新建工程,选择芯片

打开 STM32CubeMX → 点击Access to MCU Selector → 搜索STM32F103C8T6 → 选中芯片后点击Start Project

步骤 2:基础配置(必做)
  1. 配置 RCC 时钟:点击左侧RCC → 高速外部时钟HSE选择Crystal/Ceramic Resonator(8MHz 晶振);
  2. 配置调试接口:点击左侧SYS → 调试模式选择Serial Wire(SWD),方便后续下载和调试程序。
步骤 3:配置硬件 I2C1
  1. 仅需配置OLED的SDA和SCL、BMP280的SDA和SCL。
步骤 4:配置系统时钟树

将 STM32 系统时钟配置为72MHz(F103 的最大主频,性能最佳):

  • HSE 选择 8MHz → PLL 倍频系数设为 9 → 系统时钟 = 8*9=72MHz;
  • AHB 分频系数 1,APB1 分频系数 2,APB2 分频系数 1;
  • 点击Refresh,确认时钟配置无误,无红色报错。
步骤 5:生成工程代码
  1. 点击顶部Project Manager → 设置工程名称(如BMP280_OLED)、保存路径(路径不能有中文和空格);
  2. 工具链选择MDK-ARM,勾选Generate peripheral initialization as a pair of .c/.h files per peripheral
  3. 点击GENERATE CODE生成代码,生成完成后点击Open Project直接打开 Keil 工程。

四、完整代码编写(可直接复制,注释详尽)

本次代码采用模块化开发,结构清晰,分为三部分:① 导入 OLED 驱动代码 ② 编写 BMP280 驱动代码 ③ 编写主函数实现数据采集与显示,所有代码无冗余,新手可直接复制使用。

✅ 步骤 1:导入 0.96 寸 OLED 驱动代码

0.96 寸 I2C OLED 的驱动基于 SSD1306 芯片,为通用驱动,无需修改,直接在工程中添加两个文件即可:

  1. 在 Keil 工程的Src目录下新建oled.cInc目录下新建oled.h
  2. 将 SSD1306 的 I2C 驱动代码复制到这两个文件中(网上可下载通用版,核心功能:初始化、清屏、显示字符、显示字符串)。

关键提示:OLED 的默认 I2C 地址为0x78,若屏幕无显示,可在 oled.h 中修改为0x7A重试。

✅ 步骤 2:编写 BMP280 传感器驱动代码(核心)

在工程中新建两个文件:bmp280.c(放入 Src 目录)和bmp280.h(放入 Inc 目录),这两个文件是 BMP280 的核心驱动,包含初始化、校准参数读取、温压数据读取、海拔计算等所有功能。

BMP280.c

cs 复制代码
void BMP280GetData(float* pressure,float* temperature,float* asl)
{
    static float t;
    static float p;
	
	bmp280GetPressure();

	t=bmp280CompensateT(bmp280RawTemperature)/100.0;		
	p=bmp280CompensateP(bmp280RawPressure)/25600.0;		

	presssureFilter(&p,pressure);
	*temperature=(float)t;                                                   /*单位度*/
	*pressure=(float)p ;	                                                   /*单位hPa*/	
	
	*asl=bmp280PressureToAltitude(pressure);	                               /*转换成海拔*/	
}

#define CONST_PF 0.1902630958	                                               //(1/5.25588f) Pressure factor
#define FIX_TEMP 25				                                               // Fixed Temperature. ASL is a function of pressure and temperature, but as the temperature changes so much (blow a little towards the flie and watch it drop 5 degrees) it corrupts the ASL estimates.
								                                               // TLDR: Adjusting for temp changes does more harm than good.
/*
 * Converts pressure to altitude above sea level (ASL) in meters
*/
static float bmp280PressureToAltitude(float* pressure/*, float* groundPressure, float* groundTemp*/)
{
    if (*pressure>0)
    {
        return((pow((1015.7f/ *pressure),CONST_PF)-1.0f)*(FIX_TEMP+273.15f))/0.0065f;
    }
    else
    {
        return 0;
    }
}

BMP280.h

cs 复制代码
/**
 ****************************************************************************************************
 * @file        bmp280.h
 * @author      送外卖的工程师
 * @version     V1.0
 * @date        2025-12-27
 * @brief       BMP280驱动代码
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:STM32F103C8T6
 *     CSDN:送外卖的工程师
 * 技术指导VX:wmz14026
 * 淘宝店铺:小马科技
 * 闲鱼店铺:送外卖的工程师
 *
 * 修改说明
 * V1.0.0.251227
 * 第一次发布
 * 注:长期接各种项目设计,提供仿真、实物、原理图、PCB、代码工程、后期指导、操作视频、
   说明文档、各种报告、后期指导等。
 ****************************************************************************************************
 */
#ifndef __BMP280_H
#define __BMP280_H
#include "main.h"
#include "stdbool.h"



//==============================================BMP280硬件接口==================================================
#define		BMP280_IIC_RCC_EN_CLK				__HAL_RCC_GPIOB_CLK_ENABLE();
#define		BMP280_IIC_PORT				        GPIOB
#define		BMP280_IIC_SCL_PIN		            GPIO_PIN_0
#define		BMP280_IIC_SDA_PIN		            GPIO_PIN_1

#define 	BMP280_IIC_SCL(x)				    HAL_GPIO_WritePin(BMP280_IIC_PORT, BMP280_IIC_SCL_PIN,(GPIO_PinState)(x))
#define 	BMP280_IIC_SDA(x)				    HAL_GPIO_WritePin(BMP280_IIC_PORT, BMP280_IIC_SDA_PIN,(GPIO_PinState)(x))
#define 	BMP280_READ_SDA   		            HAL_GPIO_ReadPin(BMP280_IIC_PORT, BMP280_IIC_SDA_PIN)//输入SDA 

//=============================================================================================================


#define BMP280_ADDR						(0xEC)
#define BMP280_DEFAULT_CHIP_ID			(0x58)

#define BMP280_CHIP_ID					(0xD0)                                 /* Chip ID Register */
#define BMP280_RST_REG					(0xE0)                                 /* Softreset Register */
#define BMP280_STAT_REG					(0xF3)                                 /* Status Register */
#define BMP280_CTRL_MEAS_REG			(0xF4)                                 /* Ctrl Measure Register */
#define BMP280_CONFIG_REG				(0xF5)                                 /* Configuration Register */
#define BMP280_PRESSURE_MSB_REG			(0xF7)                                 /* Pressure MSB Register */
#define BMP280_PRESSURE_LSB_REG			(0xF8)                                 /* Pressure LSB Register */
#define BMP280_PRESSURE_XLSB_REG		(0xF9)                                 /* Pressure XLSB Register */
#define BMP280_TEMPERATURE_MSB_REG		(0xFA)                                 /* Temperature MSB Reg */
#define BMP280_TEMPERATURE_LSB_REG		(0xFB)                                 /* Temperature LSB Reg */
#define BMP280_TEMPERATURE_XLSB_REG		(0xFC)                                 /* Temperature XLSB Reg */

#define BMP280_SLEEP_MODE				(0x00)
#define BMP280_FORCED_MODE				(0x01)
#define BMP280_NORMAL_MODE				(0x03)

#define BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG             (0x88)
#define BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH       (24)
#define BMP280_DATA_FRAME_SIZE			(6)

#define BMP280_OVERSAMP_SKIPPED			(0x00)
#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)

//IIC所有操作函数
void BMP_IIC_Init(void);                                                           //初始化IIC的IO口				 
void BMP_IIC_Start(void);				                                           //发送IIC开始信号
void BMP_IIC_Stop(void);	  			                                           //发送IIC停止信号
void BMP_IIC_Send_Byte(uint8_t txd);			                                           //IIC发送一个字节
uint8_t BMP_IIC_Read_Byte(unsigned char ack);                                           //IIC读取一个字节
uint8_t BMP_IIC_Wait_Ack(void); 				                                           //IIC等待ACK信号
void BMP_IIC_Ack(void);					                                           //IIC发送ACK信号
void BMP_IIC_NAck(void);				                                           //IIC不发送ACK信号

void IIC_Write_One_Byte(uint8_t daddr,uint8_t addr,uint8_t data);
uint8_t IIC_Read_One_Byte(uint8_t daddr,uint8_t addr);	
			 
uint8_t iicDevReadByte(uint8_t devaddr,uint8_t addr);	                                       /*读一字节*/
void iicDevWriteByte(uint8_t devaddr,uint8_t addr,uint8_t data);	                           /*写一字节*/
void iicDevRead(uint8_t devaddr,uint8_t addr,uint8_t len,uint8_t *rbuf);                           /*连续读取多个字节*/
void iicDevWrite(uint8_t devaddr,uint8_t addr,uint8_t len,uint8_t *wbuf);                          /*连续写入多个字节*/


bool BMP280Init(void);
void BMP280GetData(float* pressure, float* temperature, float* asl);





#endif

✅ 代码编译注意事项(新手必看,解决编译报错)

编译代码时,新手大概率会遇到 2 个报错,以下是解决方案,必须配置,否则编译失败

  1. 开启微库(Use MicroLIB) :Keil 中点击Options for TargetTarget → 勾选Use MicroLIB,解决sprintf格式化浮点数报错;
  2. 链接数学库 :点击Options for TargetEditorMisc Controls,输入--cpu Cortex-M3 -lm,解决pow(幂函数)、sqrt等数学函数未定义的报错;
  3. 若提示OLED_xxx函数未定义,检查 OLED 驱动文件是否正确添加到工程中,头文件是否包含。

五、程序下载与测试效果

✅ 1. 编译下载程序

  1. 在 Keil 中点击Build编译代码,无报错后点击Download下载程序到 STM32;
  2. 下载完成后,给 STM32 供电,此时 OLED 屏幕会点亮。

✅ 2. 测试效果

  1. OLED 屏幕会显示标题、实时大气压强,显示稳定;
  2. 抬起传感器,海拔高度会增加,放下则减少,数据变化符合实际物理规律;
  3. 正常环境下,气压值在 1000~1020hPa 之间,海拔根据当地实际高度显示。

六、常见问题解决(新手避坑,最全解决方案)

这部分是重中之重,新手在调试时大概率会遇到以下问题,所有问题均为实测中出现的高频问题,解决方案精准有效:

❌ 问题 1:OLED 屏幕无任何显示

  1. 检查 OLED 的 VCC 和 GND 是否接对,确保 3.3V 供电正常;
  2. 确认 OLED 的 I2C 地址是0x78还是0x7A,在 oled.h 中修改地址重试;
  3. 检查 SCL 和 SDA 引脚是否接反,PB6=SCL,PB7=SDA,接反后无显示;
  4. 所有设备必须共地,无共地则 I2C 通信失败。

❌ 问题 2:BMP280 初始化失败(程序卡死在 while (1))

  1. 传感器供电问题:BMP280 必须接 3.3V,接 5V 可能导致传感器烧毁,无法通信;
  2. I2C 地址错误:SDO 接 GND 地址是 0x76(写地址 0xEE),接 VCC 是 0x77(写地址 0xF0),在 bmp280.h 中修改地址;
  3. SCL/SDA 引脚接反,或传感器未共地;
  4. 传感器硬件损坏:更换 BMP280 模块重试。

❌ 问题 3:气压数据显示异常(如气压 0hPa)

  1. 未读取校准参数:BMP280 必须读取校准参数才能计算出正确数据,检查代码;
  2. 传感器未进入工作模式:检查BMP280_CTRL_MEAS寄存器的配置值是否为 0x77;
  3. 数据读取顺序错误:BMP280 的温压数据是 6 个字节,必须按顺序读取,不能拆分。

❌ 问题 4:数据显示乱码、跳动严重

  1. 杜邦线过长,导致信号干扰,更换短的杜邦线;
  2. 电源纹波过大,给传感器的 VCC 引脚并联一个 0.1μF 的滤波电容;
  3. 延时时间过短,增大HAL_Delay(200)的数值,降低刷新频率。

七、功能扩展(进阶开发,可选)

本教程实现了基础的气压采集与显示,可根据需求轻松扩展以下功能,适合项目升级:

  1. 串口打印数据:添加 USART 串口配置,将气压数据通过串口打印到电脑串口助手,便于数据记录;
  2. 气压预警功能:当气压低于 980hPa 时,通过 GPIO 控制 LED 闪烁,实现低气压预警;
  3. 多传感器联合采集:搭配 DHT11/DHT22 温湿度传感器,同时显示温度、湿度、气压、海拔,打造完整气象站。
相关推荐
2501_927773072 小时前
嵌入式51单片机——中断
stm32·单片机·嵌入式硬件
玩转以太网2 小时前
WIZnet以太网单片机选型指南
单片机·嵌入式硬件·以太网
tianyazhichiC3 小时前
stm32f103 标准外设库下载
stm32·单片机·嵌入式硬件
专业开发者3 小时前
NXP解析蓝牙 ® 声道探测技术将如何赋能汽车数字钥匙
人工智能·物联网·汽车
小美单片机4 小时前
Proteus 报错 Unable to open HEX file ‘..\1、程序\jio\jtd.hex‘. [U1]
c语言·单片机·嵌入式硬件·51单片机·proteus
乡野码圣4 小时前
【RK3588 Android12】固件烧录与启动
stm32·单片机·嵌入式硬件
灵哎惹,凌沃敏4 小时前
一句话总结IIC协议
arm开发·单片机·开源协议
2401_863318634 小时前
基于单片机的温度控制系统的设计
单片机·嵌入式硬件