1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <Wire.h>
#include <Adafruit_AHTX0.h> // AHT20 驅動庫
#include <TFT_eSPI.h> // TTGO T-Display LCD
#include <MQ135.h> // MQ-135 驅動庫

#define SDA_PIN 21
#define SCL_PIN 22
#define MQ135_PIN 27 // MQ-135 ADC 腳位
#define MQ2_PIN 12 // MQ-2 ADC 腳位

Adafruit_AHTX0 aht;
TFT_eSPI tft = TFT_eSPI();
MQ135 mq135_sensor(MQ135_PIN);

void setup() {
Serial.begin(115200);

// 初始化螢幕
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);

// 初始化 I2C
Wire.begin(SDA_PIN, SCL_PIN);

// 初始化 AHT20
if (!aht.begin()) {
tft.fillScreen(TFT_BLACK);
tft.setCursor(10, 30);
tft.setTextColor(TFT_RED);
tft.println("AHT20 INIT FAIL");
Serial.println("AHT20 初始化失敗");
while(1) delay(1000);
}

tft.fillScreen(TFT_BLACK);
tft.setCursor(10, 30);
tft.setTextColor(TFT_GREEN);
tft.println("AHT20 OK");
Serial.println("AHT20 初始化成功");
delay(2000);

Serial.println("=== 氣體感測器除錯測試 ===");
Serial.println("等待感測器預熱...");

// 感測器預熱
for(int i = 30; i > 0; i--) {
tft.fillScreen(TFT_BLACK);
tft.setCursor(10, 50);
tft.setTextColor(TFT_YELLOW);
tft.printf("感測器預熱中... %d 秒", i);
delay(1000);
}
}

void loop() {
// 讀取 AHT20 溫濕度
sensors_event_t humidity, temp;
aht.getEvent(&humidity, &temp);
float temperature = temp.temperature;
float humi = humidity.relative_humidity;

// 檢查 AHT20 數值是否有效
bool aht_valid = (!isnan(temperature) && !isnan(humi));

// 讀取 MQ-135 (使用函式庫方法)
float mq135_ppm = 0.0;
if (aht_valid) {
mq135_ppm = mq135_sensor.getCorrectedPPM(temperature, humi);
} else {
mq135_ppm = mq135_sensor.getPPM(); // 無溫濕度補償
}

// 讀取 MQ-2 原始值 (因為沒有專用函式庫)
int mq2_raw = analogRead(MQ2_PIN);

// 序列埠除錯輸出
Serial.printf("AHT20: %.1f°C, %.1f%% (有效: %s)\n",
temperature, humi, aht_valid ? "是" : "否");
Serial.printf("MQ-135: %.1f ppm\n", mq135_ppm);
Serial.printf("MQ-2: %d ADC\n", mq2_raw);
Serial.println("---");

// 螢幕顯示
tft.fillScreen(TFT_BLACK);

// 標題
tft.setCursor(10, 5);
tft.setTextColor(TFT_CYAN);
tft.setTextSize(1);
tft.println("氣體感測器除錯測試");

// AHT20 狀態
tft.setCursor(10, 25);
tft.setTextColor(aht_valid ? TFT_GREEN : TFT_RED);
tft.printf("AHT20: %.1f°C %.0f%%", temperature, humi);

// MQ-135 測試
tft.setCursor(10, 45);
tft.setTextColor(TFT_YELLOW);
tft.println("MQ-135 (GPIO27):");

tft.setCursor(10, 60);
if (mq135_ppm > 1.0) {
tft.setTextColor(TFT_GREEN);
tft.printf("✓ PPM: %.1f", mq135_ppm);
} else if (mq135_ppm > 0.0) {
tft.setTextColor(TFT_ORANGE);
tft.printf("? PPM: %.1f (低)", mq135_ppm);
} else {
tft.setTextColor(TFT_RED);
tft.printf("✗ PPM: %.1f (異常)", mq135_ppm);
}

// MQ-2 測試
tft.setCursor(10, 80);
tft.setTextColor(TFT_YELLOW);
tft.println("MQ-2 (GPIO12):");

tft.setCursor(10, 95);
if (mq2_raw > 100) {
tft.setTextColor(TFT_GREEN);
tft.printf("✓ ADC: %d", mq2_raw);
} else if (mq2_raw > 10) {
tft.setTextColor(TFT_ORANGE);
tft.printf("? ADC: %d (低)", mq2_raw);
} else {
tft.setTextColor(TFT_RED);
tft.printf("✗ ADC: %d (無訊號)", mq2_raw);
}

// 問題診斷
tft.setCursor(10, 115);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(1);

if (!aht_valid) {
tft.println("AHT20 連接問題!");
} else if (mq135_ppm <= 0.0 && mq2_raw <= 10) {
tft.println("檢查: 氣體感測器供電/接線");
} else if (mq135_ppm <= 0.0) {
tft.println("MQ-135: 檢查5V供電");
} else if (mq2_raw <= 10) {
tft.println("MQ-2: 檢查連接");
} else {
tft.println("感測器運作正常!");
}

delay(2000);
}