Alarmă de curent PRO cu ATtiny85 (USB 5V)

Dispozitiv compact care anunță căderea sau revenirea curentului de la rețea prin buzzer și LED-uri. Alimentare de la un încărcător USB 5V, logică pe ATtiny85, comutator pentru moduri (Fail / Off / Return).

Descriere & cum funcționează

Dispozitivul monitorizează prezența tensiunii de 5V furnizată de un încărcător USB. La căderea alimentării, trece automat pe modul alimentat din acumulator și declanșează o alertă acustică continuă (configurabilă în firmware). La revenirea alimentării, emite o secvență de 3 beep-uri și semnalizează vizual prin LED-uri. Un comutator cu trei poziții permite selectarea rapidă a modului:

Conectorul USB-C este cablat ca UFP/Sink, cu rezistențe de 5.1 kΩ pe liniile CC pentru negocirea standard (VBUS 5V). Microcontrolerul ATtiny85 gestionează logica de stare, anti-debouncing pentru comutator și modelele de semnalizare. LED-urile indică rapid starea, iar buzzerul poate fi pasiv (prin driver tranzistor) sau activ (direct la 5V).

Schemă electronică

Schema electronică Alarmă de curent PRO cu ATtiny85
Schema completă a dispozitivului (click pentru versiunea PDF de rezoluție mare).

Bill of Materials (BOM)

Orientativ — ajustează după componentele tale finale.

RefDes Componentă Specificații Cant. Note
U1 ATtiny85-20SU MCU 8-bit, 5V, SOIC-8/TSSOP-8 1 Frecv. internă; ISP prin header 2×3
J1 USB-C Receptacle UFP/Sink, doar alimentare (VBUS + CC) 1 CC1/CC2 cu Rd = 5.1 kΩ
R1, R2 Rezistențe CC 5.1 kΩ ±1% 2 Rd pentru CC1/CC2 → GND
C1, C2 Decuplare 100 nF, 10 µF / 16V 2 Lângă U1 și VBUS
D1 TVS VBUS SMBJ5.0A sau USB ESD 1 Protecție ESD/Surge
F1 Siguranță PTC Resetabilă 0.5–1.0 A 1 Protecție la scurt
SW1 Comutator 3 poziții ON-OFF-ON (SPDT) 1 Moduri: FAIL / OFF / RETURN
LED1, LED2 LED status Verde / Roșu + R serie 2 R ~1–2 kΩ la 5V
BZ1 Buzzer 5V activ sau pasiv 1 Pasiv → driver tranzistor (Q1)
Q1, Rb Driver buzzer (opțional) NPN + 1–4.7 kΩ 1+1 Pentru buzzer pasiv
J2 Header ISP 2×3, 2.54 mm 1 Programare USBasp/UNO-as-ISP

Video demonstrativ

Galerie

Alarmă de curent PRO în carcasă – vedere față
Vedere generală a dispozitivului montat în carcasă.
Alarmă de curent PRO în carcasă – vedere interior
Vedere generală a dispozitivului în interior.
Detaliu PCB cu ATtiny85, buzzer și conector USB-C
Detaliu PCB: ATtiny85, driver buzzer, conector USB-C.

Firmware ATtiny85

Vezi codul complet

// ATtiny85 (ATTinyCore): 0->PB0, 1->PB1, 2->PB2, 3->PB3, 4->PB4
const uint8_t BUZZ_PIN   = 0; // PB0  (HIGH = ON prin MOSFET)
const uint8_t LED_GREEN  = 1; // PB1  (ACTIVE-LOW: LOW = ON)
const uint8_t NET_SENSE  = 2; // PB2  (LM393: HIGH=curent prezent, LOW=pană)
const uint8_t SW_ON1     = 3; // PB3  (ON=LOW) -> CĂDERE
const uint8_t SW_ON2     = 4; // PB4  (ON=LOW) -> REVENIRE

inline void led_on(uint8_t p){ digitalWrite(p, LOW); }   // active-low
inline void led_off(uint8_t p){ digitalWrite(p, HIGH); }

const uint16_t DEBOUNCE_MS     = 50;

// --- Parametri sunet ---
const uint16_t OUTAGE_ON_MS    = 400; // model intermitent cât timp e pană (ON)
const uint16_t OUTAGE_OFF_MS   = 300; // model intermitent cât timp e pană (OFF)

const uint16_t BEEP_MS_EVENT   = 180; // pentru „revenire” (3 bipuri)
const uint16_t BEEP_MS_PAUSE   = 120;

// --- Stări ---
bool net_present=false, net_prev=false;

// pentru modelul intermitent la pană
bool          buzz_state = false;
unsigned long buzz_t0    = 0;
bool          in_outage_pattern = false;

bool read_net_debounced(){
  static bool stable=false; static unsigned long t0=0;
  bool raw = digitalRead(NET_SENSE); // HIGH=prezent
  if (raw != stable){
    if (millis()-t0 >= DEBOUNCE_MS){ stable = raw; t0 = millis(); }
  } else { t0 = millis(); }
  return stable;
}

inline void buzz_on()  { digitalWrite(BUZZ_PIN, HIGH); buzz_state = true;  }
inline void buzz_off() { digitalWrite(BUZZ_PIN, LOW);  buzz_state = false; }

void triple_beep(){
  for (uint8_t i=0; i<3; i++){
    buzz_on();  delay(BEEP_MS_EVENT);
    buzz_off(); delay(BEEP_MS_PAUSE);
  }
}

// Rulează modelul intermitent non-blocking cât timp e pană (ON-1 activ)
void outage_buzz_tick(){
  static uint16_t current_slice = OUTAGE_ON_MS; // durata segmentului curent
  if (!in_outage_pattern){
    // inițializare la intrarea în mod
    in_outage_pattern = true;
    buzz_on();
    buzz_t0 = millis();
    current_slice = OUTAGE_ON_MS;
  }
  unsigned long now = millis();
  if (now - buzz_t0 >= current_slice){
    // schimbă starea și durata
    if (buzz_state){
      buzz_off();
      current_slice = OUTAGE_OFF_MS;
    } else {
      buzz_on();
      current_slice = OUTAGE_ON_MS;
    }
    buzz_t0 = now;
  }
}

void reset_outage_buzz(){
  in_outage_pattern = false;
  buzz_off();
}

void setup(){
  pinMode(BUZZ_PIN,  OUTPUT); buzz_off();
  pinMode(LED_GREEN, OUTPUT); led_off(LED_GREEN);
  pinMode(NET_SENSE, INPUT);
  pinMode(SW_ON1,    INPUT_PULLUP); // ON=LOW (centrul la GND)
  pinMode(SW_ON2,    INPUT_PULLUP);

  net_prev = net_present = digitalRead(NET_SENSE);
  if (net_present) led_on(LED_GREEN); else led_off(LED_GREEN);
}

void loop(){
  const bool on1 = (digitalRead(SW_ON1)==LOW);   // ON-1: cădere
  const bool on2 = (digitalRead(SW_ON2)==LOW);   // ON-2: revenire
  const bool off_mode = (!on1 && !on2) || (on1 && on2);

  net_prev    = net_present;
  net_present = read_net_debounced();

  // LED verde (prezent curent)
  if (net_present) led_on(LED_GREEN);
  else             led_off(LED_GREEN);
  // LED roșu e hardware via comparator (nu-l comandăm din cod)

  // Edge-uri
  const bool fell =  (net_prev && !net_present); // a căzut curentul
  const bool rose = (!net_prev &&  net_present); // a revenit curentul

  if (off_mode){
    reset_outage_buzz();               // mut în OFF
  } else {
    // ON-1: pană -> intermitent permanent
    if (on1){
      if (!net_present){
        outage_buzz_tick();            // rulează modelul non-blocking
      } else {
        reset_outage_buzz();           // dacă a revenit
      }
    }
    // ON-2: revenire -> 3 bipuri scurte (o singură dată pe eveniment)
    if (on2){
      if (rose){
        // ne asigurăm că nu rămâne moștenită starea din modelul de pană
        reset_outage_buzz();
        triple_beep();
      }
      // în rest, tăcem
    }
  }

  delay(2); // mic respiro
}