first commit
This commit is contained in:
61
.gitignore
vendored
Normal file
61
.gitignore
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# Arduino build files
|
||||
*.hex
|
||||
*.eep
|
||||
*.elf
|
||||
*.map
|
||||
|
||||
# Arduino IDE files
|
||||
*.ino.bak
|
||||
*.ino.tmp
|
||||
*~
|
||||
|
||||
# Build directory
|
||||
build/
|
||||
build-*/
|
||||
|
||||
# Compiled Object files
|
||||
*.o
|
||||
*.a
|
||||
|
||||
# Debugging files
|
||||
*.log
|
||||
*.txt
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# IDE specific files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.sublime-*
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.bak
|
||||
|
||||
# Arduino libraries (if using external libraries, uncomment as needed)
|
||||
# libraries/
|
||||
|
||||
# Documentation build
|
||||
docs/_build/
|
||||
|
||||
# Python (if using any Python tools)
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
venv/
|
||||
env/
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
305
README.md
Normal file
305
README.md
Normal file
@@ -0,0 +1,305 @@
|
||||
# Sistema Allarme Camper Ultra Low Power
|
||||
|
||||
Sistema di allarme per camper ottimizzato per consumo energetico minimo, con rilevamento intelligente delle vibrazioni e controllo remoto via RF.
|
||||
|
||||
## Caratteristiche
|
||||
|
||||
- **Ultra Low Power**: ~3.5mA armato, autonomia 60+ giorni con batteria 12V 7Ah
|
||||
- **Rilevamento Intelligente**: Conta N cambi di stato in finestra temporale per ridurre falsi positivi
|
||||
- **Sleep Mode PWR_DOWN**: Sistema dorme il 99% del tempo (~0.1µA)
|
||||
- **Interrupt-Driven**: Risposta immediata senza polling continuo
|
||||
- **Watchdog Timer**: Lampeggio LED senza sprechi energetici
|
||||
- **Configurabile**: Debug serial e tipo sensore via #define
|
||||
- **Controllo RF**: Attivazione/disattivazione tramite telecomando 433MHz
|
||||
|
||||
## Hardware Richiesto
|
||||
|
||||
### Componenti Principali
|
||||
- **Arduino Pro Mini 3.3V 8MHz** (consigliato per ultra low power)
|
||||
- Dissaldare LED power sulla board (risparmio ~10mA)
|
||||
- Mantenere regolatore di tensione onboard
|
||||
- **RX480E-4** - Ricevitore RF 433MHz (⚠️ richiede 5V - vedi nota sotto)
|
||||
- **Sensore vibrazione SW-420** - Modulo con switch vibrazioni
|
||||
- Dissaldare LED power e LED signal dal modulo (risparmio ~15mA)
|
||||
- Regolazione sensibilità tramite potenziometro onboard
|
||||
- **Buzzer attivo** 3.3V-5V compatibile
|
||||
- **LED** x2 (status + intrusione)
|
||||
- **Resistenze** 1.5kΩ per LED (low power)
|
||||
|
||||
**⚠️ Nota importante RF Receiver:**
|
||||
Il RX480E-4 richiede alimentazione a 5V. Con Pro Mini 3.3V hai due opzioni:
|
||||
1. Usare regolatore 5V separato per il solo ricevitore RF
|
||||
2. Usare ricevitore RF compatibile 3.3V (es. RXB6, moduli superheterodyne)
|
||||
|
||||
### Alimentazione
|
||||
- Batteria 12V 7Ah (autonomia ~67 giorni)
|
||||
- Oppure batteria 9V 500mAh (autonomia ~5 giorni)
|
||||
- Regolatore step-down se necessario
|
||||
|
||||
## Schema Collegamento
|
||||
|
||||
```
|
||||
Arduino Pin → Componente
|
||||
────────────────────────────
|
||||
Pin 2 → SW-420 D0 (INT0)
|
||||
Pin 6 → RX480E-4 DATA (PCINT22)
|
||||
Pin 9 → Buzzer
|
||||
Pin 12 → LED intrusione
|
||||
Pin 13 → LED status
|
||||
|
||||
VCC (3.3V) → SW-420 VCC
|
||||
VCC (5V) → RX480E-4 VCC (richiede regolatore separato)
|
||||
GND → Tutti i GND comuni
|
||||
```
|
||||
|
||||
## Configurazione Software
|
||||
|
||||
### Parametri Configurabili
|
||||
|
||||
Nel file `src/src.ino`, modifica le seguenti define:
|
||||
|
||||
```cpp
|
||||
// Debug Serial (disabilita in produzione)
|
||||
#define DEBUG_SERIAL
|
||||
|
||||
// Stato iniziale all'accensione
|
||||
#define STARTUP_STATE 1 // 0=sempre disarmato, 1=sempre armato, 2=check RF
|
||||
|
||||
// Rilevamento vibrazione intelligente
|
||||
#define VIBRATION_WINDOW_MS 2000 // Finestra temporale (ms)
|
||||
#define VIBRATION_THRESHOLD 80 // N° cambi di stato richiesti
|
||||
#define VIBRATION_TIMEOUT_MS 3000 // Timeout inattività (ms)
|
||||
|
||||
// Durate allarme
|
||||
#define TRIGGER_DURATION_MS 5000 // Durata buzzer (ms)
|
||||
#define ARMING_DELAY_MS 2000 // Delay armamento (ms)
|
||||
```
|
||||
|
||||
### Modalità di Avvio
|
||||
|
||||
| STARTUP_STATE | Comportamento |
|
||||
|---------------|---------------|
|
||||
| 0 | **ALWAYS_DISARMED** - Parte sempre disarmato (ignora RF) |
|
||||
| 1 | **ALWAYS_ARMED** - Parte sempre armato (massima sicurezza) |
|
||||
| 2 | **CHECK_RF** - Controlla stato RF all'avvio (default) |
|
||||
|
||||
## Installazione
|
||||
|
||||
### 1. Arduino IDE Setup
|
||||
|
||||
```
|
||||
Tools → Board → Arduino Pro or Pro Mini
|
||||
Tools → Processor → ATmega328P (3.3V, 8MHz)
|
||||
Tools → Programmer → (seleziona il tuo FTDI/USB-Serial)
|
||||
```
|
||||
|
||||
**Nota:** Il codice è compatibile con 8MHz. Le funzioni millis() e watchdog timer si adattano automaticamente alla frequenza del clock.
|
||||
|
||||
### 2. Upload Codice
|
||||
|
||||
1. Apri `src/src.ino` nell'Arduino IDE
|
||||
2. Abilita `#define DEBUG_SERIAL` per test
|
||||
3. Compila e carica (`Ctrl+U`)
|
||||
4. Apri Serial Monitor (9600 baud) per vedere l'output
|
||||
|
||||
### 3. Test Funzionalità
|
||||
|
||||
**Con DEBUG_SERIAL abilitato:**
|
||||
```
|
||||
Alarm Ready
|
||||
(Premi telecomando) → Sistema si arma
|
||||
(Scuoti sensore) → INTRUSIONE
|
||||
```
|
||||
|
||||
### 4. Produzione
|
||||
|
||||
1. Commenta `#define DEBUG_SERIAL`
|
||||
2. Ricompila e carica
|
||||
3. Sistema pronto per installazione
|
||||
|
||||
## Funzionamento
|
||||
|
||||
### Stati del Sistema
|
||||
|
||||
```
|
||||
DISARMED (Disarmato)
|
||||
↓ (RF HIGH)
|
||||
ARMING (Armamento - 2s)
|
||||
↓
|
||||
ARMED (Armato - lampeggio LED)
|
||||
↓ (Vibrazioni > soglia)
|
||||
TRIGGERED (Allarme - buzzer 5s)
|
||||
↓ (Timeout o RF LOW)
|
||||
DISARMED / ARMED
|
||||
```
|
||||
|
||||
### Rilevamento Vibrazioni Intelligente
|
||||
|
||||
Il sistema conta i **cambi di stato** del sensore in una finestra temporale:
|
||||
|
||||
- **Soglia default**: 80 cambi in 2000ms
|
||||
- **Vantaggio**: Filtra falsi positivi (vibrazioni stradali, vento)
|
||||
- **Personalizzabile**: Regola `VIBRATION_THRESHOLD` e `VIBRATION_WINDOW_MS`
|
||||
|
||||
**Esempio:**
|
||||
```
|
||||
Vibrazione stradale leggera → 5 cambi in 2s → Ignorata ✓
|
||||
Intrusione reale → 80+ cambi in 2s → ALLARME! ✓
|
||||
```
|
||||
|
||||
## Consumo Energetico
|
||||
|
||||
### Consumi per Stato
|
||||
|
||||
| Stato | Consumo | Durata Tipica |
|
||||
|-------|---------|---------------|
|
||||
| **DISARMED** | ~3.0 mA | Continuo |
|
||||
| **ARMING** | ~1.5 mA | 2 secondi |
|
||||
| **ARMED** | ~3.5 mA | Continuo |
|
||||
| **TRIGGERED** | ~32 mA | 5 secondi |
|
||||
|
||||
### Autonomia Stimata
|
||||
|
||||
**Con batteria 12V 7Ah:**
|
||||
- Allarme armato continuo: **~67 giorni**
|
||||
- Uso misto (8h armato/giorno): **~6 mesi**
|
||||
|
||||
**Con batteria 9V 500mAh:**
|
||||
- Allarme armato continuo: **~5 giorni**
|
||||
|
||||
### Breakdown Consumo (Armato)
|
||||
|
||||
```
|
||||
RX480E-4 (sempre on): 3.0 mA (86%)
|
||||
LED lampeggio (media): 0.1 mA (3%)
|
||||
ATmega328P (wake-up): 0.4 mA (11%)
|
||||
─────────────────────────────────
|
||||
TOTALE: 3.5 mA
|
||||
```
|
||||
|
||||
## Preparazione Hardware
|
||||
|
||||
### Arduino Pro Mini: Rimozione LED Power (Obbligatoria)
|
||||
|
||||
**Risparmio: ~10mA**
|
||||
|
||||
Il LED power sulla board Pro Mini consuma continuamente ~10mA e deve essere rimosso:
|
||||
|
||||
1. Individua il LED sempre acceso sulla scheda (solitamente vicino al regolatore)
|
||||
2. Dissalda il LED con saldatore a punta fine
|
||||
3. Verifica con multimetro la riduzione di consumo
|
||||
|
||||
### Sensore SW-420: Rimozione LED (Obbligatoria)
|
||||
|
||||
**Risparmio: ~15mA**
|
||||
|
||||
Il modulo SW-420 ha tipicamente 2 LED (power + signal) che consumano inutilmente:
|
||||
|
||||
1. Individua i 2 LED sul modulo SW-420
|
||||
2. Dissalda entrambi i LED con saldatore a punta fine
|
||||
3. Il sensore continuerà a funzionare normalmente via pin digitale D0
|
||||
|
||||
**Dopo rimozione LED:** Consumo totale sistema ridotto da ~28mA a ~3.5mA armato
|
||||
|
||||
### Ottimizzazione Opzionale: RF con Switch MOSFET
|
||||
|
||||
**Risparmio: ~3mA → autonomia >1 anno**
|
||||
|
||||
Aggiungi MOSFET P-channel per accendere RX solo periodicamente:
|
||||
- Complicato da implementare
|
||||
- Latenza attivazione fino a 10 secondi
|
||||
- Non consigliato per questo progetto
|
||||
|
||||
## Calibrazione
|
||||
|
||||
### Sensore SW-420: Regolazione Hardware
|
||||
|
||||
Il modulo SW-420 ha un potenziometro per regolare la sensibilità fisica:
|
||||
|
||||
1. Ruota il potenziometro completamente in senso orario (minima sensibilità)
|
||||
2. Alimenta il modulo e osserva l'uscita digitale D0
|
||||
3. Ruota gradualmente in senso antiorario fino a rilevare vibrazioni medie
|
||||
4. Evita di renderlo troppo sensibile (rileverà vibrazioni ambientali)
|
||||
|
||||
**Obiettivo:** Rilevare vibrazioni da intrusione ma ignorare vibrazioni stradali/vento
|
||||
|
||||
### Calibrazione Software Threshold
|
||||
|
||||
Dopo aver calibrato il potenziometro hardware:
|
||||
|
||||
1. Abilita `#define DEBUG_SERIAL`
|
||||
2. Carica il codice
|
||||
3. Arma il sistema
|
||||
4. Prova diverse intensità di vibrazione
|
||||
5. Osserva sul Serial Monitor quanti cambi vengono rilevati
|
||||
6. Regola `VIBRATION_THRESHOLD` di conseguenza
|
||||
|
||||
**Consigli:**
|
||||
- Soglia troppo bassa → Troppi falsi positivi
|
||||
- Soglia troppo alta → Sistema poco sensibile
|
||||
- Default 80 cambi/2s → Buon compromesso con SW-420
|
||||
|
||||
### Misura Consumo
|
||||
|
||||
Con multimetro in serie sulla linea VCC:
|
||||
```
|
||||
Sistema DISARMED → Deve leggere ~3.0mA
|
||||
Sistema ARMED → Deve leggere ~3.5mA (media)
|
||||
LED lampeggia → Picchi fino a 5-6mA
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Sistema non si arma
|
||||
- Verifica connessione RX480E-4
|
||||
- Controlla che telecomando trasmetta
|
||||
- Abilita DEBUG_SERIAL per diagnostica
|
||||
|
||||
### Troppi falsi positivi
|
||||
- Aumenta `VIBRATION_THRESHOLD`
|
||||
- Aumenta `VIBRATION_WINDOW_MS`
|
||||
- Verifica montaggio sensore vibrazione
|
||||
|
||||
### Consumo troppo alto
|
||||
- Verifica che RX sia modello a basso consumo
|
||||
- Rimuovi LED power da Pro Mini
|
||||
- Controlla che DEBUG_SERIAL sia disabilitato
|
||||
|
||||
### Serial Monitor non funziona
|
||||
- Verifica baud rate 9600
|
||||
- Controlla che `#define DEBUG_SERIAL` sia attivo
|
||||
- Verifica connessione FTDI (TX→RX, RX→TX)
|
||||
|
||||
## Tecniche Low Power Implementate
|
||||
|
||||
- ✅ **SLEEP_MODE_PWR_DOWN** - Consumo minimo 0.1µA
|
||||
- ✅ **Interrupt esterni** - Wake-up istantaneo
|
||||
- ✅ **Watchdog Timer** - Funziona in PWR_DOWN
|
||||
- ✅ **Disabilitazione moduli** - ADC, TWI, SPI, Timer2, USART
|
||||
- ✅ **Brown-out Detector disable** - Durante sleep
|
||||
- ✅ **Pin non usati OUTPUT LOW** - Riduce leakage current
|
||||
- ✅ **Eliminazione delay()** - Sostituiti con sleep
|
||||
- ✅ **LED low current** - 2mA invece di 20mA
|
||||
|
||||
## File del Progetto
|
||||
|
||||
```
|
||||
camper/
|
||||
├── src/
|
||||
│ └── src.ino # Codice principale
|
||||
├── README.md # Questo file
|
||||
└── .gitignore # Git ignore per Arduino
|
||||
```
|
||||
|
||||
## Licenza
|
||||
|
||||
Questo progetto è rilasciato come open source.
|
||||
|
||||
## Crediti
|
||||
|
||||
Sviluppato per sistema allarme camper ultra low power.
|
||||
Hardware target: Arduino Pro Mini 3.3V 8MHz (LED power dissaldato)
|
||||
|
||||
---
|
||||
|
||||
**Autonomia target raggiunta: 60+ giorni con batteria standard 12V 7Ah**
|
||||
422
src/src.ino
Normal file
422
src/src.ino
Normal file
@@ -0,0 +1,422 @@
|
||||
// ========== ULTRA LOW POWER ALARM SYSTEM ==========
|
||||
// Target: Arduino Pro Mini 3.3V 8MHz (ATmega328P, LED power dissaldato)
|
||||
// Sensore: SW-420 vibration sensor (LED dissaldati)
|
||||
// Sistema allarme camper ottimizzato per consumo minimo
|
||||
// Rilevamento intelligente: conta N cambi di stato in finestra temporale
|
||||
// Consumo atteso: ~3.5mA armato, autonomia 60+ giorni con 12V 7Ah
|
||||
|
||||
// ========== CONFIGURAZIONI UTENTE ==========
|
||||
// Decommentare per abilitare, commentare per disabilitare
|
||||
|
||||
#define DEBUG_SERIAL // Serial debug (DISABILITA per produzione, risparmio ~500µA)
|
||||
|
||||
// Stato iniziale allarme all'accensione del sistema
|
||||
// Opzioni disponibili:
|
||||
// 0 = ALWAYS_DISARMED - Parte sempre disarmato (ignora pin RF)
|
||||
// 1 = ALWAYS_ARMED - Parte sempre armato (ignora pin RF)
|
||||
// 2 = CHECK_RF - Controlla stato pin RF all'avvio (default)
|
||||
#define STARTUP_STATE 1
|
||||
|
||||
// Parametri rilevamento vibrazione intelligente
|
||||
#define VIBRATION_WINDOW_MS 2000 // Finestra temporale per conteggio vibrazioni (ms)
|
||||
#define VIBRATION_THRESHOLD 80 // Numero minimo cambi di stato per allarme
|
||||
#define VIBRATION_TIMEOUT_MS 3000 // Timeout inattività per reset contatore (ms)
|
||||
|
||||
#define TRIGGER_DURATION_MS 5000 // Durata allarme intrusione (ms)
|
||||
#define ARMING_DELAY_MS 2000 // Delay armamento (ms)
|
||||
|
||||
// ========== INCLUSIONI ==========
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
// ========== PIN DEFINITION ==========
|
||||
const uint8_t vibPin = 2; // INT0 - SW-420 vibration sensor D0 output
|
||||
const uint8_t buzzerPin = 9; // Output - Buzzer allarme
|
||||
const uint8_t ledPin = 13; // Output - LED status (lampeggio quando armato)
|
||||
const uint8_t ledIntrusionePin = 12; // Output - LED intrusione
|
||||
const uint8_t rfChannel = 6; // PCINT22 - RX480E-4 CH1
|
||||
|
||||
// ========== STATE MACHINE ==========
|
||||
enum AlarmState {
|
||||
STATE_DISARMED, // Allarme disattivo (PWR_DOWN continuo, consumo ~3mA)
|
||||
STATE_ARMING, // Armamento in corso (2 secondi, IDLE mode)
|
||||
STATE_ARMED, // Armato e monitoraggio (PWR_DOWN + WDT lampeggio, ~3.5mA)
|
||||
STATE_TRIGGERED // Intrusione rilevata (buzzer attivo 5 secondi)
|
||||
};
|
||||
|
||||
volatile AlarmState currentState = STATE_DISARMED;
|
||||
|
||||
// ========== FLAGS INTERRUPT (solo volatile bool) ==========
|
||||
volatile bool rfStatoChanged = false;
|
||||
volatile bool vibrationDetected = false; // Flag per interrupt vibrazione
|
||||
volatile bool wdtFired = false;
|
||||
|
||||
// ========== VARIABILI GLOBALI ==========
|
||||
bool ledState = false;
|
||||
unsigned long armingStartTime = 0;
|
||||
unsigned long triggerStartTime = 0;
|
||||
|
||||
// Tracciamento vibrazioni intelligente
|
||||
volatile uint8_t vibrationCount = 0; // Contatore cambi di stato
|
||||
volatile unsigned long firstVibrationTime = 0; // Timestamp prima vibrazione
|
||||
unsigned long lastVibrationTime = 0; // Timestamp ultima vibrazione (per timeout)
|
||||
|
||||
// ========== ISR - INTERRUPT SERVICE ROUTINES ==========
|
||||
// IMPORTANTE: ISR devono essere atomiche e brevissime!
|
||||
// Solo flag setting, nessun delay() o Serial.print()
|
||||
|
||||
// Watchdog Timer Interrupt (lampeggio LED ogni 500ms)
|
||||
ISR(WDT_vect) {
|
||||
wdtFired = true;
|
||||
}
|
||||
|
||||
// External Interrupt 0 (vibrazione rilevata su pin 2)
|
||||
// Conta i cambi di stato per rilevamento intelligente
|
||||
ISR(INT0_vect) {
|
||||
// ISR deve essere ATOMICA - solo operazioni minime!
|
||||
// Il timestamp verrà gestito nel loop principale
|
||||
vibrationCount++;
|
||||
vibrationDetected = true;
|
||||
}
|
||||
|
||||
// Pin Change Interrupt 2 (RF ricevitore cambio stato su pin 6)
|
||||
ISR(PCINT2_vect) {
|
||||
rfStatoChanged = true;
|
||||
}
|
||||
|
||||
// ========== FUNZIONI LOW POWER ==========
|
||||
|
||||
void disableUnusedPeripherals() {
|
||||
// ADC - non usato (sensore è digitale)
|
||||
ADCSRA &= ~(1 << ADEN); // Risparmio: ~200µA
|
||||
power_adc_disable();
|
||||
|
||||
// TWI/I2C - non usato
|
||||
power_twi_disable(); // Risparmio: ~10µA
|
||||
|
||||
// SPI - non usato
|
||||
power_spi_disable(); // Risparmio: ~5µA
|
||||
|
||||
// Timer2 - non usato
|
||||
power_timer2_disable(); // Risparmio: ~10µA
|
||||
|
||||
// USART - disabilita se non DEBUG_SERIAL
|
||||
#ifndef DEBUG_SERIAL
|
||||
power_usart0_disable(); // Risparmio: ~100µA
|
||||
#endif
|
||||
|
||||
// Timer0 - MANTENERE attivo per millis() (usato per tracking vibrazioni)
|
||||
// Timer1 - MANTENERE attivo (può servire per PWM buzzer)
|
||||
}
|
||||
|
||||
void setupPins() {
|
||||
// Output pins
|
||||
pinMode(buzzerPin, OUTPUT);
|
||||
pinMode(ledPin, OUTPUT);
|
||||
pinMode(ledIntrusionePin, OUTPUT);
|
||||
digitalWrite(buzzerPin, LOW);
|
||||
digitalWrite(ledPin, LOW);
|
||||
digitalWrite(ledIntrusionePin, LOW);
|
||||
|
||||
// Input pins
|
||||
pinMode(vibPin, INPUT); // Sensore vibrazione switch digitale
|
||||
pinMode(rfChannel, INPUT); // RF ricevitore
|
||||
|
||||
// Pin non usati → OUTPUT LOW per ridurre leakage current
|
||||
// Configurare tutti i pin non utilizzati
|
||||
for (uint8_t i = 0; i < 20; i++) {
|
||||
// Salta i pin che usiamo
|
||||
if (i == vibPin || i == buzzerPin || i == ledPin ||
|
||||
i == ledIntrusionePin || i == rfChannel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pinMode(i, OUTPUT);
|
||||
digitalWrite(i, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void setupInterrupts() {
|
||||
cli(); // Disable interrupts durante setup
|
||||
|
||||
// INT0 (vibrazione su pin 2) - ANY CHANGE per contare tutti i cambi di stato
|
||||
EICRA |= (1 << ISC00); // Any logical change trigger
|
||||
EICRA &= ~(1 << ISC01); // Clear ISC01 per ANY CHANGE mode
|
||||
EIMSK |= (1 << INT0); // Enable INT0
|
||||
|
||||
// PCINT22 (RF su pin 6) - Any change
|
||||
PCICR |= (1 << PCIE2); // Enable PCINT2 group (PCINT16-23)
|
||||
PCMSK2 |= (1 << PCINT22); // Enable only PCINT22 (pin D6)
|
||||
|
||||
sei(); // Re-enable interrupts
|
||||
}
|
||||
|
||||
void setupWatchdog_500ms() {
|
||||
cli();
|
||||
MCUSR &= ~(1 << WDRF); // Clear watchdog reset flag
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE); // Enter config mode
|
||||
WDTCSR = (1 << WDIE) | // Interrupt enable (non reset mode)
|
||||
(1 << WDP2) | (1 << WDP0); // Timeout 500ms (0b0101)
|
||||
sei();
|
||||
}
|
||||
|
||||
void disableWatchdog() {
|
||||
cli();
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE);
|
||||
WDTCSR = 0x00; // Turn off WDT
|
||||
sei();
|
||||
}
|
||||
|
||||
void enterSleep(uint8_t mode) {
|
||||
set_sleep_mode(mode);
|
||||
sleep_enable();
|
||||
sleep_bod_disable(); // Risparmio ~20µA durante sleep
|
||||
sei(); // Interrupt abilitati
|
||||
sleep_cpu(); // *** ENTRA IN SLEEP MODE ***
|
||||
// --- WAKE UP QUI quando interrupt viene triggerato ---
|
||||
sleep_disable();
|
||||
}
|
||||
|
||||
// ========== FUNZIONI RILEVAMENTO VIBRAZIONE INTELLIGENTE ==========
|
||||
|
||||
void resetVibrationCounter() {
|
||||
vibrationCount = 0;
|
||||
firstVibrationTime = 0;
|
||||
lastVibrationTime = 0;
|
||||
}
|
||||
|
||||
bool checkVibrationThreshold() {
|
||||
if (vibrationCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long now = millis();
|
||||
unsigned long elapsed = now - firstVibrationTime;
|
||||
|
||||
// Se superata la soglia nella finestra temporale → INTRUSIONE!
|
||||
if (vibrationCount >= VIBRATION_THRESHOLD && elapsed <= VIBRATION_WINDOW_MS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Se scaduta la finestra temporale senza superare soglia → reset
|
||||
if (elapsed > VIBRATION_WINDOW_MS) {
|
||||
resetVibrationCounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Se troppo tempo dall'ultima vibrazione → timeout, reset
|
||||
if (now - lastVibrationTime > VIBRATION_TIMEOUT_MS) {
|
||||
resetVibrationCounter();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== STATE HANDLERS ==========
|
||||
|
||||
void handleDisarmedState() {
|
||||
// Check RF per attivazione
|
||||
if (rfStatoChanged) {
|
||||
rfStatoChanged = false;
|
||||
if (digitalRead(rfChannel) == HIGH) {
|
||||
// Attiva allarme
|
||||
currentState = STATE_ARMING;
|
||||
armingStartTime = millis();
|
||||
digitalWrite(ledIntrusionePin, LOW);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Deep sleep continuo quando disarmato
|
||||
// Consumo: ~3mA (dominato da RX480E-4)
|
||||
enterSleep(SLEEP_MODE_PWR_DOWN);
|
||||
}
|
||||
|
||||
void handleArmingState() {
|
||||
// Check timeout armamento (2 secondi)
|
||||
if (millis() - armingStartTime >= ARMING_DELAY_MS) {
|
||||
// Armato!
|
||||
currentState = STATE_ARMED;
|
||||
setupWatchdog_500ms(); // Avvia lampeggio LED
|
||||
armingStartTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check RF durante armamento (possibile disattivazione)
|
||||
if (rfStatoChanged) {
|
||||
rfStatoChanged = false;
|
||||
if (digitalRead(rfChannel) == LOW) {
|
||||
// Disarmato durante armamento
|
||||
currentState = STATE_DISARMED;
|
||||
armingStartTime = 0;
|
||||
digitalWrite(ledPin, LOW);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep IDLE mode (Timer0 attivo per millis())
|
||||
enterSleep(SLEEP_MODE_IDLE);
|
||||
}
|
||||
|
||||
void handleArmedState() {
|
||||
// Check vibrazione rilevata dall'interrupt
|
||||
if (vibrationDetected) {
|
||||
vibrationDetected = false;
|
||||
unsigned long now = millis();
|
||||
lastVibrationTime = now;
|
||||
|
||||
// Se è la prima vibrazione, inizializza timestamp
|
||||
if (firstVibrationTime == 0) {
|
||||
firstVibrationTime = now;
|
||||
}
|
||||
|
||||
// Controlla se abbiamo superato la soglia
|
||||
if (checkVibrationThreshold()) {
|
||||
// INTRUSIONE confermata!
|
||||
currentState = STATE_TRIGGERED;
|
||||
disableWatchdog(); // Stop lampeggio durante trigger
|
||||
digitalWrite(ledPin, LOW);
|
||||
triggerStartTime = millis();
|
||||
digitalWrite(ledIntrusionePin, HIGH);
|
||||
digitalWrite(buzzerPin, HIGH);
|
||||
|
||||
// Reset contatore vibrazioni
|
||||
resetVibrationCounter();
|
||||
|
||||
#ifdef DEBUG_SERIAL
|
||||
Serial.println(F("INTRUSIONE"));
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check timeout vibrazioni (anche se non c'è nuovo interrupt)
|
||||
if (vibrationCount > 0) {
|
||||
checkVibrationThreshold(); // Gestisce timeout e reset automatico
|
||||
}
|
||||
|
||||
// Check RF per disattivazione
|
||||
if (rfStatoChanged) {
|
||||
rfStatoChanged = false;
|
||||
if (digitalRead(rfChannel) == LOW) {
|
||||
// Disarma
|
||||
currentState = STATE_DISARMED;
|
||||
disableWatchdog();
|
||||
digitalWrite(ledPin, LOW);
|
||||
digitalWrite(ledIntrusionePin, LOW);
|
||||
resetVibrationCounter(); // Reset contatore quando disarma
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Lampeggio LED via Watchdog Timer
|
||||
if (wdtFired) {
|
||||
wdtFired = false;
|
||||
ledState = !ledState;
|
||||
digitalWrite(ledPin, ledState);
|
||||
}
|
||||
|
||||
// Sleep PWR_DOWN tra lampeggi
|
||||
// Consumo: ~3.5mA medio (RX + lampeggio LED)
|
||||
enterSleep(SLEEP_MODE_PWR_DOWN);
|
||||
}
|
||||
|
||||
void handleTriggeredState() {
|
||||
// Check timeout trigger (5 secondi)
|
||||
if (millis() - triggerStartTime >= TRIGGER_DURATION_MS) {
|
||||
// Fine allarme
|
||||
digitalWrite(buzzerPin, LOW);
|
||||
digitalWrite(ledIntrusionePin, LOW);
|
||||
triggerStartTime = 0;
|
||||
|
||||
// Torna ad ARMED
|
||||
currentState = STATE_ARMED;
|
||||
setupWatchdog_500ms();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check RF per disattivazione durante trigger
|
||||
if (rfStatoChanged) {
|
||||
rfStatoChanged = false;
|
||||
if (digitalRead(rfChannel) == LOW) {
|
||||
// Disarmato durante trigger
|
||||
digitalWrite(buzzerPin, LOW);
|
||||
digitalWrite(ledIntrusionePin, LOW);
|
||||
triggerStartTime = 0;
|
||||
currentState = STATE_DISARMED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep IDLE durante trigger (millis() deve funzionare)
|
||||
enterSleep(SLEEP_MODE_IDLE);
|
||||
}
|
||||
|
||||
// ========== ARDUINO CORE FUNCTIONS ==========
|
||||
|
||||
void setup() {
|
||||
// 1. Disabilita moduli non usati SUBITO
|
||||
disableUnusedPeripherals();
|
||||
|
||||
// 2. Setup pin I/O
|
||||
setupPins();
|
||||
|
||||
// 3. Setup interrupt
|
||||
setupInterrupts();
|
||||
|
||||
// 4. Serial debug (solo se DEBUG_SERIAL)
|
||||
#ifdef DEBUG_SERIAL
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("Alarm Ready"));
|
||||
#endif
|
||||
|
||||
// 5. Imposta stato iniziale in base a STARTUP_STATE
|
||||
#if STARTUP_STATE == 0
|
||||
// ALWAYS_DISARMED - Parte sempre disarmato
|
||||
currentState = STATE_DISARMED;
|
||||
|
||||
#elif STARTUP_STATE == 1
|
||||
// ALWAYS_ARMED - Parte sempre armato
|
||||
currentState = STATE_ARMING;
|
||||
armingStartTime = millis();
|
||||
|
||||
#else
|
||||
// CHECK_RF - Controlla stato pin RF all'avvio (default)
|
||||
bool rfHigh = digitalRead(rfChannel);
|
||||
if (rfHigh) {
|
||||
currentState = STATE_ARMING;
|
||||
armingStartTime = millis();
|
||||
} else {
|
||||
currentState = STATE_DISARMED;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// State machine basata su interrupt
|
||||
// Il sistema passa la maggior parte del tempo in sleep
|
||||
// e si sveglia solo quando necessario
|
||||
|
||||
switch(currentState) {
|
||||
case STATE_DISARMED:
|
||||
handleDisarmedState();
|
||||
break;
|
||||
|
||||
case STATE_ARMING:
|
||||
handleArmingState();
|
||||
break;
|
||||
|
||||
case STATE_ARMED:
|
||||
handleArmedState();
|
||||
break;
|
||||
|
||||
case STATE_TRIGGERED:
|
||||
handleTriggeredState();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user