Alarm włamaniowy z rejestracją zdarzeń


Tomasz Bartuś



2016-03-22
Alarm włamaniowy z rejestracją zdarzeń

Wstęp

Projekt przedstawia urządzenie, które można wykorzystać w domu do kontroli antywłamaniowej pomieszczeń (Fig. 1). Założenia projektowe:

  • praca w trybie ciągłym,
  • detekcja ruchu w oparcu o czujnik ruchu PIR,
  • uzbrajane alarmu przyciskiem,
  • możliwość podłączenia zewnętrznych urządzeń alarmowych (np. lamp LED) na 220V,
  • podłączenie wyświetlacza ciekłokrystalicznego,
  • wykorzystanie modułu zegara czasu rzeczywistego,
  • sygnalizacja akustyczna alamu,
  • umożliwiemor rejestracji zdarzeń na karcie SD.

Urządzenie antywłamaniowe
Fig. 1. Urządzenie antywłamaniowe

Hardware

Sercem układu jest platforma Arduino Leonardo (Fig. 2). Do mikrokontrolera podłączono czujnik PIR DHT11. Dane z czujnika przekazywane są do pinu D12 Arduino. Kontrolę stanu urządzenia (alarm uzbrojony/nieuzbrojony) umożliwia mikroprzycisk, który jest podłączony do pinu D7. Oba piny (D12 i D7) wraz z sygnałami modułu zegara czasu rzeczywistego (I2C), stanową komplet sygnałów wejściowych urządzenia. Sygnały wyjściowe obsługują: buzzer odpowiedzialny za generowanie sygnałów akustycznych (D4), czerwoną diodę LED odpowiedzialną za sygnalizowanie wykrytej aktywności (D11), zieloną diodę LED odpowiedzialną za sygnalizowanie stanu alarmu (nieuzbrojony/uzbrajanie/uzbrojony) (D8), dwukanałowy moduł przekaźników umożliwiający podłączenie dwóch niezależnych urządzeń zewnętrznych (np. oświetlenia, D5 i D9) oraz moduł czytnika kart SD (złącze ICSP oraz D10). Dodatkowo, za pomocą magistrali I2C podłączono moduł wyświetlacza LCD.

Schemat ideowy

rototyp alarmu włamaniowego z rejestracją zdarzeń
Fig. 2. Prototyp alarmu włamaniowego z rejestracją zdarzeń

Działanie

Po włączeniu zasilania (5V), układ automatycznie przechodzi w tryb czuwania, w trakcie którego za pomocą pasywnego czujnika podczerwieni (PIR) monitorowana jest aktywność. Działanie czujnika oparte jest o precyzyjny pomiar temperatury otoczenia. Zastosowany czujnik HC-SR501 umożliwia skuteczną detekcję ruchu w promieniu do kilku metrów. W przypadku wykrycia aktywności, w zależności od ustawień czujnika (potencjometry czułości i opóźnienia), włączana jest dioda czerwona LED. Jednocześnie, na wyświetlaczu pojawia się komunikat o wykryciu aktywności. Właściwe funkcje alarmu uruchamiane są po uzbrojeniu urządzenia za pomocą przycisku.

Naciśnięcie przycisku powoduje uzbrojenie urządzenia. Następuje ono bezpośrednio po upłynięciu czasu potrzebnego na opuszczenie zabezpieczanej strefy. Czas opóźnienia ustawiono sztywno na 10 sekund. Podczas uzbrajania urządzenia, zielona dioda LED miga, a na wyświetlaczu LCD naprzemiennie pojawia się i znika komunikat "uzbrajanie". Po upłynięciu czasu uzbrajania, zielona dioda LED zostaje zaświecona na stałe, co sygnalizuje uzbrojenie alarmu i przejście urządzenia w tryb czuwania. Po uzbrojeniu alarmu, na wyświetlaczu LCD pojawia się komunikatu "uzbrojony". W tym samym czasie, na port szeregowy i na kartę SD wysyłany jest raport o treści: "data; godzina; Alarm rozbrojony". Po uzbrojeniu alarmu, stale wykonywana jest detekcja ruchu. Każde wykrycie aktywności jest sygnalizowane zaświeceniem czerwonej diody LED, odpowiednim komunikatem na wyświetlaczu LCD i dodatkowo sygnałem akustycznym oraz zwarciem obu przekaźników obsługujących urządzenia zewnętrzne. Zdarzenie jest także rejestrowane odpowienim zapisem na karcie SD oraz komunikatem wysyłanym na port szeregowy. Alarm jest anulowany po ustaniu aktywności, bądź po okresie zwłoki czujnika PIR wyznaczonej za pomocą odpowiedniego potencjometru. Ustanie aktywności jest rejestrowane na wyświetlaczu LCD, porcie szeregowym i karcie SD. Rozbrojenie alarmu następuje po kolejnym naciśnięciu przycisku. Zdarzenie rozbrojenia alarmu jest rejestrowane wyłączeniem zielonej diody LED, na wyświetlaczu LCD i porcie szeregowym oraz odpowiednim raportem zapisanym na karcie SD.

Lista części

  1. platforma Arduino (tu Leonardo),
  2. czujnik ruchu PIR HC-SR501,
  3. moduł zegara czasu rzeczywistego DS3231,
  4. dwukanałowy moduł przekaźników 5V,
  5. buzzer z generatorem 5V, 12mm,
  6. moduł czytnika kart SD,
  7. dioda LED czerwona,
  8. dioda LED zielona,
  9. mikroprzycisk,
  10. rezystory 100Ω, 280Ω, 330Ω,
  11. płytka prototypowa,
  12. przewody/mostki,
  13. zasilacz/bateria.

Film

Kod

#include "Wire.h"
#include <LiquidCrystal_I2C.h>
#include <SD.h>

boolean uzbrajanie = false;                 // Zmienna pomoc. do migania diodami podczasu uzbajania
boolean uzbrojony = false;                  // Zmienna uzbrojenia alarmu
int intruz = LOW;                           // Zmienna wykrycia ruchu
int val = 0;
int PRZYCISK_stan = LOW;                    // Zmienna pomoc. potrzebna do jednokrotnej rejestracji uzbrojenia/rozbrojenia alarmu
int INTRUZ_stan = LOW;                      // Zmienna pomoc. potrzebna do jednokrotnej rejestracji aktywności/ustania aktywności
int licznik;                                // Zmienna pomoc. dla obsługi przycisku
File logfile;

#define PRZYCISK 7
#define PRZEKAZNIK_1 5
#define PRZEKAZNIK_2 9
#define BUZZER 4
#define PIR 12
#define LED_UZBROJENIE 8
#define LED_ALARM 11
#define DS3231_I2C_ADDRESS 0x68
#define CZAS_WYJSCIA 10                      // W sekundach
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Ustawienie adresu ukladu na 0x27

//===========================================
// Funkcje pomocnicze

// Sygnał alarmu
void alarm() {
  tone(BUZZER, 4300);                        // Wygeneruj sygnał o częstotliwości 4300Hz
  delay(150);
  tone(BUZZER, 3500);                        // Wygeneruj sygnał o częstotliwości 3500Hz
  delay(150);
}

// Konwersja liczby dziesiętnej do postaci binarnej
byte decToBcd(byte val) {
  return ( (val / 10 * 16) + (val % 10) );
}

// Konwersja liczby binarnej do postaci dziesiętnej
byte bcdToDec(byte val) {
  return ( (val / 16 * 10) + (val % 16) );
}
//=================================================

void dateTimeWrite() {
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(10);

  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  delay(10);
  int sc = bcdToDec(Wire.read());    // Sekunda
  int mt = bcdToDec(Wire.read());    // Minuta
  int hr = bcdToDec(Wire.read());    // Godzina
  int dy = bcdToDec(Wire.read());    // Dzień
  int dt = bcdToDec(Wire.read());    // Data
  int mh = bcdToDec(Wire.read());    // Miesiąc
  int yr = bcdToDec(Wire.read());    // Rok

  logfile = SD.open("logfile.txt", FILE_WRITE);
  logfile.print(dt);
  logfile.print("-");
  logfile.print(mh);
  logfile.print("-");
  logfile.print(yr);
  logfile.print(" ");
  logfile.print(hr);
  logfile.print(":");
  logfile.print(mt);
  logfile.print(":");
  logfile.print(sc);
  logfile.close();

  Serial.print(dt);
  Serial.print("-");
  Serial.print(mh);
  Serial.print("-20");
  Serial.print(yr);
  Serial.print("; ");
  Serial.print(hr);
  Serial.print(":");
  Serial.print(mt);
  Serial.print(":");
  Serial.print(sc);
}
//===========================================

void setup() {
  Wire.begin();
  Serial.begin(9600);

  pinMode(PRZYCISK, INPUT_PULLUP);
  pinMode(PRZEKAZNIK_1, OUTPUT);
  pinMode(PRZEKAZNIK_2, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  pinMode(PIR, INPUT);
  pinMode(LED_UZBROJENIE, OUTPUT);
  pinMode(LED_ALARM, OUTPUT);

  digitalWrite(LED_UZBROJENIE, LOW);
  digitalWrite(LED_ALARM, LOW);

  lcd.begin(20, 4);
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Alarm: ");
  lcd.setCursor(0, 1);
  lcd.print("Stan: ");
  delay(500);

  //  while (!Serial) {                         //Wait for serial port to connect. Needed for Leonardo only
  //  }
  Serial.print("Inicjalizacja karty SD...\n");
  if (!SD.begin(10)) {
    Serial.println("Blad inicjalizacji karty SD!\n");
    return;
  }
  Serial.println("Karta jest gotowa do zapisu...\n");
}


//void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
//                   dayOfMonth, byte month, byte year)
//{
//  // ustawienie czasu i daty w DS3231
//  Wire.beginTransmission(DS3231_I2C_ADDRESS);
//  Wire.write(0);                    // określa, że następna wartość ma trafić do rejestru sekund
//  Wire.write(decToBcd(second));     // ustawienie sekund
//  Wire.write(decToBcd(minute));     // ustawienie minuty
//  Wire.write(decToBcd(hour));       // ustawienie godziny
//  Wire.write(decToBcd(dayOfWeek));  // ustawienie dnia tygodnia (1=niedziela, 7=sobota)
//  Wire.write(decToBcd(dayOfMonth)); // ustawienie dnia (1-31)
//  Wire.write(decToBcd(month));      // ustawienie miesiąca
//  Wire.write(decToBcd(year));       // ustawienie roku (0-99)
//  Wire.endTransmission();
//}

void readDS3231time(byte *second,
                    byte *minute,
                    byte *hour,
                    byte *dayOfWeek,
                    byte *dayOfMonth,
                    byte *month,
                    byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);                            // ustawia rejestr DS3231 na 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);  // żąda 7 bajtów danych od modułu DS3231 począwszy od rejestru 00h

  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

// Przekazanie danych do wyświetlenie w serial monitorze i do LCD
void displayTime() {
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

  // CZAS
  if (hour < 10) {                         // Godziny
    lcd.setCursor(0, 3);
    lcd.print("0");
    lcd.print(hour, DEC);
  } else {
    lcd.setCursor(0, 3);
    lcd.print(hour, DEC);
  }
  lcd.print(":");

  if (minute < 10) {                       // Minuty
    lcd.setCursor(3, 3);
    lcd.print("0");
    lcd.print(minute, DEC);
  } else {
    lcd.setCursor(3, 3);
    lcd.print(minute, DEC);
  }
  lcd.print(":");

  if (second < 10) {                       //Sekundy
    lcd.setCursor(6, 3);
    lcd.print("0");
    lcd.print(second, DEC);
  } else {
    lcd.setCursor(6, 3);
    lcd.print(second, DEC);
  }

  lcd.setCursor(0, 2);                      // DATA
  lcd.print("0");

  if (dayOfMonth < 10) {                    // Dzień
    lcd.setCursor(0, 2);
    lcd.print("0");
    lcd.print(dayOfMonth, DEC);
  } else {
    lcd.setCursor(0, 2);
    lcd.print(dayOfMonth, DEC);
  }
  lcd.print(".");

  if (month < 10) {                         // Miesiąc
    lcd.setCursor(3, 2);
    lcd.print("0");
    lcd.print(month, DEC);
  } else {
    lcd.setCursor(3, 2);
    lcd.print(month, DEC);
  }
  lcd.print(".");


  lcd.print("20");                          // Rok
  if (year < 10) {
    lcd.setCursor(8, 2);
    lcd.print("0");
    lcd.print(year, DEC);
  } else {
    lcd.setCursor(8, 2);
    lcd.print(year, DEC);
  }

  lcd.setCursor(9, 3);                      // Dzień tygodnia
  switch (dayOfWeek) {
    case 1:
      lcd.print("Niedziela");
      break;
    case 2:
      lcd.print("Poniedz.");
      break;
    case 3:
      lcd.print("Wtorek");
      break;
    case 4:
      lcd.print("Sroda");
      break;
    case 5:
      lcd.print("Czwartek");
      break;
    case 6:
      lcd.print("Piatek");
      break;
    case 7:
      lcd.print("Sobota");
      break;
  }
}

void loop() {
  displayTime();                            // wyświetlanie czasu rzeczywistego
  delay(1000);                              // odśwież co sekundę
  //======================================

  // Obsługa przycisku
  if (digitalRead(PRZYCISK) == LOW) {       // gdy wcisniemy przycisk
      delay(20);
    while (digitalRead(PRZYCISK) == LOW); { //sprawia, że pomimo trzymania przycisku wcisnietego zmiana nastapi tylko raz
      delay(20);
    }
    licznik++;
  }
  if (licznik % 2 == 0) {                   //gdy reszta z dzielenia przez 2 == 0
    uzbrojony = false;
  } else {
    uzbrojony = true;
  } 
  //======================================

  // Permanentne sprawdzanie stanu PIR
  val = digitalRead(PIR);                     // Reading the sensor value
  if (val == HIGH) {                          // if sensor is high
    digitalWrite(LED_ALARM, HIGH);
    delay(100);

    if (intruz == LOW) {
      //Serial.println("Wykryto ruch");
      intruz = HIGH;                          // Update the variable state in to HIGH
      lcd.setCursor(7, 1);
      lcd.print("intruz  ");
    }
  }
  else {
    digitalWrite(LED_ALARM, LOW);
    delay(200);

    if (intruz == HIGH) {
      lcd.setCursor(7, 1);
      lcd.print("czuwanie");
      intruz = LOW;                             // update the variable state into LOW
    }
  }
  //=========================================
  // Test uzbrojenia alarmu "UZBROJONY"

  if (uzbrojony == true) {                      // ALARM UZBROJONY

    //-----------------------------------------
    // OPÓŹNIENIE w UZBRAJANIU alarmu potrzebne do opuszczenia obszaru rejestracji
    if (uzbrajanie == false) {
      for (int i = 0; i <= CZAS_WYJSCIA; i++) { // LED_UZBROJENIE miga przez okres CZAS_WYJSCIA sekund
        lcd.setCursor(7, 0);
        lcd.print("uzbrajanie  ");              // napis "uzbrajanie" na wyświetlaczu LCD miga przez okres CZAS_WYJSCIA sekund
        digitalWrite(LED_UZBROJENIE, HIGH);
        delay(500);
        lcd.setCursor(7, 0);
        lcd.print("            ");
        digitalWrite(LED_UZBROJENIE, LOW);
        delay(500);
      }
      uzbrajanie = true;                         // zmiana stanu zmiennej uzbrajanie na "true" (znaczy: został uzbrojony)
    }
    //-----------------------------------------
                                                 // Po okresie opóźnienia uzbrajania, uzbrój alarm
    digitalWrite(LED_UZBROJENIE, HIGH);          // zaświeć LED_UZBROJENIE
    //Komunikat na Serial port 
    if(PRZYCISK_stan == LOW){
      dateTimeWrite();                           // zapisz na karcie SD i porcie szeregowym datę i godzinę
      Serial.println("; Alarm uzbrojony");       // wyślij na port szeregowy komunikat "Alarm uzbrojony"
      logfile = SD.open("logfile.txt", FILE_WRITE);
      logfile.println("; Alarm uzbrojony");      // Zapisz na karcie SD komunikat "Alarm uzbrojony"
      logfile.close();
      PRZYCISK_stan = HIGH;                      // ustaw zmienną sterującą na poziom HIGH
      }
     lcd.setCursor(7, 0);
     lcd.print("uzbrojony   ");
                                                  // Sprawdzenie stanu PIR
     if (intruz == HIGH) {                        // WYKRYTO AKTYWNOŚĆ
       digitalWrite(PRZEKAZNIK_1, LOW);           // włącz PRZEKAZNIK_1
       digitalWrite(PRZEKAZNIK_2, LOW);           // włącz PRZEKAZNIK_2
       alarm();                                   // włącz BUZZER
       if(INTRUZ_stan == LOW){                    // Test potrzebny do jednokrotnego wysłania komunikatu o wykryciu ruchu
         dateTimeWrite();                         // zapisz na karcie SD i porcie szeregowym datę i godzinę
         Serial.println("; Wykryto ruch");        // wyślij na port szeregowy komunikat "Wykryto ruch"
         logfile = SD.open("logfile.txt", FILE_WRITE);
         logfile.println("; Wykryto ruch");       // Zapisz na karcie SD komunikat "Wykryto ruch"
         logfile.close();
         INTRUZ_stan = HIGH;                      // ustaw zmienną sterującą na poziom HIGH
      }    
     } else {                                     // AKTYWNOŚĆ USTAŁA
       digitalWrite(PRZEKAZNIK_1, HIGH);          // wyłącz PRZEKAZNIK_1
       digitalWrite(PRZEKAZNIK_2, HIGH);          // wyłącz PRZEKAZNIK_2
       noTone(BUZZER);                            // wyłącz BUZZER
       if(INTRUZ_stan == HIGH){                   // Test potrzebny do jednokrotnego wysłania komunikatu o ustaniu ruchu
         dateTimeWrite();                         // zapisz na karcie SD i porcie szeregowym datę i godzinę
         Serial.println("; Ruch ustal");          // wyślij na port szeregowy komunikat "Wykryto ruch"
         logfile = SD.open("logfile.txt", FILE_WRITE);
         logfile.println("; Ruch ustal");         // Zapisz na karcie SD komunikat "Ruch ustal"
         logfile.close();
         INTRUZ_stan = LOW;                       // ustaw zmienną sterującą na poziom HIGH
       }     
     }

// Test uzbrojenia alarmu "NIEUZBROJONY"
  } else {
    noTone(BUZZER);                              // włącz BUZZER
    digitalWrite(LED_UZBROJENIE, LOW);           //zaświeć LED_UZBROJENIE
    //Komunikat na Serial port 
    if(PRZYCISK_stan == HIGH){
      dateTimeWrite();                           // zapisz na karcie SD i porcie szeregowym datę i godzinę
      Serial.println("; Alarm rozbrojony");      // wyślij na port szeregowy komunikat "Alarm uzbrojony"
      logfile = SD.open("logfile.txt", FILE_WRITE);
      logfile.println("; Alarm rozbrojony");     // Zapisz na karcie SD komunikat "Alarm rozbrojony"
      logfile.close();
      PRZYCISK_stan = LOW;                       // ustaw zmienną sterującą na poziom HIGH
      }
    
    digitalWrite(PRZEKAZNIK_1, HIGH);            // wyłącz PRZEKAZNIK_1
    digitalWrite(PRZEKAZNIK_2, HIGH);            // wyłącz PRZEKAZNIK_2
    lcd.setCursor(7, 0);
    lcd.print("nieuzbrojony");
    uzbrajanie = false;                          //zmienna pom. wykożystyw. podczas uzbrajania alarmu (miganie LED_UZBROJENIE). Aby uzbroić alarm zm. uzbrajanie musi być "false"
  }

}

 
 

Doktorat

Spis treści
Rozdzialy
Abstrakt [pl]
Abstract [eng]