#include <Arduino.h>
#include <Wire.h>
#include <RTClib.h>
#include <SPI.h>
#include <SD.h>
// アドレス設定
#define LCD_ADRS 0x3E //液晶表示器(AQM1602XA)
#define LED_ADRS 2 // LEDの接続ピン
#define TipBucket 3 // 雨量計の接続ピン
#define TipBucketInt 1 // UNOではpin3はINT1の割込
#define TimeInt 60000UL //タイムステップ1分毎
#define chipSelect 10 // SDカードのチップセレクトピン
//変数定義
char lcd_buf[17] ; // 液晶表示バッファ
int i, mpp, hpp ;
boolean beat ; // LCD点滅用
volatile boolean turnBucket ; // 割込使用変数の宣言
const float wv1shot = 0.6 ; //1回の転倒ます降水量(mm/count)
float mP[60], hP[24], prep, amop ; // 雨量の記録変数
unsigned long ptime, ntime ; // 処理時間の判定用変数
RTC_DS3231 rtc;
File logFile;
// 転倒ます信号割込の処理
void tbSignal() {
turnBucket = true ; // 転倒ます転倒した
}
//LCDにデータを送る
void LCD_write(char t_data[]) {
for(i = 0; i < 16; i++) {
Wire.beginTransmission(LCD_ADRS);
Wire.write(0x40) ;
Wire.write(t_data[i]) ;
Wire.endTransmission() ;
delay(1) ;
}
}
//LCDに命令を実行させる
void LCD_command(byte t_command)
{
Wire.beginTransmission(LCD_ADRS) ;
Wire.write(0x00) ;
Wire.write(t_command) ;
Wire.endTransmission() ;
delay(10);
}
// 初期化
void setup() {
Wire.begin() ; //LCD初期化
LCD_command(0x38) ;
LCD_command(0x39) ;
LCD_command(0x14) ;
LCD_command(0x73) ;
LCD_command(0x52) ; // 5V
LCD_command(0x6C) ;
LCD_command(0x38) ;
LCD_command(0x01) ;
LCD_command(0x0C) ;
LCD_command(0x80|0x00) ; // 開始時のクレジット表示
LCD_write("*ARU-Hyetometer*") ;
pinMode(LED_ADRS, OUTPUT) ; // LED出力の初期化
digitalWrite(LED_ADRS, LOW) ;
pinMode(TipBucket, INPUT_PULLUP) ; // 雨量計の割込み設定
attachInterrupt(TipBucketInt, tbSignal, FALLING) ;
// RTC初期化
if (!rtc.begin()) {
LCD_write("RTC not found");
while (1);
}
if (rtc.lostPower()) {
// RTCが電源を失った場合、現在のコンパイル時間で設定する
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// SDカード初期化
if (!SD.begin(chipSelect)) {
LCD_command(0x80|0x40);
LCD_write("SD init failed");
while (1);
}
logFile = SD.open("datalog.txt", FILE_WRITE);
if (!logFile) {
LCD_command(0x80|0x40);
LCD_write("File open fail");
while (1);
}
logFile.println("Hyetometer Log Start:");
logFile.close();
Serial.begin(9600);
Serial.println("Setup complete");
amop = hpp = mpp = 0 ; // 雨量記録値関係の初期化
for(i = 0; i < 24; i++) hP[i] = 0.0 ;
for(i = 0; i < 60; i++) mP[i] = 0.0 ;
ptime = millis() / TimeInt ; // タイムステップ換算
ntime = ptime + 1 ; // 次のタイムステップを設定
strcpy(lcd_buf, "v.12 by Hoshi **") ;
while(ntime > ptime) { // システム時計の同期待ち
i = 99 - (int)(millis() / (TimeInt / 100) % 100) ;
LCD_command(0x80|0x40);
lcd_buf[14] = (char)(i / 10) + 0x30 ;
lcd_buf[15] = (char)(i % 10) + 0x30 ;
LCD_write(lcd_buf) ;
ptime = millis() / TimeInt ; // 最大1分間
}
ntime += 1 ; //次のタイムステップを設定
beat = false ;
turnBucket = false ; //雨量センサ検知リセット
}
// 計測ループ
void loop() {
do { // 1分間内の繰り返し処理
if(turnBucket) { // 転倒ますが動作した
digitalWrite(LED_ADRS, HIGH) ; // 検知LED点灯
delay(100) ; // チャタリング不感時間
mP[mpp] += wv1shot ; // それぞれに1回分雨量加算
hP[hpp] += wv1shot ;
amop += wv1shot ;
DateTime now = rtc.now();
char buffer[32];
snprintf(buffer, sizeof(buffer), "%02d/%02d/%04d %02d:%02d:%02d %.1fmm",
now.day(), now.month(), now.year(),
now.hour(), now.minute(), now.second(), amop);
logFile = SD.open("datalog.txt", FILE_WRITE);
if (logFile) {
logFile.println(buffer);
logFile.close();
Serial.println("Bucket Turn Logged: " + String(buffer)); // デバッグ用
} else {
Serial.println("Failed to open file for writing. Check SD initialization and connections.");
}
digitalWrite(LED_ADRS, LOW) ; // 検知LED消灯
turnBucket = false ;
}
// 雨量計算と液晶表示
prep = 0.0 ; // 直近60分間分の雨量合計
for(i = 0; i < 60; i++) prep += mP[i] ;
dtostrf(prep,5,1,&lcd_buf[0]) ; //時間雨量
lcd_buf[5] = '(' ;
prep = 0.0 ; //過去5分間平均の降雨強度を求める
for(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_command(0x80|0x00) ;
LCD_write(lcd_buf) ;
dtostrf(amop,6,1,&lcd_buf[0]) ; //総雨量
lcd_buf[6] = '(' ;
lcd_buf[7] = 'd' ;
prep = 0.0 ;
for(i = 0; i < 24; i++) prep += hP[i] ;
dtostrf(prep,5,1,&lcd_buf[8]) ; //24時間雨量
lcd_buf[13] = ')' ;
lcd_buf[14] = 'm' ;
lcd_buf[15] = 'm' ;
if(beat) {
lcd_buf[0] = 0x1D ; //(R)マークを点滅
beat = false ;
}
else beat = true ;
LCD_command(0x80|0x40) ;
LCD_write(lcd_buf) ;
delay(1000) ; // 1秒休止してループを律速
ptime = millis() / TimeInt ; // システム時刻計測
if(ptime == 0) ntime = 1 ; //システム時計のオーバーフロー対策
} while(ptime < ntime) ; // 1分経過するまでループ
ntime += 1 ; //次のタイムステップを設定
mpp = (mpp + 1) % 60 ; // 1分間雨量のポインタ増やしリセット
mP[mpp] = 0.0 ;
if(mpp == 0) { // 60分間経過したら1時間雨量のポインタ増やしリセット
hpp = (hpp + 1) % 24 ;
hP[hpp] = 0.0 ;
}
}