#include <TM1637Display.h>
#include <LiquidCrystal_I2C.h> // Libreria per il display LCD I2C
#include <Encoder.h> // Libreria per il rotary encoder
#define I2C_ADDR 0x27
/* ======== IMPOSTAZIONI UTENTE =========== */
// effetti speciali
#define ENABLE_TICK_SOUND true // Abilita il suono del ticchettio
// Definisce i pin di collegamento per il display
#define CLK 6 // Pin CLK per il display
#define DIO 7 // Pin DIO per il display
// Definisce i pin di collegamento per il rotary encoder
#define ENCODER_CLK 2 // Pin CLK per il rotary encoder
#define ENCODER_DT 3 // Pin DT per il rotary encoder
#define ENCODER_SW 4 // Pin SW per il rotary encoder
#define BUZZER 9 // Pin per il buzzer
#define RELAY_PIN 5 // Pin per il relè
#define LED_PIN 12 // Pin per il LED
int duration; // Durata in millisecondi
// Crea un oggetto display di tipo TM1637Display:
TM1637Display display = TM1637Display(CLK, DIO);
/* Inizializza il display LCD 16x2 all'indirizzo I2C predefinito */
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 2);
// Crea un oggetto encoder
Encoder myEnc(ENCODER_CLK, ENCODER_DT);
// Variabile per memorizzare l'ultima posizione del rotary encoder
long oldPosition = -999;
void setup() {
pinMode(ENCODER_SW, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
pinMode(RELAY_PIN, OUTPUT); // Imposta il pin del relè come output
pinMode(LED_PIN, OUTPUT); // Imposta il pin del LED come output
digitalWrite(RELAY_PIN, LOW); // Assicura che il relè sia inizialmente spento
duration = 16 * 1000; // Imposta di default 15 secondi in millisecondi
// Spegne il display TM1637 durante la scritta di presentazione
display.setBrightness(0); // Spegne il display
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Rocket Launch");
lcd.setCursor(0, 1);
lcd.print("4ne Electronics");
delay(3000); // Visualizza "Rocket Launch" per 3 secondi
// Cambia il messaggio a "Rotate to set TIME"
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Rotate set TIME");
lcd.setCursor(0, 1);
lcd.print("Press to LAUNCH");
// Riaccende il display TM1637
display.setBrightness(2); // Imposta la luminosità del display da 0 a 7
ShowTime(duration);
}
void loop() {
while (true) {
// La funzione controlla il rotary encoder e ritorna solo quando il pulsante di avvio è premuto
WaitForStart();
// Avvia il timer della durata
TimeDuration();
}
}
void WaitForStart() {
long newPosition;
// Controlla la pressione dei pulsanti ogni 0,15 secondi
while (digitalRead(ENCODER_SW) == HIGH) {
newPosition = myEnc.read();
if (newPosition != oldPosition) {
// Controlla se il rotary encoder è stato ruotato
if (newPosition > oldPosition) {
if (duration > 1000) {
duration -= 1000; // Decrementa di 1 secondo
tone(BUZZER, 1000, 100); // Beep quando viene ruotato il rotary encoder
digitalWrite(LED_PIN, HIGH); // Accendi LED
delay(100); // Tempo per cui il LED rimane acceso (in sincronia con il beep)
digitalWrite(LED_PIN, LOW); // Spegni LED
}
} else if (newPosition < oldPosition) {
duration += 1000; // Incrementa di 1 secondo
tone(BUZZER, 1000, 100); // Beep quando viene ruotato il rotary encoder
digitalWrite(LED_PIN, HIGH); // Accendi LED
delay(100); // Tempo per cui il LED rimane acceso (in sincronia con il beep)
digitalWrite(LED_PIN, LOW); // Spegni LED
}
ShowTime(duration);
oldPosition = newPosition;
delay(150); // Debounce per evitare rilevamenti multipli
}
delay(150);
}
// Il pulsante di avvio è stato premuto
tone(BUZZER, 1200, 550);
digitalWrite(LED_PIN, HIGH); // Accendi LED durante il tono lungo
delay(550);
digitalWrite(LED_PIN, LOW); // Spegni LED
display.clear();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Razzo Armato");
lcd.setCursor(0, 1);
lcd.print(" KEEP DISTANCE");
}
void TimeDuration() {
// Il ciclo while continua fino allo scadere del tempo
unsigned long startTime = millis();
unsigned long timer = duration;
// Controlla ripetutamente se il tempo è scaduto
while ((millis() - startTime) <= timer) {
// Calcola il tempo trascorso in millisecondi
unsigned long elapsed = millis() - startTime;
ShowTime(duration - elapsed);
unsigned long remainingTime = duration - elapsed;
if (remainingTime <= 5000) {
if ((millis() - startTime) % 500 < 50) { // Beep e LED ogni mezzo secondo negli ultimi 5 secondi
tone(BUZZER, 1300, 150);
digitalWrite(LED_PIN, HIGH); // Accendi LED
delay(150);
digitalWrite(LED_PIN, LOW); // Spegni LED
}
} else {
if ((millis() - startTime) % 1000 < 50) { // Beep e LED ogni secondo
tone(BUZZER, 1300, 150);
digitalWrite(LED_PIN, HIGH); // Accendi LED
delay(150);
digitalWrite(LED_PIN, LOW); // Spegni LED
}
}
delay(1); // Ridotto il ritardo per mostrare i millisecondi
}
// Tempo scaduto
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" R A Z Z O");
lcd.setCursor(0, 1);
lcd.print(" L A N C I A T O");
// Attiva il relè allo scadere del tempo
digitalWrite(RELAY_PIN, HIGH);
for (int i = 0; i < 3; i++) {
tone(BUZZER, 250, 500);
digitalWrite(LED_PIN, HIGH); // Accendi LED durante il beep
delay(500);
digitalWrite(LED_PIN, LOW); // Spegni LED
tone(BUZZER, 125, 500);
digitalWrite(LED_PIN, HIGH); // Accendi LED durante il beep
delay(500);
digitalWrite(LED_PIN, LOW); // Spegni LED
}
// Mantieni il relè attivo per 5 secondi
delay(5000);
digitalWrite(RELAY_PIN, LOW); // Spegni il relè
lcd.clear();
// Cambia il messaggio a "Rotate to set TIME"
lcd.setCursor(0, 0);
lcd.print("Rotate set TIME");
lcd.setCursor(0, 1);
lcd.print("Press to LAUNCH");
// Visualizza il tempo corrente sul display a 4 cifre
ShowTime(duration);
}
void ShowTime(unsigned long value) {
static unsigned long lastTime;
// Aggiorna il display se il tempo è cambiato
if (lastTime != value) {
lastTime = value;
int iMinutes = value / 60000;
int iSeconds = (value % 60000) / 1000;
int iMillis = (value % 1000) / 10; // Millisecondi con due cifre decimali
// Mostra sul display a 4 cifre
uint16_t number = iMinutes * 10000 + iSeconds * 100 + iMillis;
display.showNumberDecEx(number, 0b01000000, true, 4, 0);
}
}