#include <Arduino.h>
#include <Ticker.h>
// Pines del motor paso a paso
const int motor_A = 23;
const int motor_B = 22;
const int motor_C = 19;
const int motor_D = 18;
// Pines de los sensores y botones
const int sensor_entrada = 4;
const int sensor_salida = 2;
const int boton_salida = 15; // Botón para dar salida manual
const int seta_emergencia = 27;
// Pines de los LEDs
const int led_encendido = 13; // LED VERDE
const int led_emergencia = 14; // LED ROJO
const int led_motor = 25; // Pin con funcionalidad DAC AZUL
const int led_parpadeo_1 = 26; // LED NARANJA
const int led_parpadeo_2 = 5; // LED AMARILLO
// Potenciómetro
const int pin_potenciometro = 34; // Entrada analógica
// Relé para desconectar el motor
const int rele_pin = 12; // Pin del relé
// Variables de estado
volatile bool emergencia = false;
volatile bool boton_presionado = false;
volatile bool producto_listo_para_salida = false;
int productos_en_linea = 0;
// Configuración de los pasos del motor
#define NUMSEC 4
int tabla_pasos[NUMSEC][4] = {
{ HIGH, LOW, LOW, LOW },
{ LOW, HIGH, LOW, LOW },
{ LOW, LOW, HIGH, LOW },
{ LOW, LOW, LOW, HIGH }
};
int paso_actual = 0;
int motor_speed = 100; // Velocidad inicial del motor en ms
// Instancias de Ticker para temporizadores
Ticker reporteTicker;
Ticker motorTicker;
Ticker ledsTicker;
Ticker emergenciaTicker;
Ticker salidaEmergenciaTicker;
Ticker productoTicker;
Ticker parpadeoLedTicker;
// Función para ajustar la velocidad del motor
void ajustar_velocidad_motor() {
int valor_pot = analogRead(pin_potenciometro); // Leer el valor del potenciómetro
motor_speed = map(valor_pot, 0, 4095, 50, 500); // Ajustar el rango de velocidad del motor
// Ajustar la intensidad del LED del motor según la velocidad
int intensidad = map(valor_pot, 0, 4095, 0, 255);
analogWrite(led_motor, intensidad);
motorTicker.attach_ms(motor_speed, mover_motor); // Reajusta el ticker del motor
}
// Función para mover el motor al siguiente paso
void mover_motor() {
if (!emergencia) {
digitalWrite(motor_A, tabla_pasos[paso_actual][0]);
digitalWrite(motor_B, tabla_pasos[paso_actual][1]);
digitalWrite(motor_C, tabla_pasos[paso_actual][2]);
digitalWrite(motor_D, tabla_pasos[paso_actual][3]);
paso_actual = (paso_actual + 1) % NUMSEC;
}
}
// Función para parpadear los LEDs 4 y 5 según la cantidad de productos
void parpadear_leds() {
static bool estado_leds = false;
if (!emergencia && productos_en_linea > 0) {
// Calcula la frecuencia de parpadeo en milisegundos
int frecuencia = 1000 / productos_en_linea;
estado_leds = !estado_leds;
digitalWrite(led_parpadeo_1, estado_leds);
digitalWrite(led_parpadeo_2, !estado_leds);
ledsTicker.attach_ms(frecuencia, parpadear_leds);
} else {
digitalWrite(led_parpadeo_1, LOW);
digitalWrite(led_parpadeo_2, LOW);
ledsTicker.detach();
}
}
// Función para reporte serial
void reporte_serial() {
Serial.printf("Productos en la cinta: %d\n", productos_en_linea);
int valor_pot = analogRead(pin_potenciometro);
float velocidad = map(valor_pot, 0, 4095, 0, 100);
Serial.printf("Velocidad: %.2f%%\n", velocidad);
}
// Función para manejar la emergencia
void manejar_emergencia() {
if (digitalRead(seta_emergencia) == LOW) { // Botón presionado
if (!boton_presionado) {
boton_presionado = true;
emergencia = true;
digitalWrite(rele_pin, LOW); // Desactivar el motor
digitalWrite(led_emergencia, HIGH); // Encender LED de emergencia
emergenciaTicker.once(3, []() { // Espera 3 segundos
if (digitalRead(seta_emergencia) == LOW) { // Verificar si sigue presionado
salidaEmergenciaTicker.once(3, []() { // Espera otros 3 segundos
emergencia = false;
productos_en_linea = 0; // Reinicia los productos
digitalWrite(rele_pin, HIGH); // Reactivar el motor
digitalWrite(led_emergencia, LOW); // Apagar LED de emergencia
boton_presionado = false;
parpadear_leds(); // Reinicia el parpadeo
});
} else {
boton_presionado = false;
emergenciaTicker.detach(); // Detener el temporizador si se suelta el botón antes de 3 segundos
}
});
}
} else {
boton_presionado = false;
emergenciaTicker.detach(); // Detener el temporizador si se suelta el botón antes de 3 segundos
}
}
// Función para manejar la salida de productos con botón
void manejar_salida_manual() {
if (!emergencia && productos_en_linea > 0 && producto_listo_para_salida) {
productos_en_linea--; // Reducir productos
producto_listo_para_salida = false; // Reiniciar el estado
parpadear_leds(); // Actualiza el parpadeo al disminuir productos
}
}
// Función para simular la llegada de un nuevo producto
void llegada_producto() {
if (!emergencia) {
productos_en_linea++;
producto_listo_para_salida = false;
parpadear_leds(); // Actualiza el parpadeo al aumentar productos
// Marca el producto como listo para salida después de 5 segundos
productoTicker.once(5, []() {
producto_listo_para_salida = true;
});
}
}
void setup() {
// Configuración de pines
pinMode(motor_A, OUTPUT);
pinMode(motor_B, OUTPUT);
pinMode(motor_C, OUTPUT);
pinMode(motor_D, OUTPUT);
pinMode(rele_pin, OUTPUT);
pinMode(sensor_entrada, INPUT_PULLUP);
pinMode(sensor_salida, INPUT_PULLUP);
pinMode(boton_salida, INPUT_PULLUP);
pinMode(seta_emergencia, INPUT_PULLUP);
pinMode(led_encendido, OUTPUT);
pinMode(led_emergencia, OUTPUT);
pinMode(led_motor, OUTPUT);
pinMode(led_parpadeo_1, OUTPUT);
pinMode(led_parpadeo_2, OUTPUT);
digitalWrite(led_encendido, HIGH);
digitalWrite(rele_pin, HIGH); // Activar el motor
// Configuración de interrupciones
attachInterrupt(digitalPinToInterrupt(sensor_entrada), llegada_producto, FALLING);
attachInterrupt(digitalPinToInterrupt(sensor_salida), manejar_salida_manual, FALLING);
attachInterrupt(digitalPinToInterrupt(seta_emergencia), manejar_emergencia, FALLING);
attachInterrupt(digitalPinToInterrupt(boton_salida), manejar_salida_manual, FALLING);
Serial.begin(115200);
// Configuración de los Tickers
reporteTicker.attach(5, reporte_serial); // Reportar cada 5 segundos
motorTicker.attach_ms(motor_speed, mover_motor); // Mover el motor con la velocidad inicial
parpadear_leds(); // Inicializa el parpadeo de LEDs
}
void loop() {
// Ajustar la velocidad del motor según el valor del potenciómetro
ajustar_velocidad_motor();
}