/*
Autor: Antonio Garcia
Proyecto: Excrusor o dispensador de líquidos (pegamento)
Programa Dispensador de líquidos o excrusor, consta de un ESP32, driver control,
motor paso a paso, 2 Display oled, jeringa, 2 botones, potenciómetro.
El boton de stop no tiene código es un boton físico para detener el avance o revolución del motor
Tiene 2 librería para manejar el display oled Adafruit.
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
// Crear objeto para el display
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Configuración de los pines para el A4988
const int stepPin = 2; // Pin para el control de paso (STEP)
const int buttonPin = 4; // Pin del botón (para activar el movimiento)
// Pines para controlar la resolución de los pasos
const int MS1 = 5;
const int MS2 = 17;
const int MS3 = 16;
// Variables para el control del potenciómetro
const int potPin = 34; // Usamos el pin 34 en lugar de A0
int potValue = 0; // Valor leído del potenciómetro
int selectedStep = 0; // Opción seleccionada (0-4)
int steps = 0; // Pasos mapeados de 0 a 3200
int angulo = 0;
// Variables para el control del botón
bool lastButtonState = HIGH; // Último estado del botón (HIGH porque está configurado con pull-up)
bool currentButtonState = HIGH; // Estado actual del botón
unsigned long lastDebounceTime = 0; // Última vez que el botón fue presionado
unsigned long debounceDelay = 50; // Tiempo de retardo para evitar rebotes
// Variables para el control del botón STOP
bool motorRunning = true; // El motor está funcionando por defecto
bool lastStopButtonState = HIGH; // Último estado del botón STOP
bool currentStopButtonState = HIGH; // Estado actual del botón STOP
unsigned long stopButtonLastDebounceTime = 0; // Última vez que se presionó el botón STOP
unsigned long stopButtonDebounceDelay = 50; // Tiempo de retardo para evitar rebotes
// Arreglo con los pasos predeterminados
int stepOptions[5] = {200, 400, 800, 1600, 3200};
void setup() {
// Inicializar el display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Error al inicializar el display"));
while (true);
}
// Inicializar el display2
if (!display2.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
Serial.println(F("Error al inicializar el display"));
while (true);
}
display.display();
// Mostrar mensaje principal antes de que inicie el sistema
display.clearDisplay();
display.setTextSize(2); // Tamaño de texto más grande
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(" Excrusor");
display.print("");
display.setTextSize(1); // Tamaño de texto más pequeño
display.setCursor(0, 20);
display.println("Ver: 1.0");
display.setCursor(0, 30);
display.println("Prog y Dis: AJ Garcia");
display.setCursor(0, 40); // Mueve el cursor a la siguiente línea
display.println("Accesor: JP Machado");
display.println("");
display.println("Iniciando programa...");
display.display();
delay(1000);
display2.clearDisplay();
display2.setTextColor(SSD1306_WHITE);
display2.setTextSize(1); // Tamaño de texto más grande
display2.println(" CONFIGURACION");
display2.setTextSize(0); // Tamaño de texto más grande
display2.display();
// Configurar los pines para el A4988
pinMode(stepPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP); // Configurar el pin del botón con pull-up interno
// Configurar los pines de MS1, MS2 y MS3 para la resolución
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(MS3, OUTPUT);
// Configurar la resolución (por ejemplo, Octavo de paso)
setStepResolution(8); // Configuración de octavo de paso
Serial.begin(9600); // Inicializar monitor serie para depuración
}
void loop() {
// Leer el valor del potenciómetro (0-1023) desde el pin 34
potValue = analogRead(potPin);
// Mapear el valor del potenciómetro (0-1023) a las 5 opciones de pasos
selectedStep = map(potValue, 0, 4095, 0, 4); // Mapea el valor a un índice de 0 a 4
// Limitar el índice seleccionado para que no exceda el rango
selectedStep = constrain(selectedStep, 0, 4);
// Mostrar el menú en el display
display.setTextSize(0);
display.clearDisplay();
display.setCursor(0, 0);
display.println("--- Nivel/Avance ---");
// Mostrar las opciones de pasos
for (int i = 0; i < 5; i++) {
// Dibujar el rectángulo sin relleno alrededor de la opción seleccionada
if (i == selectedStep) {
display.drawRect(1, 8 + i * 11, 124, 12, SSD1306_WHITE); // Rectángulo sin relleno
//drawArrow(8, 10 + i * 11, 110, 10,SSD1306_WHITE);
/*display.setCursor(82, 10+i*11);
char asciiChar = 62; // Código ASCII para '>'
display.print(asciiChar);
display.setCursor(12, 10+i*11);
char asciiChar2 = 60; // Código ASCII para '<'
display.print(asciiChar2);*/
display.setCursor(10, 10+i*11);
int nivel=i+1;
display.print(nivel);
display.setCursor(95, 10);
display.print("1/16");
display.setCursor(95, 21);
display.print("1/8");
display.setCursor(95, 32);
display.print("1/4");
display.setCursor(95, 43);
display.print("1/2");
display.setCursor(95, 54);
display.print("1");
}
display.setCursor(20, 10 + i * 11);
display.print(stepOptions[i]/8);
display.print(" MicroPas");
//********************SEGUNDA DISPLAY O PANTALLA***********************
display2.clearDisplay();
display2.setTextSize(1); // Tamaño de texto más grande
display2.setCursor(0, 0);
display2.println(" CONFIGURACION");
display2.setTextSize(0); // Tamaño de texto más grande
display2.setCursor(0, 15);
if (selectedStep== 0) {
angulo=45; steps=200;
} else if (selectedStep == 1) {
angulo=90;steps=400;
}else if (selectedStep == 2) {
angulo=180; steps=800;
}else if (selectedStep == 3) {
angulo=360;steps=1600;
}else if (selectedStep == 4) {
angulo=720;steps=3200;}
display2.print("Velocidad: Nivel ");
display2.println(selectedStep+1);
display2.print("Valor Pot: ");
display2.println(potValue);
//Cálculo o fórmula para potencial electrico o voltaje
float volt= (potValue*3.3)/4095;
String mensaje = "Potencial: " + String(volt)+" volt";
display2.println(mensaje);
//Cálculo o fórmula para el volumen excrutado (No completadas las pruebas)
//Nota: es necesario hacer varias pruebas una vez que este listo el dispositivo
//para verificar y comprobar el volumen dispensado por nivel o micropaso.
float vo=0;
String mensaje2 = "Volumen: " + String(vo)+" ml";
display2.println(mensaje2);
String mensaje3 = "Recorrido: " + String(steps/8) +" MicPas";
display2.println(mensaje3);
//display2.print("Micropasos: ");
//display2.println(steps/8);
display2.print("Angulo Avance: ");
display2.print(angulo);
display2.print((char)167);
}
display2.display();
display.display();
// Leer el estado del botón
currentButtonState = digitalRead(buttonPin);
// Verificar si el botón ha sido presionado (detectando un cambio de estado)
if (currentButtonState == LOW && lastButtonState == HIGH && (millis() - lastDebounceTime) > debounceDelay) {
// Actualizar el tiempo de debounce
lastDebounceTime = millis();
// Seleccionar el número de pasos basado en la opción seleccionada
steps = stepOptions[selectedStep];
// Solo mover el motor si los pasos son mayores que cero
if (steps > 0) {
// Mostrar en el serial los pasos seleccionados
Serial.print("Seleccionado: ");
Serial.print(steps);
Serial.println(" pasos");
// Mover el motor con los pasos seleccionados
moveMotor(steps); // Mover el motor la cantidad de pasos calculados
}
}
}
// Función para mover el motor paso a paso
void moveMotor(int stepsToMove) {
if (!motorRunning) {
return; // Si motorRunning es false, no mover el motor
}
// Hacer que el motor se mueva el número de pasos calculado
for (int i = 0; i < stepsToMove; i++) {
if (!motorRunning) {
break; // Si motorRunning es false, detener el movimiento
}
digitalWrite(stepPin, HIGH);
delayMicroseconds(500); // Control de velocidad
digitalWrite(stepPin, LOW);
delayMicroseconds(500);
}
}
// Función para establecer la resolución del paso
void setStepResolution(int resolution) {
switch (resolution) {
case 1:
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
digitalWrite(MS3, LOW); // Paso completo
break;
case 2:
digitalWrite(MS1, HIGH);
digitalWrite(MS2, LOW);
digitalWrite(MS3, LOW); // Medio paso
break;
case 4:
digitalWrite(MS1, LOW);
digitalWrite(MS2, HIGH);
digitalWrite(MS3, LOW); // Cuarto de paso
break;
case 8:
digitalWrite(MS1, HIGH);
digitalWrite(MS2, HIGH);
digitalWrite(MS3, LOW); // Octavo de paso
break;
case 16:
digitalWrite(MS1, HIGH);
digitalWrite(MS2, HIGH);
digitalWrite(MS3, HIGH); // Dieciseisavo de paso
break;
default:
// Por defecto, configuramos a paso completo
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
digitalWrite(MS3, LOW); // Paso completo
break;
}
}