/****************************************
Progetto : SoftAir Bomb
Autore : L.M.
Data : 03/10/2022
Modifica : 13/10/2022
Versione : V 1.0
/***************************************/
// Variabili e/o costanti di Sistema
bool debug = true, first = true;
byte filo[] = {14, 15, 16, 17};
byte stato_fili [4] = {};
byte filo_ok;
#define buzzer 3
#define rele 12
int time_rele;
// definizione led neopixel
#include <Adafruit_NeoPixel.h>
#define LED_PIN 2
#define LED_COUNT 16
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// definizioni per tastiera 4x4
#include <Wire.h>
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
{'1','2','3','a'}
,
{'4','5','6','b'}
,
{'7','8','9','c'}
,
{'*','0','#','d'}
};
byte rowPins[ROWS] = {
11, 10, 9, 8};
byte colPins[COLS] = {
7, 6, 5, 4
};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
// definizione per display LCD
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
int Hours = 00;
int Minutes = 00;
int Seconds = 00;
int trycount = 0;
int keycount = 0;
int i = 0;
int redled = 4;
int yellowled = 3;
int greenled = 2;
int hourstenscode;
int hoursonescode;
int mintenscode;
int minonescode;
int sectenscode;
int seconescode;
long secMillis = 0;
long interval = 1000;
const byte lung_psw = 6;
char password[lung_psw];
char entered[lung_psw];
// routine per il restar del games a fine attività
void(* Riavvia)(void) = 0;
void setup() {
// init serial monitor
if(debug){
Serial.begin(9600);
Serial.println("AirSoft Bomb");
}
// init LCD
lcd.init();
lcd.backlight();
// init Buzzer
tone(buzzer,2400,300);
// init I/O
for(byte j = 14; j <= 17; j++){
pinMode(j, INPUT_PULLUP);
}
pinMode(rele, OUTPUT);digitalWrite(rele, LOW);
delay(50);
pinMode(rele, OUTPUT);digitalWrite(rele, HIGH);
bool app = true;
for(byte j = 14; j <= 17; j++){
if(digitalRead(j) != LOW)app = false;
}
if(app == false){
lcd.print("Filo scollegato");
if(debug)Serial.println("Filo scollegato");
while(1);
}
// init led ws2812 neopixel
strip.begin();
strip.show();
strip.setBrightness(50);
colorWipe(strip.Color(200, 200, 200), 30);
delay(1000);
// controllo tensione batteria
readVcc();
if (readVcc() >= 3800) {
lcd.setCursor(0, 0);
lcd.print("Tensione = ");
lcd.print(readVcc() / 1000.00);
lcd.print("v");
lcd.setCursor(0, 1);
lcd.print("Ottimo !");
delay(3000);
} else {
lcd.setCursor(0, 0);
lcd.print("Tensione = ");
lcd.print(readVcc() / 1000.00);
lcd.print("v");
lcd.setCursor(0, 1);
lcd.print("Sostituire");
if(debug)Serial.println("Tensione bassa");
while(1);
}
configurazione();
}
void loop(){
timer();
char disarmcode = keypad.getKey();
// controllo dei fili
for(byte j = 0; j < 4; j++){
stato_fili[j] = digitalRead(filo[j]);
}
for(byte j = 0; j < 4; j++){
if(stato_fili[j] == HIGH){
Serial.println(j);
if(filo_ok == j){
lcd.noBlink();
lcd.clear();
lcd.home();
lcd.print(" La bomba e' ");
lcd.setCursor(0, 1);
lcd.print("!! DISARMATA !!");
strip.setPixelColor(i, strip.Color(0, 0, 200));
strip.show();
delay(2000);
Riavvia();
}else{
if(first){
interval = 400;
first = false;
}
}
}
}
if (disarmcode == '*') {
tone(buzzer, 5000, 100);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Code: ");
while (keycount < lung_psw) {
timer();
char disarmcode = keypad.getKey();
if (disarmcode == '#') {
tone(buzzer, 5000, 100);
keycount = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Code: ");
}
else if (disarmcode != NO_KEY) {
lcd.setCursor(keycount + 7, 0);
lcd.blink();
lcd.print(disarmcode);
entered[keycount] = disarmcode;
keycount++;
tone(buzzer, 5000, 100);
delay(100);
lcd.noBlink();
lcd.setCursor(keycount + 6, 0);
lcd.print("*");
lcd.setCursor(keycount + 7, 0);
lcd.blink();
}
}
Serial.println(digitalRead(filo[filo_ok]));
if (keycount == lung_psw) {
if (entered[0] == password[0] && entered[1] == password[1] && entered[2] == password[2] && entered[3] == password[3] && entered[4] == password[4] && entered[5] == password[5]) {
lcd.noBlink();
lcd.clear();
lcd.home();
lcd.print(" La bomba e' ");
lcd.setCursor(0, 1);
lcd.print("!! DISARMATA !!");
keycount = 0;
for(int j = 0; j < 10; j++){
for(int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(0, 0, 200));
}
strip.show();
delay(500);
for(int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(0, 0, 0));
}
strip.show();
delay(500);
}
Riavvia();
} else {
lcd.noBlink();
lcd.clear();
lcd.home();
lcd.print("Password ERRATA!");
trycount++;
if (Hours > 0) {
Hours = Hours / 2;
}
if (Minutes > 0) {
Minutes = Minutes / 2;
}
if (Seconds > 0) {
Seconds = Seconds / 2;
}
if (trycount == 2) {
interval = interval / 10;
}
if (trycount == 3) {
Minutes = Minutes - 59;
Hours = Hours - 59;
Seconds = Seconds - 59;
}
delay(1000);
keycount = 0;
}
}
}
}
void timer(){
if (Hours <= 0) {
if ( Minutes < 0 ) {
lcd.noBlink();
lcd.clear();
lcd.home();
lcd.print("Tempo trascorso");
lcd.setCursor (0, 1);
lcd.print(" Bomba ESPLOSA ");
for(int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(200, 0, 0));
}
strip.show();
tone(buzzer, 7000, 2000);
while (Minutes < 0) {
digitalWrite(rele, LOW);
delay(time_rele);
digitalWrite(rele, HIGH);
Minutes = 1;
}
Riavvia();
}
}
lcd.setCursor (0, 1);
lcd.print ("Timer: ");
if (Hours >= 10) {
lcd.setCursor (7, 1);
lcd.print (Hours);
}
if (Hours < 10) {
lcd.setCursor (7, 1);
lcd.print ("0");
lcd.setCursor (8, 1);
lcd.print (Hours);
}
lcd.print (":");
if (Minutes >= 10) {
lcd.setCursor (10, 1);
lcd.print (Minutes);
}
if (Minutes < 10) {
lcd.setCursor (10, 1);
lcd.print ("0");
lcd.setCursor (11, 1);
lcd.print (Minutes);
}
lcd.print (":");
if (Seconds >= 10) {
lcd.setCursor (13, 1);
lcd.print (Seconds);
}
if (Seconds < 10) {
lcd.setCursor (13, 1);
lcd.print ("0");
lcd.setCursor (14, 1);
lcd.print (Seconds);
}
if (Hours < 0) {
Hours = 0;
}
if (Minutes < 0) {
Hours --;
Minutes = 59;
}
if (Seconds < 1) {
Minutes --;
Seconds = 59;
}
if (Seconds > 0) {
unsigned long currentMillis = millis();
if (currentMillis - secMillis > interval) {
tone(buzzer, 7000, 50);
secMillis = currentMillis;
Seconds --;
colorWipe(strip.Color(0, 200, 0), 10);
}
}
}
// configurazione parametri bomba
void configurazione(){
// set tempo eccitazione relè
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Tempo attivare ");
lcd.setCursor(0, 1);
lcd.print("Rele = ");
while (keycount == 0) {
lcd.blink();
char app = keypad.getKey();
if(app != NO_KEY){
if(app > '0' && app < '7'){
time_rele = ((app & 0x07) * 1000) + 1000;
lcd.print(app);
lcd.noBlink();
tone(buzzer, 5000, 100);
keycount++;
delay(2000);
}
}
}
if(debug){
Serial.print("Tempo relè = ");Serial.println(time_rele/1000)-1;
}
// selezione del filo per disinnesco
keycount = 0;
lcd.setCursor(0, 0);
lcd.print("Filo disinnesco ");
lcd.setCursor(0, 1);
lcd.print("Num = ");
while (keycount == 0) {
lcd.blink();
char app = keypad.getKey();
if(app != NO_KEY){
if(app > '0' && app < '5'){
filo_ok = (app & 0x03) - 1;
lcd.print(app);
lcd.noBlink();
tone(buzzer, 5000, 100);
keycount++;
delay(2000);
}
}
}
if(debug){
Serial.print("Filo OK N° = ");Serial.println(filo_ok+1);
}
// inserimento codice per disattivare bomba
keycount = 0;
lcd.setCursor(0, 0);
lcd.print(" Attivare bomba ");
lcd.setCursor(0, 1);
lcd.print("Codice = ");
while (keycount < lung_psw) {
lcd.setCursor(keycount + 10, 1);
lcd.blink();
char armcode = keypad.getKey();
armcode == NO_KEY;
if (armcode != NO_KEY) {
if ((armcode != '*') && (armcode != '#')) {
lcd.print(armcode);
tone(buzzer, 5000, 100);
password[keycount] = armcode;
keycount++;
}
}
}
if(debug){
Serial.print("PSW disinnesco = ");
for(byte j = 0 ;j < 6;j++){
Serial.print(password[j]);
}
Serial.println();
}
if (keycount == lung_psw) {
delay(500);
lcd.noBlink();
lcd.clear();
lcd.home();
lcd.print(" Codice Disarmo ");
lcd.setCursor(6, 1);
lcd.print(password[0]);
lcd.print(password[1]);
lcd.print(password[2]);
lcd.print(password[3]);
lcd.print(password[4]);
lcd.print(password[5]);
delay(3000);
lcd.clear();
}
// inerimento tempo disponibile disarmo
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Timer: HH:MM:SS ");
lcd.setCursor(0, 1);
lcd.print("SET= : :");
keycount = 5;
lcd.blink();
// inserire decine di ore
while (keycount == 5) {
char hourstens = keypad.getKey();
lcd.setCursor(5, 1);
if (hourstens >= '0' && hourstens <= '9') {
hourstenscode = hourstens - '0';
tone(buzzer, 5000, 100);
lcd.print(hourstens);
keycount++;
}
}
// inserire unita ore
while (keycount == 6) {
char hoursones = keypad.getKey();
lcd.setCursor(6, 1);
if (hoursones >= '0' && hoursones <= '9') {
hoursonescode = hoursones - '0';
tone(buzzer, 5000, 100);
lcd.print(hoursones);
keycount++;
}
}
// inserire decine minuti
while (keycount == 7) {
char mintens = keypad.getKey();
lcd.setCursor(8, 1);
if (mintens >= '0' && mintens <= '9') {
mintenscode = mintens - '0';
tone(buzzer, 5000, 100);
lcd.print(mintens);
keycount++;
}
}
// inserire unita minuti
while (keycount == 8) {
char minones = keypad.getKey();
lcd.setCursor(9, 1);
if (minones >= '0' && minones <= '9') {
minonescode = minones - '0';
tone(buzzer, 5000, 100);
lcd.print(minones);
keycount++;
}
}
// inserire decine secondi
while (keycount == 9) {
char sectens = keypad.getKey();
lcd.setCursor(11, 1);
if (sectens >= '0' && sectens <= '9') {
sectenscode = sectens - '0';
tone(buzzer, 5000, 100);
lcd.print(sectens);
keycount = 10;
}
}
// inserire unita secondi
while (keycount == 10) {
char secones = keypad.getKey();
lcd.setCursor(12, 1);
if (secones >= '0' && secones <= '9'){
seconescode = secones - '0';
tone(buzzer, 5000, 100);
lcd.print(secones);
keycount = 11;
}
}
// visualizza il tempo programmato per disinnesco
if (keycount == 11) {
Hours = (hourstenscode * 10) + hoursonescode;
Minutes = (mintenscode * 10) + minonescode;
Seconds = (sectenscode * 10) + seconescode;
delay(100);
lcd.noBlink();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Tempo disarmo ");
if (Hours >= 10) {
lcd.setCursor (4, 1);
lcd.print (Hours);
}else{
lcd.setCursor (4, 1);
lcd.print ("0");
lcd.setCursor (5, 1);
lcd.print (Hours);
}
lcd.print (":");
if (Minutes >= 10) {
lcd.setCursor (7, 1);
lcd.print (Minutes);
}else{
lcd.setCursor (7, 1);
lcd.print ("0");
lcd.setCursor (8, 1);
lcd.print (Minutes);
}
lcd.print (":");
if (Seconds >= 10) {
lcd.setCursor (10, 1);
lcd.print (Seconds);
}else{
lcd.setCursor (10, 1);
lcd.print ("0");
lcd.setCursor (11, 1);
lcd.print (Seconds);
}
delay(3000);
lcd.setCursor(0, 0);
lcd.print(" Premi tasto # ");
lcd.setCursor(0, 1);
lcd.print(" per iniziare ");
keycount = 12;
}
while (keycount == 12) {
char armkey = keypad.getKey();
if (armkey == '#') {
tone(buzzer, 5000, 100);
delay(100);
tone(buzzer, 0, 100);
delay(100);
tone(buzzer, 5000, 100);
delay(100);
tone(buzzer, 0, 100);
delay(100);
tone(buzzer, 5000, 100);
delay(100);
tone(buzzer, 0, 100);
delay(100);
lcd.setCursor(0, 0);
lcd.print (" Bomba attivata ");
lcd.setCursor(0, 1);
lcd.print("Start conteggio ");
delay(3000);
keycount = 0;
}
}
}
// accesnsione led neopixel
void colorWipe(uint32_t color, int wait) {
for(int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, color);
strip.setPixelColor(i - 1, 0);
strip.show();
delay(wait);
}
for(int i = strip.numPixels(); i >= 0; i--) {
strip.setPixelColor(i, color);
strip.setPixelColor(i + 1, 0);
strip.show();
delay(wait);
}
strip.setPixelColor(0, 0);
strip.show();
}
// controllo dello stato di carica della batteria
int readVcc() {
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC)); // measuring
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
long result = (high << 8) | low;
result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
return result; // Vcc in millivolts
}