#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <SPI.h>
#include <SD.h>
// アドレス設定
#define LCD_ADRS 0x27 // 液晶表示器のI2Cアドレス
#define LED_ADRS 2 // LEDの接続ピン
#define TipBucket 3 // 雨量計の接続ピン
#define TimeInt 60000UL // タイムステップ1分毎
const int chipSelect = 4; // SDカードモジュールのCSピン
// 変数定義
char lcd_buf[17]; // 液晶表示バッファ
volatile boolean turnBucket; // 割込使用変数の宣言
const float wv1shot = 0.5; // 1回の転倒ます降水量(mm/count) を0.5に変更
float mP[60], hP[24], amop; // 雨量の記録変数
int mpp, hpp;
// LCDオブジェクトの作成
LiquidCrystal_I2C lcd(LCD_ADRS, 16, 2);
// RTCオブジェクトの作成
RTC_DS3231 rtc;
// 転倒ます信号割込の処理
void tbSignal() {
turnBucket = true; // 転倒ます転倒した
}
// 初期化
void setup() {
Serial.begin(9600);
Wire.begin(); // LCD & RTC 初期化
// RTCの初期化
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1)
;
}
if (rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// SDカードの初期化
if (!SD.begin(chipSelect)) {
Serial.println("SD initialization failed!");
while (1)
;
} else {
Serial.println("SD card initialized.");
}
// LCDの初期化
lcd.init();
lcd.noBacklight(); // LCDのバックライトをオフにする
lcd.setCursor(0, 0);
lcd.print("*ARU-Hyetometer*");
pinMode(LED_ADRS, OUTPUT); // LED出力の初期化
digitalWrite(LED_ADRS, LOW);
pinMode(TipBucket, INPUT_PULLUP); // 雨量計の割込み設定
attachInterrupt(digitalPinToInterrupt(TipBucket), tbSignal, FALLING);
for (int i = 0; i < 24; i++) hP[i] = 0.0;
for (int i = 0; i < 60; i++) mP[i] = 0.0;
mpp = hpp = 0;
amop = 0.0;
turnBucket = false;
}
// 計測ループ
void loop() {
unsigned long currentMillis = millis();
unsigned long nextMinuteMillis = (currentMillis / TimeInt + 1) * TimeInt;
while (millis() < nextMinuteMillis) {
DateTime now = rtc.now(); // ここで最新の時刻を取得
if (turnBucket) { // 転倒ますが動作した
digitalWrite(LED_ADRS, HIGH); // 検知LED点灯
delay(100); // チャタリング不感時間
mP[mpp] += wv1shot; // それぞれに1回分雨量加算
hP[hpp] += wv1shot;
amop += wv1shot;
digitalWrite(LED_ADRS, LOW); // 検知LED消灯
// ファイルに記録
File dataFile = SD.open("rain.log", FILE_WRITE);
if (dataFile) {
dataFile.print(now.year(), DEC);
dataFile.print('/');
dataFile.print(now.month(), DEC);
dataFile.print('/');
dataFile.print(now.day(), DEC);
dataFile.print(',');
dataFile.print(now.hour(), DEC);
dataFile.print(':');
dataFile.print(now.minute(), DEC);
dataFile.print(':');
dataFile.println(now.second(), DEC); // 秒の部分も更新
dataFile.close();
Serial.println("Data written to SD card.");
} else {
Serial.println("Error opening file for writing.");
}
turnBucket = false;
}
// 雨量計算と液晶表示
float prep = 0.0; // 直近60分間分の雨量合計
for (int i = 0; i < 60; i++) prep += mP[i];
dtostrf(prep, 5, 1, lcd_buf); // 時間雨量
lcd_buf[5] = '(';
prep = 0.0; // 過去5分間平均の降雨強度を求める
for (int i = (mpp + 56); i <= (mpp + 60); i++)
prep += mP[i % 60];
prep *= 12.0; // 1時間当たりに換算
dtostrf(prep, 5, 1, lcd_buf + 6); // 降雨強度
lcd_buf[11] = ')';
lcd_buf[12] = 'm';
lcd_buf[13] = 'm';
lcd_buf[14] = '/';
lcd_buf[15] = 'h';
lcd_buf[16] = '\0'; // 終端文字を追加
lcd.setCursor(0, 0);
lcd.print(lcd_buf);
char timestamp[17];
sprintf(timestamp, "%02d/%02d %02d:%02d", now.month(), now.day(), now.hour(), now.minute());
timestamp[16] = '\0'; // 終端文字を追加
lcd.setCursor(0, 1);
lcd.print(timestamp);
delay(1000); // 1秒休止してループを律速
}
mpp = (mpp + 1) % 60; // 1分間雨量のポインタ増やしリセット
mP[mpp] = 0.0;
if (mpp == 0) { // 60分間経過したら1時間雨量のポインタ増やしリセット
hpp = (hpp + 1) % 24;
hP[hpp] = 0.0;
}
}