/***Poznamky * Senzor otresu je hodne citlivy * Zadani kodu pro otevreni pri alarmu se pocita jako chybny kod * Tlacitko rotacniho enkoderu obcas nerozpoznava kratke stisky * Zluta barva na RGB LED vypada jako zelena * Enkoder obcas preskoci vice cislic najednou */ /***Zapojeni **Prepinac P1 --------- 5V COM -------- PIN_SW P2 --------- GND **RGB LED R ---------- PIN_RGB_R G ---------- PIN_RGB_G B ---------- PIN_RGB_B - ---------- GND **I2C LCD GND -------- GND VCC -------- 5V SDA -------- SDA SCL -------- SCL **Rotacni enkoder GND -------- GND + -------- 5V SW -------- PIN_ROT_SW DT -------- PIN_ROT_DT CLK -------- PIN_ROT_CLK **Senzor otresu P1 --------- GND P2 --------- PIN_SHAKE **Senzor pohybu P1 --------- GND P2 --------- PIN_MOTION P3 --------- 5V ***/ #include #define PIN_SW 2 #define PIN_ROT_CLK 19 //Pouziva preruseni #define PIN_ROT_DT 16 #define PIN_ROT_SW 24 //Pouziva preruseni #define PIN_MOTION 3 //Pouziva preruseni #define PIN_RGB_R 7 #define PIN_RGB_G 6 #define PIN_RGB_B 5 #define PIN_SHAKE 18 //Pouziva preruseni #define LCD_FRAME_DELAY 250 #define LCD_COLS 16 #define LCD_ROWS 2 #define LCD_CURSOR_BLINK 500 #define RGB_LED_BLINK 250 #define ROT_SW_DEBOUNCE 125 #define ROT_SW_RELEASE_DEBOUNCE 200 #define MOTION_END_TIME 3000 #define S_CLOSE 0 #define S_OPEN 1 #define S_ALARM 2 #define M_NIGHT false #define M_DAY true LiquidCrystal_I2C lcd(0x27, LCD_COLS, LCD_ROWS); int lcd_frame_n = 0; unsigned long lcd_prev_frame = 0; unsigned long lcd_cursor_prev_blink = millis(); unsigned long last_motion_report = 0; unsigned long rgb_led_prev_blink = millis(); bool rgb_led_state = false; bool lcd_cursor_state = false; bool shake_trig = false; bool mode_chg = false; bool rot_sw_done = false; char lcd_text_new[25]; char lcd_text_old[25]; bool lcd_repeat = false; bool lcd_invert_dir = false; unsigned long rot_sw_time = 0; unsigned long rot_sw_release_time = 0; bool rot_sw_down = false; int state = S_CLOSE; volatile bool mode = M_NIGHT; volatile short rot_val = 0; volatile bool motion_trig = false; volatile unsigned long motion_trig_time = 0; volatile unsigned long motion_trig_end_time = 0; int code_pos = -1; int wrong_codes = 0; char code[4]; char open_code1[4] = {5, 7, 0, 3}; char open_code2[4] = {6, 2, 1, 9}; char alarm_code[4] = {3, 4, 9, 7}; void setup() { //Nastaveni lcd lcd.init(); lcd.backlight(); lcd_set_text("Nocni rezim"); lcd_invert_dir = true; lcd_repeat = true; //Nastaveni pinu pinMode(PIN_SW, INPUT); pinMode(PIN_ROT_CLK, INPUT); pinMode(PIN_ROT_DT, INPUT); pinMode(PIN_MOTION, INPUT); pinMode(PIN_ROT_SW, INPUT_PULLUP); pinMode(PIN_RGB_R, OUTPUT); pinMode(PIN_RGB_G, OUTPUT); pinMode(PIN_RGB_B, OUTPUT); pinMode(PIN_SHAKE, INPUT_PULLUP); //Nastaveni preruseni attachInterrupt(digitalPinToInterrupt(PIN_SW), sw_int, CHANGE); attachInterrupt(digitalPinToInterrupt(PIN_ROT_CLK), rot_int, RISING); attachInterrupt(digitalPinToInterrupt(PIN_MOTION), motion_int, RISING); attachInterrupt(digitalPinToInterrupt(PIN_SHAKE), shake_int, RISING); interrupts(); //Nastaveni komunikace Serial.begin(9600); Serial.println("System pro ovladani trezoru byl aktivovan"); } void loop() { //Cteni z terminalu while (Serial.available() > 0) { char c = Serial.read(); if (c == 'Q') { state = S_CLOSE; Serial.println("Alarm vypnut"); } else if (c == 'S') { if (mode == M_NIGHT) { Serial.print("Rezim NOC, "); if (state == S_ALARM) { Serial.println("Alarm"); } else if (motion_trig) { Serial.println("detekovan pohyb"); } else { Serial.println("bez Alarmu"); } } else { Serial.print("Rezim DEN, "); if (state == S_OPEN) { Serial.println("Stav Otevreno"); } else if (state == S_CLOSE) { Serial.println("Stav Zavreno"); } else { Serial.println("Alarm"); } } } else if (c == 'R') { if (mode == M_NIGHT) { mode = M_DAY; mode_chg = true; } else if (state != S_OPEN) { mode = M_NIGHT; mode_chg = true; } } } //Oznameni zmeny rezimu if (mode_chg) { mode_chg = false; if (mode == M_NIGHT) { Serial.println("Rezim NOC"); } else { Serial.println("Rezim DEN"); } } //Tlacitko rotacniho enkoderu if (digitalRead(PIN_ROT_SW) == LOW && !rot_sw_down) { rot_sw_down = true; if (millis() - rot_sw_release_time > ROT_SW_RELEASE_DEBOUNCE) { rot_sw_done = false; rot_sw_time = millis(); } } else if (rot_sw_down) { rot_sw_down = false; rot_sw_release_time = millis(); if (!rot_sw_done && millis() - rot_sw_time > ROT_SW_DEBOUNCE && mode == M_DAY && (state == S_CLOSE || state == S_ALARM)) { rot_sw_done = true; code_pos++; rot_val = 0; if (code_pos == 0) { memset(code, 0, 4); } if (code_pos == 4) { //Vyhodnoceni kodu code_pos = -1; if (strncmp(code, open_code1, 4) == 0 && state == S_CLOSE) { //Kod na otevreni 1 state = S_OPEN; } else if (strncmp(code, open_code2, 4) == 0 && state == S_CLOSE) { //Kod na otevreni 2 state = S_OPEN; } else if (strncmp(code, alarm_code, 4) == 0 && state == S_ALARM) { //Kod na vypnuti alarmu state = S_CLOSE; Serial.println("Alarm vypnut"); } else { //Alarm po 3 chybnych kodech wrong_codes++; if (wrong_codes == 3) { wrong_codes = 0; Serial.println("Chybny kod"); state = S_ALARM; } } } } else if (!rot_sw_done && millis() - rot_sw_time > 3000 && state == S_OPEN) { //Zavreni trezoru rot_sw_done = true; state = S_CLOSE; } } //Oznameni otresu (Alarm se spousti v ISR) if (shake_trig) { Serial.println("Podezrele otresy!"); shake_trig = false; } //Senzor pohybu if (mode == M_NIGHT) { if (motion_trig) { if (millis() - last_motion_report > 1000) { Serial.println("Podezrely pohyb"); last_motion_report = millis(); } } if (digitalRead(PIN_MOTION) && motion_trig) { if (millis() - motion_trig_time > 3000) { state = S_ALARM; } } else { motion_trig = false; } } //Cteni kodu z enkoderu if (code_pos != -1) { code[code_pos] = rot_val / 2; } //Nastaveni textu na LCD if (mode == M_DAY) { lcd_repeat = false; lcd_invert_dir = false; if (state == S_OPEN) { lcd_set_text("Otevreno"); } else if (state == S_CLOSE) { lcd_set_text("Zavreno"); } else { lcd_set_text("Alarm"); } } else { lcd_repeat = true; lcd_invert_dir = true; lcd_set_text("Nocni rezim"); } //Vypsani na LCD a rosviceni RGB LED lcd_update(); rgb_led_update(); } //ISR pro senzor pohybu void motion_int() { motion_trig = true; if (millis() - motion_trig_time > MOTION_END_TIME) { motion_trig_time = millis(); } } //ISR pro senzor otresu void shake_int() { if (state == S_CLOSE) { shake_trig = true; state = S_ALARM; } } //ISR pro prepinac void sw_int() { if (state == S_CLOSE || state == S_ALARM) { mode = !mode; mode_chg = true; } code_pos = -1; } //ISR pro rotacni enkoder void rot_int() { if (digitalRead(PIN_ROT_DT)) { rot_val++; } else { rot_val--; } rot_val += 20; rot_val = rot_val % 20; } //Funkce pro rozsviceni RGB LED void rgb_led_update() { if (millis() - rgb_led_prev_blink > RGB_LED_BLINK) { rgb_led_state = !rgb_led_state; rgb_led_prev_blink = millis(); } if (mode == M_DAY && state == S_CLOSE) { digitalWrite(PIN_RGB_R, LOW); digitalWrite(PIN_RGB_G, HIGH); digitalWrite(PIN_RGB_B, LOW); } else if (mode == M_DAY && state == S_OPEN) { digitalWrite(PIN_RGB_R, LOW); digitalWrite(PIN_RGB_G, rgb_led_state); digitalWrite(PIN_RGB_B, LOW); } else if (mode == M_DAY && state == S_ALARM) { digitalWrite(PIN_RGB_R, rgb_led_state); digitalWrite(PIN_RGB_G, LOW); digitalWrite(PIN_RGB_B, LOW); } else if (mode == M_NIGHT && state != S_ALARM && motion_trig) { digitalWrite(PIN_RGB_R, HIGH); digitalWrite(PIN_RGB_G, HIGH); digitalWrite(PIN_RGB_B, LOW); } else if (mode == M_NIGHT && state != S_ALARM) { digitalWrite(PIN_RGB_R, LOW); digitalWrite(PIN_RGB_G, LOW); digitalWrite(PIN_RGB_B, HIGH); } else if (mode == M_NIGHT && state == S_ALARM) { digitalWrite(PIN_RGB_R, rgb_led_state); digitalWrite(PIN_RGB_G, rgb_led_state); digitalWrite(PIN_RGB_B, LOW); } } //Funkce pro nastaveni animaovaneho textu void lcd_set_text(char * text) { if (strcmp(text, lcd_text_new) == 0)return; lcd_prev_frame = millis(); lcd_frame_n = 0; strcpy(lcd_text_old, lcd_text_new); strcpy(lcd_text_new, text); } //Funcke pro vypsani na LCD void lcd_update() { if (millis() - lcd_cursor_prev_blink > LCD_CURSOR_BLINK) { lcd_cursor_prev_blink = millis(); lcd_cursor_state = ! lcd_cursor_state; } if (code_pos != -1 && mode == M_DAY) { lcd.setCursor(0, 1); for (int i = 0; i < 4; i++) { if (i < code_pos) { lcd.print("*"); } else if (i == code_pos) { if (lcd_cursor_state) { lcd.print("_"); } else { lcd.print((int)code[i]); } } } } else { lcd_clear_row(1); } if (lcd_frame_n == -1)return; if (millis() - lcd_prev_frame > LCD_FRAME_DELAY) { lcd.noDisplay(); lcd_clear_row(0); lcd_prev_frame = millis(); int old_text_trg_pos = 8 - strlen(lcd_text_old) / 2; int new_text_trg_pos = 8 - strlen(lcd_text_new) / 2; int old_text_pos = old_text_trg_pos - lcd_frame_n; if (lcd_invert_dir) { old_text_pos = old_text_trg_pos + lcd_frame_n; } int new_text_pos = (old_text_trg_pos + 17) - lcd_frame_n; if (lcd_invert_dir) { new_text_pos = (old_text_trg_pos - 16) + lcd_frame_n; } lcd_print_safe(lcd_text_old, old_text_pos, 0); lcd_print_safe(lcd_text_new, new_text_pos, 0); lcd_frame_n++; lcd.display(); if (new_text_pos == new_text_trg_pos) { strcpy(lcd_text_old, lcd_text_new); if (!lcd_repeat) { lcd_frame_n = -1; } else { lcd_frame_n = 1; } } } } //Funkce pro vypsani na LCD s ochranou proti vypisu na neplatne pozice void lcd_print_safe(char * text, int col, int row) { int len = strlen(text); for (int i = 0; i < len; i++) { if (col + i < 16 && col + i >= 0) { lcd.setCursor(col + i, row); lcd.write(text[i]); } } } //Funkce pro smazani radku na LCD void lcd_clear_row(int row) { lcd.setCursor(0, row); for (int i = 0; i < LCD_COLS; i++) { lcd.print(" "); } }