TA的每日心情  | 奋斗 2025-7-11 08:33 | 
|---|
 
  签到天数: 2 天 连续签到: 1 天 [LV.1]初来乍到 
举人 
 
 
	- 积分
 - 511
 
 
 
 
 | 
 
 
 本帖最后由 eefocus_4087784 于 2025-7-3 18:31 编辑  
 
??零知开源是一个真正属于国人自己的开源软硬件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧! 
 
 (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.3V  | VCC  | VCC  |  GND  | GND  | GND  |  10  | CS  | /  |  11(MOSI)  | SDA  | /  |  12(MISO)  | SDO  | /  |  13(SCK)  | SCL  | /  |  6  | /  | CS  |  2  | /  | DC  |  8  | /  | SDA  |  7  | /  | SCL  |  4  | /  | RES  |  
  
1.3 硬件连线图 
 
 
1.4 接线实物图 
 
 
 二、完整代码实现  采取软件SPI替换ST7789的通信方式解决总线冲突的方案,确保零知IDE包含以下库文件: 
    SparkFun_BMP581_Arduino_Library.h 
    Adafruit_GFX.h 
    Adafruit_ST7789.h 
    SPI.h  
  2.1 初始化定义    
定义显示屏和BMP581气压传感器驱动的相关参数 
// BMP581 SPI通信参数 
uint8_t bmp581_cs = 10;  // BMP581 片选引脚 
uint32_t clockFrequency = 100000;  // 设置SPI时钟频率 
 
// ST7789 显示屏引脚定义 
#define TFT_CS   6  // 设置软件SPI的片选引脚 
#define TFT_RST  4   // 显示屏复位引脚 
#define TFT_DC   2  // 显示屏数据/控制命令引脚 
#define TFT_MOSI 8  // 软件SPI的MOSI引脚 
#define TFT_SCLK 7  // 软件SPI的SCK引脚 
 
// 传感器和显示屏的对象创建与初始化 
BMP581 pressureSensor; 
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); 
 
// 定义显示屏参数 
#define SCREEN_WIDTH  240 
#define SCREEN_HEIGHT 320 
#define ST77xx_PURPLE 0x862F 
#define VALUE_SIZE    3 
#define LABEL_SIZE    1 
 
// 颜色定义 
#define BACKGROUND  ST77XX_BLACK 
#define TEXT_COLOR  ST77XX_WHITE 
#define TEMP_COLOR  ST77xx_PURPLE 
#define PRESS_COLOR ST77XX_CYAN 
#define ALT_COLOR   ST77XX_GREEN 
#define BOX_COLOR   ST77XX_ORANGE  
2.2 初始化配置   
配置串口通信波特率为115200,ST7789显示屏大小、方向和交互内容显示,开启BMP581的SPI通信连接,绘制显示屏标题和数据内容标签 
- void setup() {
 
 -     // 开启串口监视器并设置波特率为115200
 
 -     Serial.begin(115200);
 
 -     Serial.println("BMP581 with ST7789 Display Example");
 
  
-     // 初始化SPI
 
 -     SPI.begin();
 
  
-     // 初始化显示屏
 
 -     tft.init(SCREEN_WIDTH, SCREEN_HEIGHT);
 
 -     tft.setRotation(3);
 
 -     tft.fillScreen(BACKGROUND);
 
 -     tft.setTextColor(TEXT_COLOR);
 
  
-     // 初始化BMP581传感器
 
 -     while (pressureSensor.beginSPI(bmp581_cs, clockFrequency) != BMP5_OK) {
 
 -         Serial.println("Error: BMP581 not connected, check wiring and CS pin!");
 
 -         tft.setCursor(10, 10);
 
 -         tft.setTextSize(2);
 
 -         tft.print("Sensor not found!");
 
 -         delay(1000);
 
 -         tft.fillScreen(BACKGROUND);
 
 -     }
 
  
-     Serial.println("BMP581 connected!");
 
 -     drawStaticElements();
 
 - }
 
 
  复制代码 
 
 
2.3 读取传感器数据   
 
loop函数循环获取实时的大气压强和温度数据,并通过经验公式转换为海拔高度数据,将获得的数据实时更新到TFT显示屏界面上 
- void loop() {
 
 -     // 从寄存器获取到数值
 
 -     bmp5_sensor_data data = {0, 0};
 
 -     int8_t err = pressureSensor.getSensorData(&data);
 
  
-     if (err == BMP5_OK) {
 
 -         // 将气压数据转换以百帕为单位 (1 hPa = 100 Pa)
 
 -         float pressure_hPa = data.pressure / 100.0;
 
  
-         // 使用经验公式计算海拔高度数据
 
 -         float altitude = (1013.25 - pressure_hPa) / 12 * 100;
 
  
-         // 更新屏幕
 
 -         updateTextDisplay(data.temperature, pressure_hPa, altitude);
 
  
-         // 打印串口监视数据
 
 -         Serial.print("Temperature (C): ");
 
 -         Serial.print(data.temperature);
 
 -         Serial.print("\tPressure (hPa): ");
 
 -         Serial.print(pressure_hPa);
 
 -         Serial.print("\tAltitude (m): ");
 
 -         Serial.println(altitude);
 
 -     } else {
 
 -         Serial.print("Error getting data from sensor! Error code: ");
 
 -         Serial.println(err);
 
 -     }
 
  
-     delay(1000);  // 每秒更新一次数据
 
 - }
 
 
  复制代码 
 
 2.4 UI界面更新 
- void drawStaticElements() {
 
 -   tft.fillScreen(BACKGROUND);
 
 -   
 
 -   // 绘制标题
 
 -   tft.setTextSize(1);
 
 -   tft.setTextColor(ST77XX_YELLOW);
 
 -   tft.setCursor(SCREEN_WIDTH/2 + 120, 10);
 
 -   tft.print("BMP581 SENSOR");
 
 -   
 
 -   // 绘制温度数据容器
 
 -   drawDataBox(30, 10, "TEMPERATURE", "(C)", TEMP_COLOR);
 
 -   
 
 -   // 绘制气压数据容器
 
 -   drawDataBox(30, 90, "PRESSURE", "(hPa)", PRESS_COLOR);
 
 -   
 
 -   // 绘制海拔数据容器
 
 -   drawDataBox(30, 170, "ALTITUDE", "(m)", ALT_COLOR);
 
 - }
 
  
- void drawDataBox(int x, int y, const char* label, const char* unit, uint16_t color) {
 
 -     // 绘制数据容器
 
 -     tft.drawRoundRect(x, y, SCREEN_WIDTH - 60, 60, 10, BOX_COLOR);
 
  
-     // 绘制数据标题
 
 -     tft.setTextSize(LABEL_SIZE);
 
 -     tft.setTextColor(color);
 
 -     tft.setCursor(x + 15, y + 10);
 
 -     tft.print(label);
 
  
-     // 绘制数据单位
 
 -     tft.setTextSize(LABEL_SIZE - 1);
 
 -     tft.setCursor(x + SCREEN_WIDTH - 60 - 40, y + 10);
 
 -     tft.print(unit);
 
 - }
 
  
- void updateTextDisplay(float temp, float pressure, float altitude) {
 
 -   updateDataValue(30, 10, temp, 1, TEMP_COLOR);  // 更新温度数据
 
 -   updateDataValue(30, 90, pressure, 1, PRESS_COLOR);  // 更新气压数据
 
 -   updateDataValue(30, 170, altitude, 1, ALT_COLOR);  // 更新海拔数据
 
 - }
 
  
- void updateDataValue(int x, int y, float value, int decimals, uint16_t color) {
 
 -     // 清除旧数据
 
 -     tft.fillRect(x + 10, y + 30, SCREEN_WIDTH - 80, 25, BACKGROUND);
 
  
-     // 写入新数据
 
 -     tft.setTextSize(VALUE_SIZE);
 
 -     tft.setTextColor(color);
 
 -     tft.setCursor(x + 15, y + 30);
 
 -     tft.print(value, decimals);
 
 - }
 
  复制代码 
 
 2.5 项目完整代码获取 
 
 三、实际效果展示  
 
3.1 显示屏信息解读 
成功运行后,显示屏将分为三个区域显示: 
 
- 温度区:灰色标签,显示摄氏度
 - 气压区:红色标签,显示百帕
 - 海拔区:紫色标签,显示米
 
 
 
 
  
 
3.2 视频演示效果 
? 
 
将通过传感器获取到的气压值与app海拔仪气压值进行对比 
 
3.3 串口监视器数据 
同时,串口监视器将每秒输出一次数据: 
 
四、SPI冲突解决方案详解 
 
4.1 问题现象     
当BMP581和ST7789共享硬件SPI总线时:显示屏无法正常显示,传感器数据读取不稳定,系统可能完全无法工作 
 
 4.2 根本原因 
 
 SPI总线需要独占访问: 
两个设备共享MOSI、MISO、SCK信号线 
片选(CS)信号控制不足 
总线竞争导致数据冲突  
  4.3 方案一 
 
软件SPI驱动显示屏:将显示屏改为软件SPI驱动,与传感器的硬件SPI物理隔离。 
- // ST7789使用软件SPI
 
 - #define TFT_CS   6  // 显示屏片选
 
 - #define TFT_RST  4  // 复位引脚
 
 - #define TFT_DC   2  // 数据/命令选择
 
 - #define TFT_MOSI 8  // 软件SPI数据引脚
 
 - #define TFT_SCLK 7  // 软件SPI时钟引脚
 
  
- // 创建显示屏对象(使用软件SPI)
 
 - Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
 
  复制代码 优势: 
- 完全避免硬件SPI冲突
 - 简化编程逻辑
 - 更稳定的通信表现
 - 灵活的引脚分配
 
 
  
4.4 方案二 
 
共享SPI总线+显式CS控制:通过精确控制CS引脚状态,确保同一时间只有一个设备使用SPI总线。 
- // BMP581 SPI参数
 
 - uint8_t bmp581_cs = 10;  // BMP581芯片选择引脚
 
 - uint32_t clockFrequency = 100000;  // BMP581的SPI时钟频率
 
  
- // ST7789显示屏引脚配置
 
 - #define TFT_CS   6  // 显示屏芯片选择引脚(与BMP581不同)
 
  
- Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);   //使用硬件SPI驱动方式
 
  
- void setup() {
 
 -     // ...其他初始化...
 
 -     
 
 -     // 初始化CS引脚
 
 -     pinMode(TFT_CS, OUTPUT);
 
 -     digitalWrite(TFT_CS, HIGH);  // 初始取消选择显示屏
 
 -     pinMode(bmp581_cs, OUTPUT);
 
 -     digitalWrite(bmp581_cs, HIGH);  // 初始取消选择传感器
 
 - }
 
  
- void loop() {
 
 -     // 读取传感器数据
 
 -     digitalWrite(TFT_CS, HIGH);  // 取消选择显示屏
 
 -     err = pressureSensor.getSensorData(&data);
 
 -     digitalWrite(bmp581_cs, HIGH);  // 取消选择传感器
 
 -     
 
 -     // 更新显示
 
 -     digitalWrite(bmp581_cs, HIGH);  // 确保传感器已取消选择
 
 -     updateTextDisplay(...);
 
 - }
 
  复制代码 ?关键点:- 通信前确保另一个设备被取消选择
 - 通信后立即取消选择当前设备
 - 初始化时所有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 
 
 
 |   
 
  
  
  
 
 
 |