// Arduino電圧変化検知システム
// 電圧変化を検知してLEDとパトカーサイレンで警告
// ピン定義
const int VOLTAGE_PIN = A0; // 電圧測定用アナログピン
const int LED_PIN = 13; // LED出力ピン
const int BUZZER_PIN = 8; // ブザー出力ピン
// 設定パラメータ(変更可能)
float START_VOLTAGE_RATIO = 0.4; // VCCに対する開始電圧比率(40%)
float STOP_VOLTAGE_RATIO = 0.2; // VCCに対する停止電圧比率(20%)
int CONFIRMATION_TIME = 100; // 状態変更確認時間(ミリ秒)
int AVERAGE_SAMPLES = 5; // 平均値計算用サンプル数
// システム変数
float currentVoltage = 0.0;
float voltageSum = 0.0;
int voltageCount = 0;
float vccVoltage = 5.0; // 測定されたVCC電圧
float startVoltage = 4.75; // 動的に計算される開始電圧
float stopVoltage = 4.0; // 動的に計算される停止電圧
bool alertActive = false;
unsigned long lastSirenToggle = 0;
unsigned long lastLedToggle = 0; // LED点滅用タイマー
bool sirenHigh = true; // サイレン音の高低切り替え用
bool ledState = false; // LED点滅状態
// 状態変更確認用変数
bool candidateStart = false; // 開始候補状態
bool candidateStop = false; // 停止候補状態
unsigned long candidateStartTime = 0;
unsigned long candidateStopTime = 0;
// VCC電圧を測定する関数
float readVCC() {
// 内部基準電圧(1.1V)を測定してVCCを逆算
long result;
// ADMUXレジスタを設定(内部基準電圧を選択)
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // 安定化待ち
// AD変換開始
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA,ADSC)); // 変換完了まで待機
// 結果を読み取り
uint8_t low = ADCL;
uint8_t high = ADCH;
result = (high<<8) | low;
// VCC = 1.1V * 1024 / ADC値
result = 1125300L / result; // 1.1V * 1024 * 1000 (mV単位)
return result / 1000.0; // V単位に変換
}
void setup()
{
// ピン設定
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
// シリアル通信開始(デバッグ用)
Serial.begin(9600);
Serial.println("電圧変化検知システム開始(VCC自動調整版)");
// VCC電圧を測定して閾値を計算
vccVoltage = readVCC();
startVoltage = vccVoltage * START_VOLTAGE_RATIO;
stopVoltage = vccVoltage * STOP_VOLTAGE_RATIO;
Serial.print("測定VCC電圧: ");
Serial.print(vccVoltage);
Serial.println("V");
Serial.print("警告開始電圧: ");
Serial.print(startVoltage);
Serial.print("V (VCCの");
Serial.print(START_VOLTAGE_RATIO * 100);
Serial.println("%)");
Serial.print("警告停止電圧: ");
Serial.print(stopVoltage);
Serial.print("V (VCCの");
Serial.print(STOP_VOLTAGE_RATIO * 100);
Serial.println("%)");
}
void loop()
{
// 電圧測定と平均値計算
int sensorValue = analogRead(VOLTAGE_PIN);
float instantVoltage = (sensorValue * vccVoltage) / 1024.0; // VCCベースで計算
// 移動平均の計算
voltageSum += instantVoltage;
voltageCount++;
if (voltageCount >= AVERAGE_SAMPLES) {
currentVoltage = voltageSum / voltageCount; // 平均電圧
voltageSum = 0;
voltageCount = 0;
} else {
// まだサンプル数が足りない場合は前回の処理をスキップ
delay(10);
return;
}
unsigned long currentTime = millis();
// 警告開始の候補チェック
if (currentVoltage >= startVoltage && !alertActive && !candidateStart) {
candidateStart = true;
candidateStartTime = currentTime;
// Serial.println("警告開始候補を検出中..."); // 高速化のためコメントアウト
}
// 警告停止の候補チェック
if (currentVoltage <= stopVoltage && alertActive && !candidateStop) {
candidateStop = true;
candidateStopTime = currentTime;
// Serial.println("警告停止候補を検出中..."); // 高速化のためコメントアウト
}
// 候補状態のリセット(条件を満たさなくなった場合)
if (candidateStart && currentVoltage < startVoltage) {
candidateStart = false;
// Serial.println("警告開始候補をリセット"); // 高速化のためコメントアウト
}
if (candidateStop && currentVoltage > stopVoltage) {
candidateStop = false;
// Serial.println("警告停止候補をリセット"); // 高速化のためコメントアウト
}
// 警告開始の確定
if (candidateStart && (currentTime - candidateStartTime >= CONFIRMATION_TIME)) {
alertActive = true;
candidateStart = false;
lastSirenToggle = currentTime;
lastLedToggle = currentTime; // LED点滅タイマー初期化
sirenHigh = true;
ledState = true; // LED点滅開始
digitalWrite(LED_PIN, HIGH); // LED点灯
Serial.println("警告開始確定!");
Serial.print("確定電圧: ");
Serial.print(currentVoltage);
Serial.println("V");
}
// 警告停止の確定
if (candidateStop && (currentTime - candidateStopTime >= CONFIRMATION_TIME)) {
alertActive = false;
candidateStop = false;
digitalWrite(LED_PIN, LOW); // LED消灯
noTone(BUZZER_PIN); // サイレン停止
Serial.println("警告停止確定");
Serial.print("確定電圧: ");
Serial.print(currentVoltage);
Serial.println("V");
}
// 警告状態の処理
if (alertActive) {
unsigned long currentTime = millis();
// サイレン音の制御(500ms間隔で切り替え)
if (currentTime - lastSirenToggle >= 500) {
if (sirenHigh) {
tone(BUZZER_PIN, 960); // 高音
} else {
tone(BUZZER_PIN, 770); // 低音
}
sirenHigh = !sirenHigh; // 高低切り替え
lastSirenToggle = currentTime;
}
// LED点滅制御(500ms間隔で切り替え)
if (currentTime - lastLedToggle >= 500) {
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
lastLedToggle = currentTime;
}
}
// デバッグ情報表示(5秒間隔に変更して負荷軽減)
static unsigned long lastDebugTime = 0;
if (millis() - lastDebugTime >= 5000) {
Serial.print("VCC: ");
Serial.print(vccVoltage);
Serial.print("V, 現在電圧: ");
Serial.print(currentVoltage);
Serial.print("V, 閾値(開始/停止): ");
Serial.print(startVoltage);
Serial.print("V/");
Serial.print(stopVoltage);
Serial.println("V");
lastDebugTime = millis();
}
delay(10); // 短縮(50ms → 10ms)
}