---
# System prepended metadata

title: 使用ESP32+AHT20+BMP280二合一模組(I2C通信)
tags: [I2C, AHT20, BMP280, ESP32]

---

## AHT20+BMP280傳感器介紹
這是一個二合一的模組，AHT20可測量溫度和濕度，BMP280可測量溫度、氣壓和海拔高度(根據氣壓計算)，使用I2C通信，共有四個接腳，分別為SCL、GND、SDA、VCC。

**AHT20+BMT280基本規格**
![image](https://hackmd.io/_uploads/BJNnG3hhC.png =70%x)

## 使用ESP32與AHT20+BMP280進行I2C通信
ESP32-S3 提供兩個 I2C 通道，I2C 接口可以接到任意 GPIO 上，但需要避免使用一些特定用途的 GPIO。這裡的配置是 SDA 接 GPIO7，SCL 接 GPIO6。
![image](https://hackmd.io/_uploads/ByTjQ3hnA.png =50%x)

使用傳感器進行 I2C 通訊時需要知道傳感器的 I2C 地址，每個模組通常都有固定的地址，可以在傳感器的規格書中查找。
<br/>

程式如下：
```c=
#include <Adafruit_AHTX0.h>
#include <Adafruit_BMP280.h>

Adafruit_BMP280 bmp;  // 將BMP280設為bmp
Adafruit_AHTX0 aht;   // 將AHTX0設為aht

void setup() {
  Serial.begin(115200);
  Wire.begin(7, 6);  // 設定 SDA 和 SCL 的 GPIO
  
  // 初始化AHT20
  if (!aht.begin()) {   // 檢查是否成功初始化
    Serial.println("Error initializing AHT20");
    return;
  }
  Serial.println("AHT20 sensor initialized.");

  // 初始化BMP280
  if (!bmp.begin(0x77)) {  // 檢查是否成功初始化, 代入BMP280位置=0x77
    Serial.println("Error initializing BMP280");
    return;
  }
  Serial.println("BMP280 sensor initialized.");
}

void loop() {
  // 讀取 AHT20 數據
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);

  Serial.print("Temperature: ");
  Serial.print(temp.temperature);
  Serial.println(" °C");

  Serial.print("Humidity: ");
  Serial.print(humidity.relative_humidity);
  Serial.println("%");
  
  // 讀取 BMP280 數據
  Serial.print("Pressure: ");
  Serial.print(bmp.readPressure() / 100.0F);
  Serial.println(" hPa");

  Serial.print("Altitude: ");
  Serial.print(bmp.readAltitude(1007.1));    // 海平面氣壓=1007.1 hPa(2024/09/10 新屋)
  Serial.println(" meters");

  delay(2000);
}
```

補充說明: 
使用bmp.readAltitude(1007.1)取得海拔高度，1007.1hPa為海平面氣壓(根據中央氣象局2024/9/10新屋的量測資料)
https://www.cwa.gov.tw/V8/C/W/OBS_County.html?ID=68
![螢幕擷取畫面 2024-09-10 011404](https://hackmd.io/_uploads/Skdgain3R.jpg)



### 執行結果：
![image](https://hackmd.io/_uploads/SkH8ssnn0.png　=60%x)


根據Google map我現在所在的位置海拔高度為122.09公尺
我家在九樓，假設一層樓高約3米, 海拔=149m(122+9*3)
差異不到10米，這結果太讓人驚呀了!下次去山上玩帶上去測看看~
![螢幕擷取畫面 2024-09-10 005732](https://hackmd.io/_uploads/HkwMYshhR.jpg)
<br/>

## 補充：I2C位置查詢

不知道傳感器I2C的地址可以使用以下程式查詢
我將傳感器的SDA接腳接在GPIO7，SCL接在GPIO6，執行以下程式

```c=
#include <Wire.h>  // 引入I2C通訊的Wire庫

// I2C引腳設定
#define SDA_PIN 7  // 定義SDA (數據線) 連接的腳位為 7
#define SCL_PIN 6  // 定義SCL (時鐘線) 連接的腳位為 6

void setup() {
  // 設定I2C引腳
  Wire.begin(SDA_PIN, SCL_PIN);  // 初始化I2C，並指定SDA和SCL的腳位
  
  Serial.begin(115200);  // 設定序列通訊，波特率為115200
  Serial.println("\nI2C Scanner");  // 顯示 "I2C Scanner" 字樣，表示程式已啟動
}

void loop() {
  byte error, address;  // 定義變數error來儲存錯誤代碼，address來儲存目前掃描的I2C地址
  int nDevices;  // 定義變數nDevices來記錄找到的設備數量
  
  Serial.println("Scanning...");  // 顯示 "Scanning..." 字樣，表示正在掃描I2C設備
  nDevices = 0;  // 初始化設備數量為0
  
  // 從地址 1 掃描到 126
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);  // 開始與指定地址的設備進行通訊
    error = Wire.endTransmission();   // 結束傳輸，並回傳錯誤代碼 (0 表示成功)
    
    if (error == 0) {  // 如果 error == 0，表示該地址上有設備
      Serial.print("I2C device found at address 0x");  // 顯示 "I2C device found at address 0x"
      if (address < 16) {  // 如果地址小於16，需要補0，保持位數一致
        Serial.print("0");
      }
      Serial.println(address, HEX);  // 顯示設備的I2C地址，並用16進制格式輸出
      nDevices++;  // 計數設備數量加1
    }
    else if (error == 4) {  // 如果 error == 4，表示發生未知錯誤
      Serial.print("Unknow error at address 0x");  // 顯示 "Unknown error at address 0x"
      if (address < 16) {  // 如果地址小於16，同樣補0
        Serial.print("0");
      }
      Serial.println(address, HEX);  // 顯示發生錯誤的地址
    }    
  }
  
  // 如果沒有找到任何I2C設備
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");  // 顯示 "No I2C devices found"
  }
  else {
    Serial.println("done\n");  // 掃描完成後顯示 "done"
  }

  delay(5000);  // 延遲5秒，然後重新掃描
}

```
顯示結果：
![螢幕擷取畫面 2024-09-10 020235](https://hackmd.io/_uploads/rJTi5hh3C.jpg)
找到兩個I2C device address，分別為0x38和0x77
(0x38為AHT20，0x77為BMP280)

