尧图精选

CH32F103+BMP280+OLED:I2C总线气象站驱动开发全解析

🕒 发布时间:2026/9/9 20:04:39 📁 来源:尧图网络
简介CH32F103C8T6与BMP280气压传感器、0.96英寸OLED屏组成的嵌入式实训项目采用沁恒RISC-V架构MCU通过PB5/PB6的I2C接口读取BMP280的压强、海拔与芯片温度数据再借助PB10/PB11的I2C链路输出至OLED显示。资源适合单片机入门者、传感器应用开发及CH32系列移植学习完整演示了MCU上电初始化、I2C时序配置、数据换算与显示刷新流程。压缩包共168个文件涵盖C源程序、头文件、MDK工程配置uvprojx/uvoptx、编译中间文件.o/.axf/.hex以及链接脚本和调试描述文件整体4.63MB方便随时打开工程对照阅读。已有162人学习下载具备一定参考热度。资源内含可直接烧录的HEX固件、标准外设库驱动、OLED字模与绘图函数并对I2C读写时序做了关键注释便于二次开发或改接其他传感器。其中OLED驱动基于SSD1306控制器BMP280的压强换算已嵌入代码注释清晰整体代码既可用于课程实验也可作为毕业设计或技能竞赛的基础模板。 把CH32F103C8T6、BMP280和一块0.96寸OLED屏放在同一条I2C总线上能玩出不少东西。最简单的就是桌面小气象站实时显示温度、气压顺便用气压换算海拔复杂点可以做成低空高度计、环境监测节点或者干脆当传感器调试底板。这套组合最吸引人的地方在于总成本不到二十块钱却把单片机最小系统、I2C通信、传感器读取、显示驱动、浮点运算全串起来了非常适合入门嵌入式驱动开发的新手也适合想快速做原型的工程师。需要先说清楚CH32F103C8T6是沁恒基于ARM Cortex-M3内核的MCU48脚封装64KB Flash、20KB RAM管脚兼容STM32F103C8T6BMP280是博世的气压温度传感器0.96寸OLED多数是SSD1306驱动、I2C接口。下面我会从选型思路、硬件接线、驱动实现、代码走读、踩坑排查一条线讲完内容偏向可以直接抄作业的那种遇到问题的朋友也可以直接跳到第5节查表。1. 项目整体设计与选型思路1.1 这套组合能做什么我最初搭这个项目纯粹是想给手头的板子加一个可视化环境参数输出。BMP280能输出大气压和温度气压数据再经过标准大气公式换算就能得到海拔。OLED屏实时把这些数字显示出来不需要接串口线、不需要上位机通电就能看放在桌面当个小仪表非常合适。往深了说这个组合的关键价值在于它把嵌入式最常用的几个模块都包含了通过I2C总线访问外部设备、读取带校准参数的传感器、操作点阵屏显存、处理浮点换算。做完这个项目你基本就掌握了I2C设备的通用调试套路后面换SHT30、换MPU6050套路是完全一样的。1.2 为什么用CH32F103C8T6而不是STM32F103C8T6选CH32F103C8T6最现实的原因是价格和供货。STM32F103C8T6近几年价格起伏很大而CH32F103C8T6一直保持在两三块钱的水平开发板也便宜坏了不心疼。它的内核同样是Cortex-M3主频72MHzFlash/RAM容量和F103C8T6一致大部分引脚可以直接替换。需要注意一个容易踩的坑CH32F103虽然标称兼容STM32F103但它的外设寄存器和中断向量并非100%一致。网上大量“STM32CubeMX生成工程 HAL库驱动OLED”的代码不能直接迁移到CH32上因为官方没有完整提供我们熟悉的HAL库。我的做法是驱动SSD1306的显示逻辑代码可以照搬但I2C底层自己写主动权掌握在自己手里。1.3 传感器和屏幕的选型考量BMP280和BME280之间我选了BMP280理由很简单BME280多了湿度检测单价贵将近一倍在这个项目里湿度不是刚需。BMP280气压量程300到1100hPa相对精度在±0.12hPa左右温度精度大约±0.5℃实际做桌面气象显示完全够用绝对精度比DHT11那种温湿度模块高一个量级。0.96寸OLED选择更要注意。市面上同一尺寸常见两种一种是4针I2C接口一种是7针SPI接口。I2C版只需要接VCC、GND、SCL、SDA四根线省IO适合这个项目。SSD1306驱动分辨率128x64关键参数是工作电压3.3V到5V都能接受但内部逻辑电平看模块设计我在项目里统一使用3.3V供电最稳。2. 硬件连接与关键电气细节2.1 引脚分配与接线表这里用I2C1引脚是PB6和PB7。BMP280和OLED都挂在这组引脚上共享总线不需要额外片选。以下是完整接线表外设引脚连接目标说明CH32F103C8T63.3VBMP280 VCC、OLED VCC统一3.3V供电CH32F103C8T6GNDBMP280 GND、OLED GND共地CH32F103C8T6PB6BMP280 SCL、OLED SCL接4.7k上拉到3.3VCH32F103C8T6PB7BMP280 SDA、OLED SDA接4.7k上拉到3.3VCH32F103C8T6PB5OLED RES可选软件复位控制不接地BMP280SDOGND设置I2C地址为0x76OLEDSA0GND或悬空设置I2C地址为0x3C2.2 上拉电阻、供电和复位问题I2C总线必须要有上拉电阻。市售的BMP280模块和OLED模块板载一般已经焊了4.7k或10k上拉如果你用的是裸屏或裸传感器需要在SCL和SDA上各接一个4.7k电阻到3.3V。没有上拉的直接表现是I2C通信完全无应答用示波器看波形时钟线能拉低但拉不高。供电方面建议全部用3.3V不要贪图OLED模块支持5V就给板子直接供5V。CH32F103C8T6本身就要3.3VUSB转串口模块或者开发板上的LDO供电能力足够整套系统工作电流大概在20到40mA之间BMP280测量时电流很小OLED点亮后会多一些。还有一个细节是OLED的RES脚。很多I2C模块把RES脚引出来了但不接也行内部有上电复位。但如果你发现屏幕偶尔花屏最好把RES接到一个普通GPIO我用PB5初始化时先拉低50ms再拉高能有效解决上电时序不确定的问题。我实测过裸屏和带板载电路的模块对这个脚的反应差别很大。2.3 硬件上的几个容易搞错的地方第一BMP280的I2C地址由SDO引脚决定接GND是0x76接VCC是0x77。大部分模块默认已经拉低但如果你用的是自己画的板子或者拆机芯片地址不确定扫描总线时可能会找不到设备。第二OLED的I2C地址由SA0决定默认0x3C部分模块是0x3D。第三千万别把SPI版的7针OLED接成I2C模式板子上的CS、DC、RES脚定义完全不同强行接线大概率烧驱动芯片或一直白屏。3. 软件驱动实现与工程搭建3.1 I2C底层硬件I2C还是软件模拟这个项目里我建议直接上软件模拟I2C不为别的就为代码可控、问题好查。CH32F103的硬件I2C在兼容STM32F103时有一些寄存器和时序差异而且网上绝大多数HAL库写法不能直接套用。软件模拟I2C虽然多占一点CPU但读一次BMP280加刷新一次OLED总耗时在几十毫秒量级对这种显示类应用毫无压力。软件模拟I2C的核心只需要四个函数起始信号、停止信号、发送一个字节、读取一个字节。SCL和SDA都用开漏输出加外部上拉代码里用一个宏切换输入输出方向。网上有很多现成实现但有一点要记住数据线SDA的电平变化必须发生在SCL低电平期间否则会被总线识别为起始或停止信号。如果非要用硬件I2C建议参考官方例程而非STM32的HAL库而且需要重点检查I2C事件中断和出错中断的处理逻辑。图省事的朋友就老实软件模拟功能完全够。3.2 BMP280读取与校准补偿公式BMP280出厂时每颗芯片的传感器特性都不一样所以芯片内部固化了一组校准系数地址从0x88到0xA1。上电后必须先把这些系数读出来再结合ADC原始值进行温度、气压补偿计算。关键寄存器如下寄存器地址名称作用0xD0ID芯片ID固定0x580xF4ctrl_meas设置工作模式、过采样率0xF5config设置滤波器、测量周期0xF7press_msb气压ADC值高字节0xFAtemp_msb温度ADC值高字节我的初始化序列是这样先读ID寄存器确认是0x58然后写0xF4寄存器为0x27也就是正常模式、温度过采样x1、气压过采样x1写0xF5为0xA0打开IIR滤波器系数4这样气压读数会更平滑。然后等待测量完成通常几毫秒就行。温度补偿公式网上很多我直接贴关键代码int32_t t_fine; int32_t bmp280_compensate_T(int32_t adc_T) { int32_t var1, var2, T; var1 (((adc_T 3) - ((int32_t)dig_T1 1)) * (int32_t)dig_T2) 11; var2 (((((adc_T 4) - (int32_t)dig_T1) * ((adc_T 4) - (int32_t)dig_T1)) 12) * (int32_t)dig_T3) 14; t_fine var1 var2; T (t_fine * 5 128) 8; return T; // 单位 0.01℃ }气压补偿公式更长包含dig_P1到dig_P9九个系数核心思路是先用温度补偿量t_fine修正气压值再经过高精度定点运算还原成0.01hPa单位。具体公式我建议直接参考博世官方数据手册附录网上也有大量代码注意变量类型要用int32_t或int64_t否则中间溢出会得到完全离谱的气压值。3.3 SSD1306 OLED显示与汉字取模OLED的本质是自发光像素点阵这也就是热搜里常问的“像素点由几层组成”答案每个像素是一颗有机发光二极管不需要背光层因此显示黑色区域是真的不发光功耗比LCD低。SSD1306内部有1KB显存对应128x64分辨率每8行像素为一页共8页。初始化SSD1306时要特别留意打开电荷泵命令是0x8D、0x14。很多人问“OLED屏连上电源就亮吗”答案是通电后如果不发初始化命令屏幕可能一直黑着因为驱动芯片默认关闭显示。完整的初始化序列大概是关闭显示、设置时钟分频、设置复用率、设置偏移、打开电荷泵、设置内存地址模式为水平模式、设置列地址和页地址范围、退出水平滚动、打开显示。显存buffer建议在内存里维护一个128x8字节数组写完数据后一次性通过I2C发送到SSD1306。这里可以把显存想象成画板所有绘图操作都在这个数组上完成最后统一刷屏既能避免闪烁又方便做区域更新。汉字显示是另一个常见需求。OLED显示汉字需要取模我的工具是PCtoLCD2002字模选择16x16像素取模方式选“逐行式”或“列行式”其实都行关键是和你的写入函数对齐。下面是我常用的16x16汉字写入逻辑先把显存坐标换算到页地址再把字模数据逐字节画到buffer上。ASCII字符用8x6字体同样处理只是宽度不一样。4. 完整代码走读与实测数据4.1 主流程与任务调度整个工程不复杂主循环里只有两件大事读取BMP280并计算然后刷新OLED显示。伪代码流程如下int main(void) { SystemInit(); delay_init(); i2c_soft_init(); oled_init(); bmp280_init(); oled_show_string(0, 0, Weather Station); while (1) { bmp280_read_all(temperature, pressure); altitude 44330.0f * (1.0f - pow(pressure / 1013.25f, 0.1903f)); snprintf(buf, sizeof(buf), T:%2.1f C, temperature); oled_show_string(0, 2, buf); snprintf(buf, sizeof(buf), P:%6.1f hPa, pressure); oled_show_string(0, 4, buf); snprintf(buf, sizeof(buf), H:%4.1f m, altitude); oled_show_string(0, 6, buf); oled_refresh(); delay_ms(500); } }实际项目中我每隔500ms更新一次值刷屏频率也是500ms。如果刷得太快一方面软件模拟I2C会把CPU占满另一方面眼皮底下看数据跳动反而不舒服。4.2 显示布局设计OLED分8页每页8像素高总共64像素。我习惯把屏幕横向分成上下两个区域顶部两页显示温度和海拔底部显示气压。字体方面ASCII用8x6字模汉字用16x16字模行距通过页地址控制。一个实用技巧是只刷新变化区域。很多人每次刷屏都重发整个1KB显存其实SSD1306支持设置显示窗口只用改某几页或某几列。我把温度、气压、海拔分别安排在不同页每次只更新对应页的数据视觉上不会出现整屏闪烁。4.3 实测数据与海拔换算室内温度稳定在26.3℃左右气压约1005.2hPa用公式换算海拔约为68米跟我在的城市海拔比较接近。BMP280在没有加入IIR滤波时读数有少量跳变开了滤波后读数平稳很多。但使用标准大气公式时要注意一个坑这个公式是0海拔参考面为1013.25hPa的简化模型实际天气变化会导致气压波动几十百帕算出来的“海拔”也会跟着上下飘。要当高度计用开机时需要手动校准参考气压我通常的做法是把当前实测气压当作当天本地海平面气压存入Flash下次开机直接使用。做桌面气象显示就无所谓了图个参考。5. 常见问题排查与避坑实录5.1 故障速查表现象可能原因排查方法解决措施I2C扫描不到设备接线错误、供电不足、上拉缺失用万用表量VCC/GND、SCL/SDA电压补上拉4.7k确认3.3V供电找不到BMP280SDO引脚地址不对扫描0x76和0x77改SDO电平或改代码地址找不到OLEDSA0地址不对扫描0x3C和0x3D改代码地址屏幕黑屏但有电源未初始化、电荷泵未开启打印初始化命令发0x8D 0x14再发0xAF数据跳动大传感器靠近热源、无滤波加IIR滤波做滑动平均取8到16次平均远离发热器件气压值像乱码校准系数没读对、变量溢出打印dig_T1等系数用int32_t/int64_t别用int16屏幕花屏复位失败、时序不稳定检查RES脚用GPIO控制RES拉低再拉高汉字乱码取模方式和显存写入不对应对照字模看点阵统一取模方式调整坐标对应关系5.2 几个独家心得最后说几个我实际调试中积累的经验。BMP280在室内比DHT11靠谱太多但它也怕风。放在空调风口下或者窗边开窗的瞬间气压能跳2到3hPa。做桌面气象站最好给传感器遮一下或者用海绵垫底做物理隔离。软件模拟I2C的时序不要太快。网上有些代码把延时写得很激进总线上挂着两个设备时过快的边沿会造成应答丢失。我一般把SCL半周期设在2到5微秒稳定优先。等所有功能正常后再尝试提速。OLED屏的对比度命令0x81可以调亮度但别设太高128x64全白时电流会明显增加如果用LDO供电有余量还好电池供电就要注意。我一般设在0x7F左右寿命和功耗都能兼顾。这套方案做完之后扩展其实很顺手。Sensor总线还可以挂上SHT30测湿度OLED空余区域显示想省电就把BMP280改成休眠模式定时唤醒一次整机功耗可以压到毫安以下。CH32F103C8T6的ADC、定时器资源也还闲着后续做报警提示或者按键切页都很方便。我的建议是先把I2C基础打牢再往这个骨架上加东西会越做越顺。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →