/*
Proyecto: Temporizador con selección de 3 tiempos y control de servo
Plataforma: ATtiny85 / Digispark
Resumen de funcionamiento:
--------------------------
- Un botón permite seleccionar uno de tres tiempos (L1, L2 y L1+L2) mediante pulsaciones cortas.
- Con una pulsación larga, se inicia el conteo del tiempo seleccionado.
- Al iniciar el conteo, ambos LEDs parpadean simultáneamente durante 2 segundos como aviso.
- Durante el conteo, los LEDs parpadean de forma alternada y secuencial para indicar que el temporizador está activo.
- Al finalizar el tiempo, el servo se mueve a 90° durante 1 segundo y luego regresa a su posición inicial (0°).
- Luego de eso, el sistema vuelve al estado inicial, esperando una nueva selección.
Esquema de conexión:
--------------------
+-------------------------+
| |
| ATtiny85/Digispark |
| |
+-------------------------+
| | | |
| | | |
Pin0 Pin1 Pin2 Pin3
| | | |
[Botón] [LED1] [LED2] [Servo]
| | | |
GND GND GND VCC
|
|
[Servo Motor]
|
[GND]
Conexiones:
-----------
- Pin 0 → Botón con resistencia pull-up interna (conectado a GND).
- Pin 1 → LED1 con resistencia limitadora (220–470Ω) a GND.
- Pin 2 → LED2 con resistencia limitadora (220–470Ω) a GND.
- Pin 3 → Señal de control del servo (alimentar con 5V).
- Servo → Alimentación externa de 5V si es necesario (no desde el pin del microcontrolador).
Notas:
------
- El botón usa la resistencia pull-up interna del microcontrolador.
- El servo necesita una fuente estable de 5V.
- El sistema es compatible con Wokwi para emulación.
*/
#include <Adafruit_SoftServo.h>
#define LED_BUTTON_PIN 0
#define SERVO_BUTTON_PIN 5
#define SERVO_PIN 3
#define LED1_PIN 1
#define LED2_PIN 2
#define DEBOUNCE_DELAY 200
#define BLINK_INTERVAL 300
#define LONG_PRESS_TIME 1000
#define START_BLINK_COUNT 5
#define START_BLINK_INTERVAL 150
// Tres tiempos correspondientes a L1, L2 y L1+L2
int led_times[] = {1000, 5000, 10000};
int current_mode = 0; // 0: L1, 1: L2, 2: L1+L2
int current_time = 0;
unsigned long last_short_press_time = 0;
Adafruit_SoftServo myServo;
int initial_position = 0;
bool button_was_pressed = false;
unsigned long button_press_start = 0;
bool counting_active = false;
unsigned long counting_start_time = 0;
bool servo_moved = false;
unsigned long servo_move_time = 0;
bool start_blink_active = false;
unsigned long start_blink_start_time = 0;
void updateLEDsForMode(int mode) {
// Apaga ambos
digitalWrite(LED1_PIN, LOW);
digitalWrite(LED2_PIN, LOW);
if (mode == 0) {
digitalWrite(LED1_PIN, HIGH);
} else if (mode == 1) {
digitalWrite(LED2_PIN, HIGH);
} else if (mode == 2) {
digitalWrite(LED1_PIN, HIGH);
digitalWrite(LED2_PIN, HIGH);
}
}
void setup() {
pinMode(LED_BUTTON_PIN, INPUT_PULLUP);
pinMode(SERVO_BUTTON_PIN, INPUT_PULLUP);
pinMode(LED1_PIN, OUTPUT);
pinMode(LED2_PIN, OUTPUT);
digitalWrite(LED1_PIN, LOW);
digitalWrite(LED2_PIN, LOW);
updateLEDsForMode(current_mode);
current_time = led_times[current_mode];
myServo.attach(SERVO_PIN);
myServo.write(initial_position);
}
void loop() {
unsigned long now = millis();
bool button_state = digitalRead(LED_BUTTON_PIN) == LOW;
// --- Detectar pulsación corta o larga ---
if (button_state) {
if (!button_was_pressed) {
button_press_start = now;
button_was_pressed = true;
}
} else {
if (button_was_pressed) {
unsigned long press_duration = now - button_press_start;
button_was_pressed = false;
if (press_duration < LONG_PRESS_TIME && (now - last_short_press_time) > DEBOUNCE_DELAY) {
// Pulsación corta: cambiar modo (0 → 1 → 2 → 0 ...)
last_short_press_time = now;
current_mode = (current_mode + 1) % 3;
updateLEDsForMode(current_mode);
current_time = led_times[current_mode];
} else if (press_duration >= LONG_PRESS_TIME && !counting_active && !start_blink_active) {
// Pulsación larga: iniciar parpadeo simultáneo
start_blink_active = true;
start_blink_start_time = now;
}
}
}
// --- Aviso inicio: 5 destellos simultáneos ---
if (start_blink_active) {
unsigned long elapsed = now - start_blink_start_time;
int total_blink_time = START_BLINK_COUNT * 2 * START_BLINK_INTERVAL;
if (elapsed >= total_blink_time) {
start_blink_active = false;
counting_active = true;
counting_start_time = now;
servo_moved = false;
digitalWrite(LED1_PIN, LOW);
digitalWrite(LED2_PIN, LOW);
} else {
int phase = (elapsed / START_BLINK_INTERVAL) % 2;
digitalWrite(LED1_PIN, phase ? HIGH : LOW);
digitalWrite(LED2_PIN, phase ? HIGH : LOW);
}
}
// --- Conteo con parpadeo secuencial entre LED1 y LED2 ---
if (counting_active) {
unsigned long elapsed = now - counting_start_time;
bool led1_on = (elapsed / BLINK_INTERVAL) % 2 == 0;
digitalWrite(LED1_PIN, led1_on ? HIGH : LOW);
digitalWrite(LED2_PIN, led1_on ? LOW : HIGH);
if (!servo_moved && elapsed >= current_time) {
myServo.write(190);
servo_move_time = now;
servo_moved = true;
}
if (servo_moved && (now - servo_move_time >= 1000)) {
myServo.write(initial_position);
counting_active = false;
servo_moved = false;
updateLEDsForMode(current_mode); // volver a mostrar modo actual
}
}
myServo.refresh();
}
Una pulsación corta en el botón cambiará
el LED seleccionado (y su tiempo asociado).
Una pulsación larga en el mismo botón
iniciará el ciclo del servo, usando el
tiempo del LED que estaba seleccionado
en ese momento.
se puede eliminar el led del PB1 y usar el del Digispark