#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
// LCD I2C
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Keypad
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
byte rowPins[ROWS] = { 9, 8, 7, 6 };
byte colPins[COLS] = { 5, 4, 3, 2 };
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Pines físicos
const int stepPin = 22;
const int dirPin = 23;
const int enPin = 24;
const int sensorPin = 32;
const int buzzer = 11;
const int buttonPin = 10;
// Variables
int vueltasObjetivo = 0;
int vueltasContadas = 0;
bool enProceso = false;
bool sensorEstadoAnterior = LOW;
bool botonPresionado = false;
// Encoder
int encoder0PinA = 12;
int encoder0PinB = 13;
int encoder0Pos = 0;
int encoder0PinALast = LOW;
int n = LOW;
int maxKnob = 20;
int stepperSpeed = 2000; // Delay en microsegundos, menor = más rápido
const int maxSpeed = 600;
const int minSpeed = 2000;
void setup() {
Serial.begin(9600);
pinMode(encoder0PinA, INPUT);
pinMode(encoder0PinB, INPUT);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
pinMode(sensorPin, INPUT_PULLUP);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(buzzer, OUTPUT);
digitalWrite(enPin, HIGH); // Motor apagado inicialmente
digitalWrite(dirPin, HIGH); // Dirección inicial
lcd.init();
lcd.backlight();
// Inicializar estado encoder para evitar pulsos falsos al inicio
encoder0PinALast = digitalRead(encoder0PinA);
lcd.setCursor(0, 1);
lcd.print(" BIENVENIDOS EEST N5 ");
lcd.setCursor(0, 2);
lcd.print(" LANUS ");
delay(1000);
lcd.clear();
ingresarVueltas();
}
void loop() {
// BOTÓN FÍSICO: pausar o reanudar
if (digitalRead(buttonPin) == HIGH && !botonPresionado) {
botonPresionado = true;
if (enProceso) {
// Pausar motor y conteo
enProceso = false;
digitalWrite(enPin, HIGH); // Apagar motor
lcd.setCursor(0, 2);
lcd.print("Pausa vuelta ");
lcd.setCursor(14, 2);
lcd.print(vueltasContadas);
} else {
// Reanudar
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Iniciando...");
lcd.setCursor(0, 1);
lcd.print("Vuelta: ");
lcd.print(vueltasContadas);
digitalWrite(dirPin, HIGH);
digitalWrite(enPin, LOW); // Activar motor
enProceso = true;
delay(1000);
}
delay(300); // debounce
}
if (digitalRead(buttonPin) == LOW) {
botonPresionado = false;
}
// TECLADO: cambiar dirección solo si está detenido
char key = keypad.getKey();
if (key != NO_KEY) {
tone(buzzer, 1000, 100);
delay(120);
noTone(buzzer);
if (key == 'C') {
if (!enProceso) {
digitalWrite(dirPin, HIGH);
lcd.setCursor(0, 2);
lcd.print("Direccion cambiada ");
delay(800);
lcd.setCursor(0, 2);
lcd.print(" ");
} else {
lcd.setCursor(0, 2);
lcd.print("En marcha: sin cambio");
delay(800);
lcd.setCursor(0, 2);
lcd.print(" ");
}
}
}
// PROCESO EN MARCHA
if (enProceso) {
getKnob(); // Solo leer encoder mientras motor gira
motorStep(1); // Paso simple
// Lectura del sensor (cuenta vueltas)
bool sensorEstado = digitalRead(sensorPin);
if (sensorEstado == HIGH && sensorEstadoAnterior == LOW) {
vueltasContadas++;
lcd.setCursor(0, 1);
lcd.print("Vuelta: ");
lcd.print(vueltasContadas);
lcd.print(" ");
}
sensorEstadoAnterior = sensorEstado;
// Mostrar velocidad en LCD (línea 3)
lcd.setCursor(0, 3);
lcd.print("Velocidad: ");
lcd.print(stepperSpeed);
lcd.print(" ");
// Meta alcanzada
if (vueltasContadas >= vueltasObjetivo) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Listo!");
digitalWrite(enPin, HIGH); // Apagar motor
for (int i = 0; i < 3; i++) {
tone(buzzer, 1000, 200);
delay(300);
}
vueltasContadas = 0;
enProceso = false;
delay(2000);
ingresarVueltas();
}
}
}
// Función que ejecuta pasos de motor con la velocidad actual
void motorStep(int MAX) {
for (int x = 0; x < MAX; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(stepperSpeed);
digitalWrite(stepPin, LOW);
delayMicroseconds(stepperSpeed);
}
}
// Lee el encoder rotativo y ajusta la velocidad del motor
void getKnob() {
n = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n == HIGH)) {
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos--;
} else {
encoder0Pos++;
}
if( encoder0Pos > maxKnob ){
encoder0Pos = maxKnob;
}
else if( encoder0Pos < 0 ){
encoder0Pos = 0;
}
int r= encoder0Pos \* 100;
r = minSpeed - r;
r = (r < maxSpeed)?maxSpeed : r;
stepperSpeed = r;
Serial.print (encoder0Pos);
Serial.println();
Serial.println ( r );
}
encoder0PinALast = n;
}
// Función para ingresar vueltas desde teclado
void ingresarVueltas() {
String numero = "";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Vueltas:");
lcd.setCursor(0, 1);
lcd.print("Ingresa #: ");
lcd.setCursor(12, 1);
while (true) {
char key = keypad.getKey();
if (key != NO_KEY) {
tone(buzzer, 1000, 100);
delay(120);
noTone(buzzer);
if (key >= '0' && key <= '9') {
numero += key;
lcd.setCursor(12, 1);
lcd.print(numero);
} else if (key == '#') {
if (numero.length() > 0) {
vueltasObjetivo = numero.toInt();
if (vueltasObjetivo > 0) {
vueltasContadas = 0; // Reiniciar contador al empezar nuevo proceso
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Meta: ");
lcd.print(vueltasObjetivo);
delay(1000);
break;
}
}
} else if (key == '\*') {
numero = "";
lcd.setCursor(12, 1);
lcd.print(" ");
lcd.setCursor(12, 1);
}
}
}
}