Hola a todos, soy ralampa, no soy programador y no entiendo mucho por no decir nada. Hace unos días monte un msx omega y ya que el diseño de la carcasa lleva un hueco para una pantalla oled de 128,32, decidí aprovecharla. Como ya he dicho no tengo ni idea, entre en chatgpt y conseguí compilar un código, me llevo 2 semanas, el cual funciona bien todo menos el encoder. Tienes que girarlo mucho para que detecte un movimiento y tanto si vas a izquierdas como a derechas el sentido es el mismo. He comprobado el encoder con otro sketch y el problema no es el encoder.
Os paso el código haber si alguno de vosotros me puede hechar un cable:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#include "LOGO.H"
const int clkPin = 8;
const int dtPin = 7;
const int btnPin = 9;
unsigned long ultimoTiempoActualizacion = 0;
const unsigned long intervaloActualizacion = 1000; // Intervalo de actualización en milisegundos (por ejemplo, cada segundo)
int state_clk_old;
int count = 0;
// DECLARAMOS LAS VARIABLES QUE INDICAN LOS PINES QUE VAMOS A UTILIZAR EN RELES
int rele1_interruptor = 12; // Para el pin que controlará el pulsador del relé 1
int rele1_activador = 2; // Para el pin que controlará el relé 1
int rele2_interruptor = 11; // Para el pin que controlará el pulsador del relé 2
int rele2_activador = 3; // Para el pin que controlará el relé 2
int rele3_interruptor = 10; // Pin para leer el estado del pulsador
int rele3_activador = 4; // Pin para controlar el tercer relé
bool rele1_estado_anterior = LOW; // Variable para rastrear el estado anterior del rele1
bool rele2_estado_anterior = false; // Declaración de la variable rele2_estado_anterior
bool rele3_estado_anterior = LOW; // Variable para rastrear el estado anterior del tercer relé
bool rele1_activo = false; // Variable para rastrear si el relé1 está activo
bool rele3_activo = false; // Variable para rastrear si el tercer relé está activo
bool mostrar_turbo_actualizado = false; // Variable para controlar si se debe actualizar el mensaje "TURBO"
bool mostrar_turbo = false; // Variable para controlar si se muestra el mensaje "TURBO"
bool mostrar_bios = false; // Variable para controlar si se muestra el mensaje "BIOS"
bool mostrar_reset = false; // Bandera para controlar la visualización del mensaje "RESET"
bool buffer_clear = true; // Flag para indicar si se debe limpiar el buffer
bool actualizarPantalla = true; // Variable para controlar si se debe actualizar la pantalla
bool mostrar_turbo_temporal = false;
bool mostrar_turbo_anterior = false;
// Declaraciones de funciones
void mostrar_menu();
void ejecutar_opcion(int opcion);
void encoder();
void reloj();
bool menu_visible = false;
bool boton_previo = HIGH;
bool mostrarMenuEnEncoder = false; // Nueva variable para controlar la visualización del menú al girar el encoder
bool menu_anterior = false; // Variable para rastrear el estado anterior del menú
bool mostrar_dos_puntos = true; // Variable para controlar la visibilidad de los dos puntos
unsigned long tiempo_anterior = 0; // Variable para controlar el tiempo
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_ADDR 0x3C
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS3231 rtc;
String opciones[] = {"HORAS", "MINUTOS", "DATOS MSX", "ATRAS"};
int max_opciones = sizeof(opciones)/sizeof(opciones[0]);
void setup() {
// Inicializar la comunicación serial
Serial.begin(9600);
//Serial.println(max_opciones);
if (!rtc.begin()) {
Serial.println("No se pudo encontrar RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC perdió la alimentación, estableciendo la hora...");
// Coloca el código para establecer la hora aquí
}
// Inicializar pantalla
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.display();
delay(2000);
// Inicializar logo
display.clearDisplay();
display.drawBitmap(0, 0, logo, 128, 32, WHITE);
display.display();
delay(5000);
// Inicializar pines como entradas
pinMode(clkPin, INPUT);
pinMode(dtPin, INPUT);
pinMode(btnPin, INPUT_PULLUP);
// Declaramos los pines que vamos a utilizar y el tipo que van a tener dichos pines RELES
pinMode(rele1_activador, OUTPUT); // Para activar el rele 1
pinMode(rele1_interruptor, INPUT); // Para leer el interruptor que activa el rele 1 turbo
pinMode(rele2_activador, OUTPUT); // Para activar el rele 2
pinMode(rele2_interruptor, INPUT); // Para leer el interruptor que activa el rele 2 bios
pinMode(rele3_interruptor, INPUT); // Para leer el interruptor que activa el rele 3 reset
pinMode(rele3_activador, OUTPUT);
digitalWrite(rele1_activador,LOW); //apagamos las salida para inicializar el programa rele 1
digitalWrite(rele2_activador,LOW); //apagamos las salida para inicializar el programa rele 2
digitalWrite(rele3_activador, LOW); // Apaga inicialmente el relé
state_clk_old = digitalRead(clkPin);
mostrar_menu();
}
void loop() {
int state_btn = digitalRead(btnPin);
int rele1_estado_actual = digitalRead(rele1_interruptor);
int rele2_estado_actual = digitalRead(rele2_interruptor);
int rele3_estado_actual = digitalRead(rele3_interruptor);
unsigned long tiempoActual = millis();
if (rele1_estado_actual != rele1_estado_anterior) {
if (rele1_estado_actual == HIGH) {
mostrar_turbo = true;
Serial.println("Relé activado. Mostrando mensaje TURBO.");
} else {
mostrar_turbo = false;
// No limpiar el área específica cuando el relé se desactiva
}
rele1_estado_anterior = rele1_estado_actual;
}
if (rele2_estado_actual != rele2_estado_anterior) {
if (rele2_estado_actual == HIGH) {
mostrar_bios = true;
Serial.println("Relé 2 activado. Mostrando mensaje correspondiente.");
} else {
mostrar_bios = false;
// No limpiar el área específica cuando el relé se desactiva
}
rele2_estado_anterior = rele2_estado_actual;
}
if (rele3_estado_actual != rele3_estado_anterior) {
if (rele3_estado_actual == HIGH) {
rele3_activo = !rele3_activo; // Invierte el estado del tercer relé al presionar el botón
digitalWrite(rele3_activador, rele3_activo ? HIGH : LOW); // Activa o desactiva el tercer relé
mostrar_reset = true; // Establece la bandera para mostrar el mensaje "RESET"
} else {
// Si se suelta el botón, desactiva el relé y la bandera para mostrar el mensaje
digitalWrite(rele3_activador, LOW);
rele3_activo = false;
mostrar_reset = false;
}
rele3_estado_anterior = rele3_estado_actual;
}
//reloj(mostrar_turbo); // Llama a la función reloj() pasando el estado de mostrar_turbo
if (state_btn == LOW && boton_previo == HIGH) {
delay(50); // Pequeña pausa para evitar rebotes
if (digitalRead(btnPin) == LOW) {
if (!menu_visible) {
// Si el menú no está visible, mostrarlo al presionar y soltar el botón
menu_visible = true;
count = 0;
} else if (count == max_opciones - 1) {
// Si el menú está visible y se selecciona "ATRAS", ocultar el menú
menu_visible = false;
} else if (opciones[count] == "HORAS") {
// Si se selecciona la opción "HORAS" al presionar y soltar el botón, mostrar la hora
ejecutar_opcion(count);
delay(100); // Pequeña pausa antes de entrar a la selección de horas
cambiar_hora(); // Llamar a la función para cambiar la hora
} else if (opciones[count] == "MINUTOS") {
// Si se selecciona la opción "MINUTOS" al presionar y soltar el botón, modificar los minutos
ejecutar_opcion(count);
delay(100); // Pequeña pausa antes de entrar a la selección de minutos
cambiar_minutos(); // Llamar a la función para modificar los minutos
} else if (opciones[count] == "DATOS MSX") {
// Si se selecciona la opción "DATOS MSX", mostrar los mensajes y esperar
ejecutar_opcion(count);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.print("S/N 000023");
display.setCursor(0, 17);
display.print("21/11/2023");
display.display();
delay(6000); // Mostrar los mensajes durante 6 segundos
display.clearDisplay(); // Limpiar la pantalla después de mostrar los mensajes
display.display();
mostrar_menu(); // Volver al menú después de mostrar los mensajes
delay(500); // Pequeña pausa para evitar rebotes del botón
} else {
ejecutar_opcion(count);
}
}
}
boton_previo = state_btn;
// Lógica para manejar el menú y la visualización del reloj
if (menu_visible) {
mostrar_menu(); // Mostrar el menú si está visible
} else {
reloj(mostrar_turbo, mostrar_bios, mostrar_reset); // Mostrar el reloj si el menú no está visible
}
// Actualizar la pantalla después de un intervalo de tiempo
if (tiempoActual - ultimoTiempoActualizacion >= intervaloActualizacion) {
display.clearDisplay();
if (!menu_visible) {
reloj(mostrar_turbo, mostrar_bios, mostrar_reset); // Mostrar el reloj si el menú no está visible
} else {
mostrar_menu(); // Mostrar el menú si está visible
}
display.display();
encoder();
delay(50);
}
if (digitalRead(rele1_interruptor) == HIGH)
{
digitalWrite(rele1_activador,HIGH); //activamos el pin que controla el rele 1
} else{
digitalWrite(rele1_activador,LOW); //desactivamos el pin que controla el rele 1
}
if (digitalRead(rele2_interruptor) == HIGH)
{
digitalWrite(rele2_activador,HIGH); //activamos el pin que controla el rele 1
} else{
digitalWrite(rele2_activador,LOW); //desactivamos el pin que controla el rele 1
}
if (buffer_clear) {
actualizarPantalla = true; // Si se necesita limpiar el buffer, se establece para actualizar la pantalla
buffer_clear = false; // Restablecer el flag
}
}
void cambiar_hora() {
DateTime hora_actual = rtc.now();
int horas_modificadas = hora_actual.hour(); // Guardar las horas actuales para comparación
int minutos = hora_actual.minute(); // Guardar los minutos actuales
bool horario_cambiando = true;
while (horario_cambiando) {
display.clearDisplay();
//display.setTextSize(2);
//display.setCursor(0, 0);
//display.print("CAMBIAR HORAS:");
//display.setTextSize(3);
//display.setCursor(0, 0);
//display.print(hora_actual.toString("HH")); // Mostrar la hora actual
display.display();
encoder(); // Leer el encoder para incrementar o decrementar las horas
int state_btn = digitalRead(btnPin);
// Detectar cambio de estado del botón para confirmar el cambio de hora
if (state_btn == LOW && boton_previo == HIGH) {
delay(50); // Pequeña pausa para evitar rebotes
if (digitalRead(btnPin) == LOW) {
rtc.adjust(DateTime(hora_actual.year(), hora_actual.month(), hora_actual.day(), horas_modificadas, minutos, 0));
horario_cambiando = false; // Salir del bucle cuando se confirme el cambio
}
}
boton_previo = state_btn;
// Incrementar o decrementar las horas según el giro del encoder
if (count > 0) {
horas_modificadas = (horas_modificadas + 1) % 24; // Incrementar las horas
count = 0;
} else if (count < 0) {
horas_modificadas = (horas_modificadas + 23) % 24; // Decrementar las horas
count = 0;
}
// Comprobar si las horas han cambiado para actualizar la visualización en la pantalla
int horas_nuevas = hora_actual.hour();
if (horas_modificadas != horas_nuevas) {
horas_modificadas = horas_nuevas;
delay(150); // Pequeña pausa para evitar cambios rápidos
}
}
}
void cambiar_minutos() {
DateTime hora_actual = rtc.now();
int minutos_modificados = hora_actual.minute(); // Guardar los minutos actuales para comparación
int minutos_nuevos = minutos_modificados; // Guardar los minutos modificados actualizados
bool minutos_cambiando = true;
bool boton_previo = HIGH;
while (minutos_cambiando) {
display.clearDisplay();
//display.setTextSize(2);
//display.setCursor(0, 0);
//display.print("CAMBIAR MINUTOS:");
display.setTextSize(3);
display.setCursor(45, 8);
display.print(minutos_modificados < 10 ? "0" + String(minutos_modificados) : String(minutos_modificados)); // Mostrar los minutos
display.display();
encoder(); // Leer el encoder para incrementar o decrementar los minutos
int state_btn = digitalRead(btnPin);
// Detectar cambio de estado del botón para confirmar el cambio de minutos
if (state_btn == LOW && boton_previo == HIGH) {
delay(50); // Pequeña pausa para evitar rebotes
if (digitalRead(btnPin) == LOW) {
rtc.adjust(DateTime(hora_actual.year(), hora_actual.month(), hora_actual.day(), hora_actual.hour(), minutos_modificados, 0));
minutos_cambiando = false; // Salir del bucle cuando se confirme el cambio
}
}
boton_previo = state_btn;
// Incrementar o decrementar los minutos según el giro del encoder
if (count > 0) {
minutos_modificados = (minutos_modificados + 1) % 60; // Incrementar los minutos
count = 0;
} else if (count < 0) {
minutos_modificados = (minutos_modificados + 59) % 60; // Decrementar los minutos
count = 0;
}
// Comprobar si los minutos han cambiado para actualizar la visualización en la pantalla
minutos_nuevos = hora_actual.minute();
if (minutos_modificados != minutos_nuevos) {
minutos_nuevos = minutos_modificados;
delay(150); // Pequeña pausa para evitar cambios rápidos
}
}
}
void encoder() {
int state_clkPin = digitalRead(clkPin);
int state_dtPin = digitalRead(dtPin);
if (state_clk_old == HIGH && state_clkPin == LOW) {
if (state_dtPin == LOW) {
count--;
} else {
count++;
}
if (count < 0) {
count = max_opciones - 1;
}
if (count > max_opciones - 1) {
count = 0;
}
mostrarMenuEnEncoder = true; // Establecer la bandera para mostrar el menú al girar el encoder
} else {
mostrarMenuEnEncoder = false; // Si no se está girando el encoder, desactivar la bandera
}
delay(5);
state_clk_old = state_clkPin;
}
void mostrar_menu(){
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.print("MENU:");
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 16);
display.print(opciones[count]);
display.display();
}
void reloj(bool mostrar_turbo, bool mostrar_bios, bool mostrar_reset) {
DateTime now = rtc.now(); // Obtener la fecha y hora actual del RTC
// Formatear la hora en una cadena (HH:MM)
String hora = String(now.hour());
String minuto = String(now.minute());
// Asegurarse de que la hora y los minutos tengan dos dígitos
if (hora.length() == 1) hora = '0' + hora;
if (minuto.length() == 1) minuto = '0' + minuto;
// Mostrar la hora en la pantalla OLED junto con el mensaje "TURBO"
display.clearDisplay();
display.setTextSize(3);
display.setCursor(3, 8); // Posición de la hora
display.print(hora);
display.setTextColor(SSD1306_WHITE);
display.setCursor(37, 8); // Posición de los dos puntos
display.print(":");
display.setCursor(53, 8); // Posición de los minutos
display.print(minuto);
if (mostrar_turbo) {
display.setTextSize(1);
display.setCursor(95, 0); // Posición del mensaje "TURBO"
display.println("TURBO");
}
if (mostrar_bios) {
display.setTextSize(1);
display.setCursor(96, 15); // Posición del mensaje "MSX2"
display.println("MSX2+");
} else {
display.setTextSize(1);
display.setCursor(96, 10); // Posición del mensaje "MSX2+" (cuando relé 2 está desactivado)
display.println("MSX2");
}
if (mostrar_reset) {
display.clearDisplay();
display.setTextSize(3);
display.setCursor(20, 8); // Posición del mensaje "RESET"
display.println("RESET");
}
display.display();
}
void ejecutar_opcion(int opcion) {
switch (opcion) {
case 0: // HORAS
if (menu_visible && opcion == count) {
bool horario_cambiando = true;
int horas = rtc.now().hour(); // Obtener las horas actuales
int minutos = rtc.now().minute(); // Obtener los minutos actuales
int horas_previas = horas; // Guardar las horas iniciales para comparación
while (horario_cambiando) {
display.clearDisplay();
//display.setTextSize(2);
//display.setCursor(0, 0);
//display.print("CAMBIAR HORAS:");
display.setTextSize(3);
display.setCursor(45, 8);
display.print(String(horas)); // Mostrar la hora actual
display.display();
encoder(); // Leer el encoder para incrementar o decrementar las horas
if (count > 0) {
horas = (horas + 1) % 24; // Incrementar las horas
count = 0;
} else if (count < 0) {
horas = (horas + 23) % 24; // Decrementar las horas
count = 0;
}
// Mostrar las horas y minutos en la pantalla OLED
//display.print(String(horas));
display.display();
delay(100); // Pequeña pausa para evitar cambios rápidos
// Confirmar el cambio de horas al presionar el botón
int state_btn = digitalRead(btnPin);
if (state_btn == LOW && horas != horas_previas) {
rtc.adjust(DateTime(rtc.now().year(), rtc.now().month(), rtc.now().day(), horas, minutos, 0));
horario_cambiando = false; // Salir del bucle
}
}
}
break;
case 1: // MINUTOS
if (menu_visible && opcion == count) {
cambiar_minutos(); // Llamar a la función para modificar los minutos
}
break;
case 2: // DATOS MSX
// if (menu_visible && opcion == count) {
//display.clearDisplay();
//display.setTextSize(2);
//display.setCursor(0, 0);
//display.print("S/N 000023");
//display.setCursor(0, 17);
//display.print("21/11/2023");
//display.display();
//delay(6000); // Mostrar los mensajes durante 2 segundos
//display.clearDisplay(); // Limpiar la pantalla después de mostrar los mensajes
//display.display();
//mostrar_menu(); // Volver al menú después de mostrar los mensajes
// }
break;
case 3: // ATRAS
// Acciones para la opción ATRAS
break;
default:
// Opción inválida
break;
}
}
el código lo que realiza es al arrancar sale un logo, pasado unos segundos aparece el reloj para dar la hora, también lleva e relés que al activarlos lanzan un mensaje a la pantalla. al apretar el pulsador del encoder me aparece un menú en el cual hay 4 opciones con el encoder me muevo por el menú y con el botón del encoder entro en la opción seleccionada. 2 opciones son "horas" y "minutos" en el cual al entrar me aparecen dos dígitos para modificar las horas y los minutos. Otra opción es "atras" la cual al seleccionar y pulsar me devuelve al reloj. La otra opción que queda al seleccionarla y pulsarla sale un mensaje durante unos segundos. utilizo un encoder rotativo, una pantalla oled de 128x32 un Rtc, 3 relés y un arduino nano.
gracias y salu2.