// No muestra bien los tercios a modificar
// Pr algún motivo si uso // lcd.setCursor(0, 0); // lcd.print(" N: "); no me imprime bien los números en el puerto en serie.
// Como uso pines analógicos necesito poner resistencias pulldown en cada fotodetector.
// El estado 0 significa que no está midiendo nada.
// El estado 1023 (o casi) significa que el sensor está midiendo algo.
// Como se usa el Timer 1 no se puede usar digitalWrite en los pines: 9 y 10.
// Display: SDA va a A4 y SCL va a A5.
// El encoder trucho que conseguí funciona teniendo siempre los pines A y B abiertos (en 1 con el internal pullup). En cada click, pasa a ambos por el cero (el orden depende del sentido de giro).
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define pin_sensor_1 A1
#define pin_sensor_2 A2
#define pin_sensor_3 A3
#define pin_transistor_leds_IR 2
#define pin_led_indicador 3
#define pin_boton_PAUSA 4
#define pin_Encoder_SW 5
#define pin_Encoder_A 6
#define pin_Encoder_B 7
#define pin_Buzzer 8
//Crear el objeto lcd dirección 0x27 (a veces es 0x3F) y 16 columnas x 2 filas
LiquidCrystal_I2C lcd(0x27, 16, 2);
int tercios_totales_de_vuelta = 0;
int umbral_de_deteccion = 500; // Sale de probar con la rueda enebradora.
boolean deteccion_sensor_1 = false;
boolean deteccion_sensor_2 = false;
boolean deteccion_sensor_3 = false;
int estado_sensor_1_actual = 0;
int estado_sensor_1_actual_IR = 0;
int estado_sensor_1_actual_Ruido = 0;
int estado_sensor_1_anterior = 0;
int estado_sensor_2_actual = 0;
int estado_sensor_2_actual_IR = 0;
int estado_sensor_2_actual_Ruido = 0;
int estado_sensor_2_anterior = 0;
int estado_sensor_3_actual = 0;
int estado_sensor_3_actual_IR = 0;
int estado_sensor_3_actual_Ruido = 0;
int estado_sensor_3_anterior = 0;
volatile boolean time_to_blink = false;
boolean blink_on = false;
// Estados:
enum tipo_estado { est_Contador,
est_Modificador,
est_Pausa };
// estado_actual = tipo_estado::menu_inicial;
tipo_estado estado_actual = est_Contador;
tipo_estado estado_anterior = est_Contador;
void setup() {
Serial.begin(9600);
pinMode(pin_led_indicador, OUTPUT);
pinMode(pin_transistor_leds_IR, OUTPUT);
digitalWrite(pin_led_indicador, HIGH);
digitalWrite(pin_transistor_leds_IR, LOW);
pinMode(pin_boton_PAUSA, INPUT_PULLUP);
pinMode(pin_Encoder_SW, INPUT_PULLUP);
pinMode(pin_Encoder_A, INPUT);
pinMode(pin_Encoder_B, INPUT);
pinMode(pin_Buzzer, OUTPUT);
// Inicializar el LCD
lcd.init();
//Encender la luz de fondo.
lcd.backlight();
lcd.clear();
// lcd.setCursor(0, 0);
// lcd.print(" N: ");
muestra_vueltas(tercios_totales_de_vuelta, 0);
setupTimer1();
}
void loop() {
// Verifica estados:
estado_actual = est_Modificador;
delay(50);
while (digitalRead(pin_Encoder_SW) == LOW) {} // Espera mientras el botón se mantenga pulsado. Cuando se suelta el botón se pasa al estado modificador. Tal vez, si se aprieta demasiado rápido, esta linea trae problemas.
delay(50);
Estado_Modificador(); // Entra en estado Modificador.
}
void setupTimer1() {
// Prepara el timer 1 para compararlo con 1 segundo.
// https://www.arduinoslovakia.eu/application/timer-calculator
noInterrupts();
// Clear registers
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// 1 Hz (16000000/((15624+1)*1024))
OCR1A = 15624;
// CTC: Clear Timer on Compare Match Mode
TCCR1B |= (1 << WGM12);
// Prescaler 1024 (también se podría usar un prescaler de 256 y un OCR1A=62496)
TCCR1B |= (1 << CS12) | (1 << CS10);
// Output Compare Match A Interrupt Enable. Se podría comparar otro tiempo como muestra GreatScott usando el March B.
TIMSK1 |= (1 << OCIE1A);
interrupts();
}
ISR(TIMER1_COMPA_vect) {
// Debe ser lo más corta posible, solo para "levantar alguna bandera" y listo.
// Al principio intenté prender y apagar el display desde acá y se me colgaba.
// Se ejecuta cada vez que se dispara la condición del timer 1.
TCNT1 = 0;
time_to_blink = true;
}
void Estado_Modificador() {
// Entra en este estado cuando se detecta que el botón del encoder está presionado.
// Sale de la función cuando se vuelve a presionar el botón del encoder.
// Al salir, siempre cambia el contador por el valor ingresado, así que si no se quiere modificar, hay que volver a elegir el mismo que tenía antes.
int encoder_A_actual; // uint8_t es equivalente a byte y es lo que está definido como argumento en la función digitalWrite().
int encoder_A_anterior;
int encoder_B_actual;
int tercios_totales_de_vuelta_a_modificar;
encoder_A_anterior = digitalRead(pin_Encoder_A);
tercios_totales_de_vuelta_a_modificar = tercios_totales_de_vuelta;
while (1) {
encoder_A_actual = digitalRead(pin_Encoder_A);
if (encoder_A_actual != encoder_A_anterior) { // Si se rotó la perilla. Creo que en cada click el A pasa a cero y, luego a 1, por lo que solo hay que contabilizar uno de los dos estados.
if (encoder_A_actual == 1) { // Si se rotó la perilla. Creo que en cada click el A pasa a cero y, luego a 1, por lo que solo hay que contabilizar uno de los dos estados.
if (digitalRead(pin_Encoder_B) != encoder_A_actual) { // Se rotó en sentido horaio.
tercios_totales_de_vuelta_a_modificar++;
} else {
tercios_totales_de_vuelta_a_modificar--;
}
/*
Serial.print("encoder_A_anterior: ");
Serial.println(encoder_A_anterior);
Serial.print("encoder_A_actual: ");
Serial.println(encoder_A_actual);
Serial.print("Encoder_B: ");
Serial.println(digitalRead(pin_Encoder_B));
*/
Serial.print("tercios_a_modificar:");
Serial.println(tercios_totales_de_vuelta_a_modificar);
muestra_vueltas(tercios_totales_de_vuelta_a_modificar, 1);
}
encoder_A_anterior = encoder_A_actual;
}
delay(1); // Es el debouncer más simple que existe.
}
}
void muestra_vueltas(int tercios_de_vuelta, int fila) {
// fila indica la fila del display que debe ser cambiada con el dato de las vueltas.
int vueltas;
byte fraccion_de_vuelta;
char char_texto_linea_display[16];
vueltas = abs(tercios_de_vuelta / 3);
fraccion_de_vuelta = abs(tercios_de_vuelta % 3); // Toma valores 0, 1 o 2.
if (fila == 0) {
sprintf(char_texto_linea_display, " N: %s%03d %d/3", tercios_de_vuelta < 0 ? "-" : "", vueltas, fraccion_de_vuelta); // Muchos dicen que usar sprintf es lento, pero acá no me importa.
}
else {
sprintf(char_texto_linea_display, " Change: %s%03d %d/3", tercios_de_vuelta < 0 ? "-" : "", vueltas, fraccion_de_vuelta); // Muchos dicen que usar sprintf es lento, pero acá no me importa.
}
lcd.setCursor(0, fila);
lcd.print(char_texto_linea_display);
//Serial.print("Vueltas: ");
//Serial.println(tercios_de_vuelta);
Serial.println(char_texto_linea_display);
/*
Serial.print(" ");
Serial.print(fraccion_de_vuelta);
Serial.println("/3");
*/
}
void Actualiza_tercios_totales(boolean incrementa) {
if (incrementa) {
tercios_totales_de_vuelta++;
}
else {
tercios_totales_de_vuelta--;
}
muestra_vueltas(tercios_totales_de_vuelta, 0);
if ((tercios_totales_de_vuelta % 3) == 0) {
tone(pin_Buzzer, 330, 50);
}
else {
tone(pin_Buzzer, 165, 50);
}
// digitalWrite(pin_led_indicador, HIGH); // se puede mejorar con algún contador para que se mantenga encendido más tiempo.
}