?零知開源是一個真正屬于國人自己的開源軟硬件平臺,在開發效率上超越了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 項目完整代碼獲取
通過網盤分享的文鏈接:
https://pan.baidu.com/s/125lFvyjRd98dkqMkYh0TSA?pwd=d4m4
三、實際效果展示
3.1 顯示屏信息解讀
成功運行后,顯示屏將分為三個區域顯示:
溫度區:灰色標簽,顯示攝氏度
氣壓區:紅色標簽,顯示百帕
海拔區:紫色標簽,顯示米
3.2 視頻演示效果
https://www.bilibili.com/video/BV1MR3tzzEXm/?spm_id_from=333.1387.homepage.video_card.click&vd_source=a31e3d8d8ce008260eee442534c2f63d
將通過傳感器獲取到的氣壓值與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控制
數據采集與顯示:實時獲取環境數據并直觀展示
海拔計算:使用簡化公式計算海拔高度
通過本教程,開發者可以快速構建穩定可靠的環境監測系統,更多零知開發教程:
審核編輯 黃宇
-
傳感器
+關注
關注
2565文章
52857瀏覽量
765997 -
SPI
+關注
關注
17文章
1797瀏覽量
95434 -
stm32f1
+關注
關注
1文章
60瀏覽量
12488
發布評論請先 登錄
零知開源——STM32F1驅動BMP581壓強傳感器使用SPI實現ST7789顯示的環境監測系統

零知開源——基于STM32F407VET6零知增強板的四路獨立計時器
零知開源——STM32F103RBT6驅動 ICM20948 九軸傳感器及 vofa + 上位機可視化教程
零知開源——STM32F103RBT6驅動 ICM20948 九軸傳感器及 vofa + 上位機可視化教程

零知開源——STM32F4驅動MAX31865實現PT100高精度測溫
零知開源——STM32F1驅動MAX31865讀取三線PT100溫度傳感器
零知開源——STM32F1驅動MAX31865讀取三線PT100溫度傳感器

ESP32驅動ST7789觸摸屏開發指南:LVGL主題設置與示波器面板
ESP32驅動ST7789觸摸屏開發指南:LVGL主題設置與示波器面板

評論