[Arduino资料] 零知开源——STM32F1驱动BMP581压强传感器使用SPI实现ST7789显示的环境监测系统

[复制链接]
 楼主| lingzhiLab 发表于 2025-7-3 16:23 | 显示全部楼层 |阅读模式
本帖最后由 lingzhiLab 于 2025-7-3 16:26 编辑
​✔零知开源是一个真正属于国人自己的开源软硬件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!

✔访问零知开源平台,获取更多实战项目和教程资源吧!
www.lingzhilab.com


(1)项目概述
        本文将详细介绍如何在零知标准板上实现BMP581气压传感器与ST7789显示屏的协同工作,重点解决SPI总线冲突问题,并展示环境数据的实时监测显示。实现以下系统功能:
        >实时采集温度和气压数据
        >计算并显示海拔高度
        >在240x320彩色显示屏上直观展示数据
        >通过串口输出监测数据

(2)项目难点
当两个SPI设备共享总线时,会产生总线竞争导致通信失败。本文将重点介绍两种解决方案。

(3)解决思路
方案一:将显示屏改为软件SPI驱动,与传感器的硬件SPI物理隔离。
方案二:通过精确控制CS引脚状态,确保同一时间只有一个设备使用SPI总线。


一、硬件准备与连接
1.1 硬件清单
组件 型号 数量
主控板 零知标准板 1
气压温度传感器 BMP581 1
显示屏 ST7789 (240x320)1
杜邦线 公对公 若干


1.2 接线方案
零知标准板(STM32F103RBT6)BMP581(硬件SPI) ST7789(软件SPI)
3.3VVCC
VCC
GND GND  GND
10 CS /
11(MOSI) SDA /
12(MISO) SDO /
13(SCK) SCL  /
6 / CS
2 / DC
8 / SDA
4 / SCL
7 / RES

1.3 硬件连线图
2025-07-03 093044.png


1.4 接线实物图
20192a0c-508a-414a-b554-39cdf09286b1.jpg


二、完整代码实现         

采取软件SPI替换ST7789的通信方式解决总线冲突的方案,确保零知IDE包含以下库文件:
        SparkFun_BMP581_Arduino_Library.h
        Adafruit_GFX.h
        Adafruit_ST7789.h
        SPI.h

2.1 初始化定义        

定义显示屏和BMP581气压传感器驱动的相关参数
  1. // BMP581 SPI通信参数
  2. uint8_t bmp581_cs = 10;  // BMP581 片选引脚
  3. uint32_t clockFrequency = 100000;  // 设置SPI时钟频率

  4. // ST7789 显示屏引脚定义
  5. #define TFT_CS   6  // 设置软件SPI的片选引脚
  6. #define TFT_RST  4   // 显示屏复位引脚
  7. #define TFT_DC   2  // 显示屏数据/控制命令引脚
  8. #define TFT_MOSI 8  // 软件SPI的MOSI引脚
  9. #define TFT_SCLK 7  // 软件SPI的SCK引脚

  10. // 传感器和显示屏的对象创建与初始化
  11. BMP581 pressureSensor;
  12. Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

  13. // 定义显示屏参数
  14. #define SCREEN_WIDTH  240
  15. #define SCREEN_HEIGHT 320
  16. #define ST77xx_PURPLE 0x862F
  17. #define VALUE_SIZE    3
  18. #define LABEL_SIZE    1

  19. // 颜色定义
  20. #define BACKGROUND  ST77XX_BLACK
  21. #define TEXT_COLOR  ST77XX_WHITE
  22. #define TEMP_COLOR  ST77xx_PURPLE
  23. #define PRESS_COLOR ST77XX_CYAN
  24. #define ALT_COLOR   ST77XX_GREEN
  25. #define BOX_COLOR   ST77XX_ORANGE


2.2 初始化配置      

配置串口通信波特率为115200,ST7789显示屏大小、方向和交互内容显示,开启BMP581的SPI通信连接,绘制显示屏标题和数据内容标签
  1. void setup() {
  2.     // 开启串口监视器并设置波特率为115200
  3.     Serial.begin(115200);
  4.     Serial.println("BMP581 with ST7789 Display Example");

  5.     // 初始化SPI
  6.     SPI.begin();

  7.     // 初始化显示屏
  8.     tft.init(SCREEN_WIDTH, SCREEN_HEIGHT);
  9.     tft.setRotation(3);
  10.     tft.fillScreen(BACKGROUND);
  11.     tft.setTextColor(TEXT_COLOR);

  12.     // 初始化BMP581传感器
  13.     while (pressureSensor.beginSPI(bmp581_cs, clockFrequency) != BMP5_OK) {
  14.         Serial.println("Error: BMP581 not connected, check wiring and CS pin!");
  15.         tft.setCursor(10, 10);
  16.         tft.setTextSize(2);
  17.         tft.print("Sensor not found!");
  18.         delay(1000);
  19.         tft.fillScreen(BACKGROUND);
  20.     }

  21.     Serial.println("BMP581 connected!");
  22.     drawStaticElements();
  23. }

2.3 读取传感器数据        

loop函数循环获取实时的大气压强和温度数据,并通过经验公式转换为海拔高度数据,将获得的数据实时更新到TFT显示屏界面上
  1. void loop() {
  2.     // 从寄存器获取到数值
  3.     bmp5_sensor_data data = {0, 0};
  4.     int8_t err = pressureSensor.getSensorData(&data);

  5.     if (err == BMP5_OK) {
  6.         // 将气压数据转换以百帕为单位 (1 hPa = 100 Pa)
  7.         float pressure_hPa = data.pressure / 100.0;

  8.         // 使用经验公式计算海拔高度数据
  9.         float altitude = (1013.25 - pressure_hPa) / 12 * 100;

  10.         // 更新屏幕
  11.         updateTextDisplay(data.temperature, pressure_hPa, altitude);

  12.         // 打印串口监视数据
  13.         Serial.print("Temperature (C): ");
  14.         Serial.print(data.temperature);
  15.         Serial.print("\tPressure (hPa): ");
  16.         Serial.print(pressure_hPa);
  17.         Serial.print("\tAltitude (m): ");
  18.         Serial.println(altitude);
  19.     } else {
  20.         Serial.print("Error getting data from sensor! Error code: ");
  21.         Serial.println(err);
  22.     }

  23.     delay(1000);  // 每秒更新一次数据
  24. }

2.4 UI界面更新
  1. void drawStaticElements() {
  2.   tft.fillScreen(BACKGROUND);
  3.   
  4.   // 绘制标题
  5.   tft.setTextSize(1);
  6.   tft.setTextColor(ST77XX_YELLOW);
  7.   tft.setCursor(SCREEN_WIDTH/2 + 120, 10);
  8.   tft.print("BMP581 SENSOR");
  9.   
  10.   // 绘制温度数据容器
  11.   drawDataBox(30, 10, "TEMPERATURE", "(C)", TEMP_COLOR);
  12.   
  13.   // 绘制气压数据容器
  14.   drawDataBox(30, 90, "PRESSURE", "(hPa)", PRESS_COLOR);
  15.   
  16.   // 绘制海拔数据容器
  17.   drawDataBox(30, 170, "ALTITUDE", "(m)", ALT_COLOR);
  18. }

  19. void drawDataBox(int x, int y, const char* label, const char* unit, uint16_t color) {
  20.     // 绘制数据容器
  21.     tft.drawRoundRect(x, y, SCREEN_WIDTH - 60, 60, 10, BOX_COLOR);

  22.     // 绘制数据标题
  23.     tft.setTextSize(LABEL_SIZE);
  24.     tft.setTextColor(color);
  25.     tft.setCursor(x + 15, y + 10);
  26.     tft.print(label);

  27.     // 绘制数据单位
  28.     tft.setTextSize(LABEL_SIZE - 1);
  29.     tft.setCursor(x + SCREEN_WIDTH - 60 - 40, y + 10);
  30.     tft.print(unit);
  31. }

  32. void updateTextDisplay(float temp, float pressure, float altitude) {
  33.   updateDataValue(30, 10, temp, 1, TEMP_COLOR);  // 更新温度数据
  34.   updateDataValue(30, 90, pressure, 1, PRESS_COLOR);  // 更新气压数据
  35.   updateDataValue(30, 170, altitude, 1, ALT_COLOR);  // 更新海拔数据
  36. }

  37. void updateDataValue(int x, int y, float value, int decimals, uint16_t color) {
  38.     // 清除旧数据
  39.     tft.fillRect(x + 10, y + 30, SCREEN_WIDTH - 80, 25, BACKGROUND);

  40.     // 写入新数据
  41.     tft.setTextSize(VALUE_SIZE);
  42.     tft.setTextColor(color);
  43.     tft.setCursor(x + 15, y + 30);
  44.     tft.print(value, decimals);
  45. }

2.5 项目完整代码获取
通过网盘分享的文链接:
https://pan.baidu.com/s/125lFvyjRd98dkqMkYh0TSA?pwd=d4m4

三、实际效果展示

3.1 显示屏信息解读

成功运行后,显示屏将分为三个区域显示:
  • 温度区:灰色标签,显示摄氏度
  • 气压区:红色标签,显示百帕
  • 海拔区:紫色标签,显示米

3.2 视频演示效果

将通过传感器获取到的气压值与app海拔仪气压值进行对比

3.3 串口监视器数据

同时,串口监视器将每秒输出一次数据:

uart.png


四、SPI冲突解决方案详解

4.1 问题现象       
当BMP581和ST7789共享硬件SPI总线时:显示屏无法正常显示,传感器数据读取不稳定,系统可能完全无法工作

4.2 根本原因

​SPI总线需要独占访问
两个设备共享MOSI、MISO、SCK信号线
片选(CS)信号控制不足
总线竞争导致数据冲突

4.3 方案一

软件SPI驱动显示屏:将显示屏改为软件SPI驱动,与传感器的硬件SPI物理隔离。
  1. // ST7789使用软件SPI
  2. #define TFT_CS   6  // 显示屏片选
  3. #define TFT_RST  4  // 复位引脚
  4. #define TFT_DC   2  // 数据/命令选择
  5. #define TFT_MOSI 8  // 软件SPI数据引脚
  6. #define TFT_SCLK 7  // 软件SPI时钟引脚

  7. // 创建显示屏对象(使用软件SPI)
  8. Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
优势:

  • 完全避免硬件SPI冲突
  • 简化编程逻辑
  • 更稳定的通信表现
  • 灵活的引脚分配


4.4 方案二
共享SPI总线+显式CS控制:通过精确控制CS引脚状态,确保同一时间只有一个设备使用SPI总线。
  1. // BMP581 SPI参数
  2. uint8_t bmp581_cs = 10;  // BMP581芯片选择引脚
  3. uint32_t clockFrequency = 100000;  // BMP581的SPI时钟频率

  4. // ST7789显示屏引脚配置
  5. #define TFT_CS   6  // 显示屏芯片选择引脚(与BMP581不同)

  6. Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);   //使用硬件SPI驱动方式

  7. void setup() {
  8.     // ...其他初始化...
  9.    
  10.     // 初始化CS引脚
  11.     pinMode(TFT_CS, OUTPUT);
  12.     digitalWrite(TFT_CS, HIGH);  // 初始取消选择显示屏
  13.     pinMode(bmp581_cs, OUTPUT);
  14.     digitalWrite(bmp581_cs, HIGH);  // 初始取消选择传感器
  15. }

  16. void loop() {
  17.     // 读取传感器数据
  18.     digitalWrite(TFT_CS, HIGH);  // 取消选择显示屏
  19.     err = pressureSensor.getSensorData(&data);
  20.     digitalWrite(bmp581_cs, HIGH);  // 取消选择传感器
  21.    
  22.     // 更新显示
  23.     digitalWrite(bmp581_cs, HIGH);  // 确保传感器已取消选择
  24.     updateTextDisplay(...);
  25. }
关键点:
  • 通信前确保另一个设备被取消选择
  • 通信后立即取消选择当前设备
  • 初始化时所有CS引脚设为HIGH
  • 软件SPI的MOSI和SCK引脚共用,片选(CS)引脚需要单独设置

五、海拔计算与精度说明
代码中使用简化的海拔计算公式:
float altitude = (1013.25 - pressure_hPa) / 12 * 100;

计算原理
1013.25 hPa:标准海平面气压
气压梯度:每下降12 hPa,海拔升高约100米

精度考虑 ,实际测量中可能存在10-50米的误差,主要因素包括:
  • 当地气象条件变化
  • 温度对气压的影响
  • 传感器本身的测量误差
  • 公式本身的近似性

六、常见问题解决

1.显示屏白屏或花屏
        检查RES引脚连接
        确认软件SPI引脚配置正确
        尝试降低软件SPI速度
                在tft.init()后添加tft.setSPISpeed(10000000)

2.传感器读取失败
        检查硬件SPI连接
        确保CS引脚配置正确
        测量传感器供电电压(应为3.3V)

3.数据显示异常
        检查引脚定义是否正确
        确认显示屏旋转方向设置合适
        验证传感器数据在串口的输出是否正常

七、方案对比与选择建议
特性
方案一(软件SPI)
方案二(硬件SPI+CS控制)
实现难度
简单 ★☆☆
中等 ★★☆
稳定性
高 ★★★
中 ★★☆
性能
中 ★★☆
高 ★★★
资源占用
较高(需要额外引脚)
低(共享SPI引脚)
推荐场景
初学者/快速实现
高性能应用/引脚受限
推荐选择:
  • 对于大多数应用,方案一(软件SPI驱动显示屏) 是更简单可靠的选择
  • 只有在需要高速刷新或引脚资源紧张时才考虑方案二



八、总结

本文详细介绍了在零知增强板上实现BMP581传感器与ST7789显示屏协同工作的完整过程,重点解决了SPI总线冲突问题。关键点包括:

  • 硬件连接:正确连接SPI设备,特别是CS引脚
  • SPI冲突解决:
        推荐方案:使用软件SPI驱动显示屏
        备选方案:共享硬件SPI+精确CS控制


  • 数据采集与显示:实时获取环境数据并直观展示
  • 海拔计算:使用简化公式计算海拔高度

通过本教程,开发者可以快速构建稳定可靠的环境监测系统,更多零知开发教程:
https://www.lingzhilab.com/freesources.html


您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

33

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

22

主题

33

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部