/*
Proyecto: Temporizador con selección de 3 tiempos y control de servo
Plataforma: ATtiny85 / Digispark
Resumen de funcionamiento:
--------------------------
- El sistema inicia con el NeoPixel apagado.
- La primera pulsación corta de botón enciende el NeoPixel al color del primer modo (L1).
- Las pulsaciones cortas posteriores cambian el color del NeoPixel para seleccionar uno de tres tiempos (L1, L2 y L1+L2).
- Con una pulsación larga, se inicia el conteo del tiempo seleccionado.
- Al iniciar el conteo, el NeoPixel parpadea simultáneamente durante un aviso de 2 segundos.
- Durante el conteo, el NeoPixel parpadea con el color del modo seleccionado.
- Al finalizar el tiempo, el servo se mueve 90 grados en sentido horario (de 0° a 90°) durante 1 segundo y luego regresa a su posición inicial (0°).
- Luego de eso, el NeoPixel se apaga. El sistema vuelve al estado inicial, esperando una nueva selección.
Esquema de conexión:
pin1 (PB5)>>>>>>no se usa
pin2 (PB3)>>>>>>señal del servo>>>>>>>>>>>>>>servo
pin3 (PB4)>>>>DIN del Neopixel
pin4 (GND)>>>>VSS del Neopixel>>>>GND(0v)>>>>servo
pin5 (PB0)>>>>>>pulsador>>>>>>>>>>GND(0v)
pin6 (PB1)>>>>>>no se usa
pin7 (PB2)>>>>>>no se usa
pin8 (VCC)>>>>VDD del Neopixel>>>>VCC(5v)>>>>servo
Conexiones:
-----------
- Pin 0 (PB0) → Botón con resistencia pull-up interna (conectado a GND).
- Pin 3 (PB3) → Señal de control del servo (alimentar con 5V).
- Pin 4 (PB4) → Pin de datos del NeoPixel.
- Servo y NeoPixel → Alimentar con una fuente de 5V externa si es necesario, conectando su GND al GND del ATtiny85.
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>
#include <Adafruit_NeoPixel.h>
#define LED_BUTTON_PIN 4
#define SERVO_PIN 3
#define NEOPIXEL_PIN 0
#define NUMPIXELS 1
#define DEBOUNCE_DELAY 200
#define BLINK_INTERVAL 150
#define LONG_PRESS_TIME 1000
#define START_BLINK_COUNT 5
#define START_BLINK_INTERVAL 150
// Tres tiempos correspondientes a los modos de NeoPixel
int led_times[] = {1000, 5000, 10000}; //1 segundo, 5 segundos y 10 segundos
int current_mode = 0; // 0: Modo Amarillo, 1: Modo Naranja, 2: Modo Rojo
int current_time = 0;
unsigned long last_short_press_time = 0;
Adafruit_SoftServo myServo;
Adafruit_NeoPixel neoPixel(NUMPIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
int initial_position = 80; // Nueva posición inicial del servo (90 grados más antihorario)
int final_position = 240; // Nueva posición final del servo (0 grados en sentido horario)
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;
bool isInitialState = true;
// Función para establecer el color del NeoPixel según el modo
void setNeoPixelModeColor(int mode) {
if (mode == 0) { // Modo 0 - Amarillo
neoPixel.setPixelColor(0, neoPixel.Color(255, 255, 0));
} else if (mode == 1) { // Modo 1 - Naranja
neoPixel.setPixelColor(0, neoPixel.Color(255, 128, 0));
} else if (mode == 2) { // Modo 2 - Rojo
neoPixel.setPixelColor(0, neoPixel.Color(255, 0, 0));
}
neoPixel.show();
}
void setup() {
pinMode(LED_BUTTON_PIN, INPUT_PULLUP);
// Inicializar NeoPixel y apagarlo
neoPixel.begin();
neoPixel.show();
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) {
if (!counting_active && !start_blink_active) {
last_short_press_time = now;
// Si es la primera pulsación, se enciende el NeoPixel
if (isInitialState) {
isInitialState = false;
setNeoPixelModeColor(current_mode);
} else {
// Si no, se cambia el modo como de costumbre
current_mode = (current_mode + 1) % 3;
setNeoPixelModeColor(current_mode);
}
current_time = led_times[current_mode];
}
} else if (press_duration >= LONG_PRESS_TIME && !counting_active && !start_blink_active) {
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;
// Apaga el NeoPixel al terminar el aviso
neoPixel.clear();
neoPixel.show();
} else {
int phase = (elapsed / START_BLINK_INTERVAL) % 2;
if (phase) {
setNeoPixelModeColor(current_mode); // Enciende con el color del modo
} else {
neoPixel.clear(); // Apaga el NeoPixel
neoPixel.show();
}
}
}
// --- Conteo con parpadeo del NeoPixel ---
if (counting_active) {
unsigned long elapsed = now - counting_start_time;
bool neo_on = (elapsed / BLINK_INTERVAL) % 2 == 0;
// El NeoPixel parpadea con el color seleccionado
if (neo_on) {
setNeoPixelModeColor(current_mode); // Enciende NeoPixel
} else {
neoPixel.clear(); // Apaga NeoPixel
neoPixel.show();
}
if (!servo_moved && elapsed >= current_time) {
myServo.write(final_position);
// Agregar un pequeño retraso para asegurar que el servo se mueva en el emulador de Wokwi
delay(10);
servo_move_time = now;
servo_moved = true;
}
if (servo_moved && (now - servo_move_time >= 1000)) {
myServo.write(initial_position);
// Agregar un pequeño retraso para asegurar que el servo se mueva en el emulador de Wokwi
delay(10);
counting_active = false;
servo_moved = false;
// Al finalizar el ciclo, apaga el NeoPixel
neoPixel.clear();
neoPixel.show();
// Y reinicia el estado inicial para la siguiente ronda
isInitialState = true;
}
}
// Es necesario llamar a refresh para que el servomotor funcione con SoftServo
myServo.refresh();
}