// Programa hecho/ensamblado por
// Asthral
#include <Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h> // Libreria pantalla OLED
#include <Adafruit_SSD1306.h> // Libreria pantalla OLED
#include <Versatile_RotaryEncoder.h>
// Configuración de la pantalla
#define SCREEN_WIDTH 128 // Ancho de la pantalla OLED, en píxeles
#define SCREEN_HEIGHT 32 // Altura de la pantalla OLED, en píxeles
// Declaración para una pantalla SSD1306 conectada a I2C (pines SDA, SCL)
// Los pines para I2C son definidos por la librería Wire.
// En un Arduino UNO: A4(SDA), A5(SCL)
// En un Arduino MEGA 2560: 20(SDA), 21(SCL)
// En un Arduino LEONARDO: 2(SDA), 3(SCL), ...
#define OLED_RESET -1 // Pin de reset # (o -1 si comparte el pin de reset del Arduino)
#define SCREEN_ADDRESS 0x3C ///< Ver datasheet para la dirección; 0x3D para 128x64, 0x3C para 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//Encoder rotativo -------------------------------------------------------------------
// Define aquí los pines de lectura de tu encoder
#define clk 8 // (d8)
#define dt 9 // (d9)
#define sw 10 // (d10)
// Prototipos de funciones para manejar cada evento del encoder
void handleRotate(int8_t rotation);
void handlePressRotate(int8_t rotation);
void handleHeldRotate(int8_t rotation);
void handlePress();
void handlePressRelease();
void handleLongPress();
void handleLongPressRelease();
void handlePressRotateRelease();
void handleHeldRotateRelease();
// Crear un puntero global para el objeto encoder
Versatile_RotaryEncoder *versatile_encoder;
// Butoon -----------------------------------------------------------------------------
int buttonLoaderPin = 7; // (d5) Boton que inicia la carga
// Servo -----------------------------------------------------------------------------
Servo servoLoad; // Declaración del objeto Servo
int servoLoadPin = 3; // (d3) Señal del servo
// servoLoad.write(180); - Girar a la derecha a máxima velocidad
// servoLoad.write(0); - Girar a la izquierda a máxima velocidad
// servoLoad.write(90); - Parar el servomotor
//Datos para el programa -----------------------------------------------------------------------------
char *presetsList[] = {"PRESETS",
"CUSTOM",
"PRESET",
"PRESET",
"PRESET",
"PRESET",
"PRESET",
"PRESET",
"PRESET",
"PRESET",
"----------"
};
char *presetsListNum[] = {"",
"",
"80",
"120",
"30",
"90",
"150",
"200",
"180",
"250"
};
int MaxPresetRows=9; // Número máximo de filas de presets que se pueden mostrar
int CurrentTextScroll = 0; // Índice actual de la lista de presets (indica cuál preset está seleccionado)
int SelectColumn = 0; // Indica la columna donde se encuentra el puntero
int CustomBBQuantity = 1; // Cantidad personalizada de BBs configurada por el usuario
int CurrentCount = -2; // Contador actual de BBs, inicializado en -2 (valor especial para indicar un estado inicial o reseteo)
int BBTarget = 0; // Objetivo de BBs configurado, es decir, cuántas BBs se deben contar antes de detener el motor
float BBsPerSecond = 0; // Bolas por segundo
bool EditingCustomBBQuantity = false; // Indicador de si el sistema está actualmente editando la cantidad de BBs Custom
// Valores asociados a cada preset en presetsList
// El primer valor es -1 (valor especial), el segundo es CustomBBQuantity (que puede cambiar)
int presetsListValue[] = {-1, // Valor especial para el encabezado de la lista
CustomBBQuantity, // Valor personalizado por el usuario
80,
120,
30,
90,
150,
200,
180,
250
};
// Indicador de si el sistema está actualmente en el estado de carga de BBs
bool currentlyLoading = false;
unsigned long passedTimeSinceLastCountedBB = 0; // Guarda el tiempo en millis cuando se cuenta una BB
unsigned long passedTimeForReset = 1000; // Tiempo máximo permitido antes del reset de la pantalla, en millis (1000 = 1s)
unsigned long lastCountTime = 0; // Variable para almacenar el tiempo de la última bola contada
//-------------------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
Serial.println("Starting up");
// pinMode(PhotoIn, INPUT); //configura el pin 2 como entrada (Sensor)
servoLoad.attach(servoLoadPin); // Conecta el servo al pin digital (Servo Loader)
pinMode(buttonLoaderPin, INPUT_PULLUP); // Configura el pin del pulsador como entrada con pull-up interno (Botton que acciona la carga)
// Configura encoder rotativo -------------------------------------------------------------------
versatile_encoder = new Versatile_RotaryEncoder(clk, dt, sw);
// Asignar funciones para manejar los eventos del encoder
versatile_encoder->setHandleRotate(handleRotate);
versatile_encoder->setHandlePressRotate(handlePressRotate);
versatile_encoder->setHandleHeldRotate(handleHeldRotate);
versatile_encoder->setHandlePress(handlePress);
versatile_encoder->setHandlePressRelease(handlePressRelease);
versatile_encoder->setHandleLongPress(handleLongPress);
versatile_encoder->setHandleLongPressRelease(handleLongPressRelease);
versatile_encoder->setHandlePressRotateRelease(handlePressRotateRelease);
versatile_encoder->setHandleHeldRotateRelease(handleHeldRotateRelease);
// Configurar valores predeterminados del encoder (opcional)
// versatile_encoder->setInvertedSwitch(true); // Invierte el comportamiento del interruptor de HIGH a LOW a LOW a HIGH
// versatile_encoder->setReadIntervalDuration(1); // Establecer 2ms como duración de pulsación larga (predeterminado es 1ms)
// versatile_encoder->setShortPressDuration(35); // Establecer 35ms como duración de pulsación corta (predeterminado es 50ms)
// versatile_encoder->setLongPressDuration(550); // Establecer 550ms como duración de pulsación larga (predeterminado es 1000ms)
//----------------------------------------------------------------------------------
// Configura pantalla OLED -------------------------------------------------------------------
// SSD1306_SWITCHCAPVCC = generar voltaje de pantalla desde 3.3V internamente
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 asignation failed (Inicial)"));
for(;;); // No continuar, bucle infinito
}
drawNameTag();
//drawFishyTear();
// Limpia el búfer
display.clearDisplay();
//AnimationTest(Bullet_hole, Bullet_hole_WIDTH, Bullet_hole_HEIGHT);
Serial.println("Starting up done");
UpdateDisplay();
//----------------------------------------------------------------------------------
}
void loop() {
// Lectura y procesamiento del encoder
if(currentlyLoading == false) {
if (versatile_encoder->ReadEncoder()) {
// Hacer algo aquí cada vez que se lea una acción del encoder
}
}
// Leer el estado del botón pulsador
if (digitalRead(buttonLoaderPin) == LOW) {
Serial.println("Yep, el botón está siendo presionado");
Serial.println(currentlyLoading);
Serial.println(CurrentCount);
Serial.println(BBTarget);
if (currentlyLoading == true) {
currentlyLoading = false;
}
}
// Carga
if (digitalRead(buttonLoaderPin) == LOW && (CurrentCount != BBTarget) && currentlyLoading == false) {
// Verificar selección y establecer objetivo
if (CustomBBQuantity == 0) {
CustomBBQuantity = 1;
}
presetsListValue[1] = CustomBBQuantity;
BBTarget = presetsListValue[CurrentTextScroll];
Serial.print("El objetivo está establecido en: ");
Serial.println(BBTarget);
// Iniciar carga
if (CurrentCount < 0) {
CurrentCount = 0;
}
currentlyLoading = true;
lastCountTime = millis(); // Inicializar el tiempo de la última bola contada
while (digitalRead(buttonLoaderPin) == LOW && (CurrentCount != BBTarget) && (BBTarget != 0)) {
servoLoad.write(0); // Girar servo hacia derecha
// Simular la carga de una bola cada 0,5 segundos
if (millis() - lastCountTime >= 50) {
CurrentCount++;
Serial.println("BB contada:");
Serial.println(CurrentCount);
lastCountTime = millis(); // Actualizar el tiempo de la última bola contada
passedTimeSinceLastCountedBB = millis();
// Actualizar pantalla
NumberScreen();
}
}
servoLoad.write(90); // Parar servo
Serial.println("Motor apagado");
} else if (digitalRead(buttonLoaderPin) == HIGH && currentlyLoading == true) {
currentlyLoading = false;
}
if (digitalRead(buttonLoaderPin) == HIGH && currentlyLoading == false && CurrentCount > 0 && ((millis() - passedTimeSinceLastCountedBB) >= passedTimeForReset)) {
// Resetear
Serial.println("Reseteando");
CurrentCount = -2;
UpdateDisplay();
}
}
void UpdateDisplay(){
MenuScreen();
}