#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED 顯示器設定 (128x64)
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// 感測器與 RTC 物件初始化
Adafruit_MPU6050 mpu;
RTC_DS1307 rtc;
void setup(void) {
Serial.begin(115200);
// 1. 初始化 OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED 啟動失敗");
for(;;);
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0,0);
display.println("Initializing...");
display.display();
// 2. 初始化 RTC (DS1307 預設位址 0x68)
if (!rtc.begin()) {
Serial.println("找不到 RTC 模組");
while (1);
}
if (!rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// 3. 初始化 MPU6050 (位址設為 0x69,避免與 RTC 衝突)
// 注意:硬體上必須將 MPU6050 的 AD0 腳位接至 3.3V
if (!mpu.begin(0x69)) {
Serial.println("找不到 MPU6050 晶片 (位址 0x69)");
while (1) { delay(10); }
}
// 設定感測器參數 (參考範例風格)
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_250_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
delay(100);
}
void loop() {
/* 每 2 秒讀取一次感測器數據 */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
// 取得 RTC 當前時間
DateTime now = rtc.now();
/* 計算 PGA (Peak Ground Acceleration),並將 m/s^2 轉換為 cm/s^2 */
// 1 m/s^2 = 100 cm/s^2
float ax_cm = abs(a.acceleration.x) * 100.0;
float ay_cm = abs(a.acceleration.y) * 100.0;
float az_cm = abs(a.acceleration.z - 9.8) * 100.0; // 扣除重力加速度 (假設感測器平放)
// 取三軸中最大值作為判定基準
float pga = max(ax_cm, max(ay_cm, az_cm));
/* 根據台灣震度標準判定地震強度 (grade 0-7) */
int grade = 0;
if (pga < 0.8) grade = 0;
else if (pga < 2.5) grade = 1;
else if (pga < 8.0) grade = 2;
else if (pga < 25.0) grade = 3;
else if (pga < 80.0) grade = 4;
else if (pga < 250.0) grade = 5;
else if (pga < 400.0) grade = 6;
else grade = 7;
/* 在 OLED 模組上顯示時間與地震強度 */
display.clearDisplay();
// 顯示標題
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Earthquake Monitor");
display.drawLine(0, 10, 127, 10, WHITE);
// 顯示日期與時間
display.setCursor(0, 15);
display.print("Date: ");
display.print(now.year()); display.print("/");
display.print(now.month()); display.print("/");
display.print(now.day());
display.setCursor(0, 25);
display.print("Time: ");
if(now.hour() < 10) display.print('0');
display.print(now.hour()); display.print(":");
if(now.minute() < 10) display.print('0');
display.print(now.minute()); display.print(":");
if(now.second() < 10) display.print('0');
display.println(now.second());
// 顯示震度級數 (放大字體)
display.setCursor(0, 40);
display.setTextSize(2);
display.print("grade: ");
display.println(grade);
display.display();
/* 序列埠輸出 (除錯用) */
Serial.print("PGA: "); Serial.print(pga); Serial.print(" cm/s^2, ");
Serial.print("Grade: "); Serial.println(grade);
// 每 2 秒更新一次
delay(2000);
}