#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <EEPROM.h>
// Inicializamos las variables.
LiquidCrystal_I2C lcd(0x27, 16,2); // 0x3F 0x27
float dis_recorrida ;
float grados ;
float dia_rueda ;
int pasos_encoder ;
//Rotary 1 encoder (dial) pines
#define ROT1_EN_A 4 //DT
#define ROT1_EN_B 3 //CLK
#define BTN_MENU 2 //Boton seleccion menu
//Definimos boton reset
byte reset= 5; //Boton reset
//Definimos los pines de entrada del encoder de medida
#define EN_MED_A 7 //DT
#define EN_MED_B 6 //CLK
//Variables para antirebote de encoder de menu
uint8_t lrmem = 3;
int lrsum = 0;
int num = 0;
//Variables para antirebote de encoder de medición
uint8_t lrmem2 = 3;
int lrsum2 = 0;
int num2 = 0;
//Preparando antirrebote de boton de menu
bool estadoPulsador, anteriorPulsador;
unsigned long db;
byte Boton=1;
//Preparamos para los cambios de estado
int Estado = 1;
int Sig_Estado = 1;
int counter = 0;
int State;
int LastState;
//Configuracion del antirebote del encoder de menu
int8_t rotary()
{
static int8_t TRANS[] = {0,-1,1,14,1,0,14,-1,-1,14,0,1,14,1,-1,0};
int8_t l, r;
l = digitalRead(ROT1_EN_B);
r = digitalRead(ROT1_EN_A);
lrmem = ((lrmem & 0x03) << 2) + 2*l + r;
lrsum = lrsum + TRANS[lrmem];
/* El encoder no esta en estado neutral */
if(lrsum % 4 != 0) return(0);
/* Encoder en el estado neutral */
if (lrsum == 4)
{
lrsum=0;
return(1);
}
if (lrsum == -4)
{
lrsum=0;
return(-1);
}
/* lrsum > 0 if the impossible transition */
lrsum=0;
return(0);
}
//Configuracion del antirebote del encoder de medicion
int8_t rotary2()
{
static int8_t TRANS2[] = {0,-1,1,14,1,0,14,-1,-1,14,0,1,14,1,-1,0};
int8_t l2, r2;
l2 = digitalRead(EN_MED_B);
r2 = digitalRead(EN_MED_A);
lrmem2 = ((lrmem2 & 0x03) << 2) + 2*l2 + r2;
lrsum2 = lrsum2 + TRANS2[lrmem2];
/* El encoder no esta en estado neutral */
if(lrsum2 % 4 != 0) return(0);
/* Encoder en el estado neutral */
if (lrsum2 == 4)
{
lrsum2=0;
return(1);
}
if (lrsum2 == -4)
{
lrsum2=0;
return(-1);
}
/* lrsum > 0 if the impossible transition */
lrsum2=0;
return(0);
}
void setup()
{
EEPROM.get(0,dia_rueda);
//if (dia_rueda==255) dia_rueda=20;
EEPROM.get(10,pasos_encoder);
//if (pasos_encoder==255) pasos_encoder=360;
////Definimos de que tipo son los pines del encoder de los menus o rotary
pinMode(BTN_MENU, INPUT_PULLUP);
pinMode(ROT1_EN_A, INPUT_PULLUP);
pinMode(ROT1_EN_B, INPUT_PULLUP);
////Definimos de que tipo son los pines del encoder de mediciones
pinMode(EN_MED_A, INPUT_PULLUP);
pinMode(EN_MED_B, INPUT_PULLUP);
pinMode(reset, INPUT_PULLUP);//Definimos el pin del boton como entrada con pullup para no tener que usar resistencia externa
// Inicializamos la pantalla.
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("Medidor");
lcd.setCursor(0, 1);
lcd.print("Angulo-Distancia");
delay(1500);
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Por");
lcd.setCursor(1, 1);
lcd.print("Joaquin Miguel");
//Esperamos 3 segundos
delay(3000);
lcd.clear();
}
void loop()
{
///ANTIRREBOTE PULSADOR
estadoPulsador=digitalRead(BTN_MENU);
if(!estadoPulsador && anteriorPulsador && millis() -db >=150UL){
Boton--;
db=millis();
}
anteriorPulsador=estadoPulsador;
Estado = Sig_Estado;
////Estado 1 Menu principal
if(Estado == 1)
{
int menu;
String arrayMenu[] = {"Modo grados","Modo distancia","Configuracion"};
int size = sizeof(arrayMenu) / sizeof(arrayMenu[0]);
menu = menuANTIFALLOSLENTO(arrayMenu,size); // no hace falta poner el numero 6, se calcula automaticamente. Solo debes de cambiar arrayMenu
if(menu == -1)Sig_Estado = 1;
else if(menu == 1)Sig_Estado = 23; // Modo grados-->2
else if(menu == 2)Sig_Estado = 22; // Modo distancia--->3
else if(menu == 3)Sig_Estado = 4; // Configuración--->4
}
////Estado 2 Calculo en el modo grados
else if( Estado == 2)
{ int min_gra = 0;
int max_gra = 359;
int8_t res3;
res3 = rotary2();
if (res3!=0){
num2 = num2 + res3;
if (res3 > 0){
grados = grados + (360/pasos_encoder);}
if (res3 < 0){
grados = grados - (360/pasos_encoder);}
if (grados > max_gra) grados=min_gra;
if (grados < min_gra) grados=(360-(360/pasos_encoder));
lcd.setCursor(2, 0);
lcd.print("Grados Giro");
lcd.setCursor(7, 1);
lcd.print(" ");
lcd.setCursor(7, 1);
lcd.print(grados,0);
lcd.setCursor(10, 1);
lcd.write( (char)223);
}
if (Boton == 0){
Boton=1;
Sig_Estado = 1;
}
if (digitalRead(reset)==LOW && Estado==2) {
grados=0;
lcd.setCursor(7, 1);
lcd.print(" ");
lcd.setCursor(7, 1);
lcd.print(grados,0);
lcd.setCursor(10, 1);
lcd.write( (char)223);
Sig_Estado = 2;
}
}
////Estado 3 modo distancia y calculo de la misma
else if( Estado == 3)
{ //Serial.println(dia_rueda);
float Long_cir = ((dia_rueda/10)*PI); //Calculamos la longitud dela rueda y lo asignamos a Long_cir
float Cal_dis_pas = (Long_cir/pasos_encoder); //Calculamos la distacia por paso de encoder
//Serial.println(Cal_dis_pas);
int8_t res3;
res3 = rotary2();
if (res3!=0){
num2 = num2 + res3;
if (res3 > 0){
dis_recorrida = dis_recorrida + Cal_dis_pas;}
if (res3 < 0){
dis_recorrida = dis_recorrida - Cal_dis_pas;}
lcd.setCursor(1, 0);
lcd.print("Distancia Reco.");
lcd.setCursor(5, 1);
lcd.print(" ");
lcd.setCursor(5, 1);
lcd.print(dis_recorrida,1);
lcd.setCursor(11, 1);
lcd.print("cm");
}
if (Boton == 0){
Boton=1;
Sig_Estado = 1;
}
if (digitalRead(reset)==LOW && Estado==3) {
dis_recorrida=0;
lcd.setCursor(5, 1);
lcd.print(" ");
lcd.setCursor(5, 1);
lcd.print(dis_recorrida,1);
lcd.setCursor(11, 1);
lcd.print("cm");
Sig_Estado = 3;
}
}
////Estado 4 menu nº2
else if( Estado == 4)
{
int menu;
String arrayMenu[] = {"Dia.Rueda","Pulsos enc.","Volver"};
int size = sizeof(arrayMenu) / sizeof(arrayMenu[0]);
menu = menuANTIFALLOSLENTO(arrayMenu,size);
if(menu == -1)Sig_Estado = 1;
else if(menu == 1)Sig_Estado = 20;
else if(menu == 2)Sig_Estado = 21;
else if(menu == 3)Sig_Estado = 1;
}
////Estado 20 Limpiamos pantalla viniendo de estado 4 y pasamos a estado 40
else if( Estado == 20)
{
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Diametro rueda");
lcd.setCursor(4, 1);
lcd.print(dia_rueda,1);
lcd.setCursor(11, 1);
lcd.print("mm");
Boton=1;
Sig_Estado = 40; //Enviamos al estado 40 despues de limpiar la pantalla para poder ajustar
}
////Estado 21 Limpiamos pantalla viniendo de estado 4 y pasamos al estado 41
else if( Estado == 21)
{
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Pulsos encoder");
lcd.setCursor(6, 1);
lcd.print(pasos_encoder);
Boton=1;
Sig_Estado = 41;//Enviamos al estado 41 despues de limpiar la pantalla para poder ajustar
}
////Estado 22 Limpiamos pantalla viniendo de estado 1 y pasamos al estado 3 para hacer los calculos
else if( Estado == 22) //Modo distancia recorrida
{
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Distancia Reco.");
lcd.setCursor(5, 1);
lcd.print(" ");
lcd.setCursor(5, 1);
lcd.print(dis_recorrida,1);
lcd.setCursor(11, 1);
lcd.print("cm");
Boton=1;
Sig_Estado = 3;
}
////Estado 23 Limpiamos pantalla viniendo de estado 1 y pasamos al estado 2 para hacer los calculos
else if( Estado == 23) //Modo grados
{
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Grados Giro");
lcd.setCursor(7, 1);
lcd.print(" ");
lcd.setCursor(7, 1);
lcd.print(grados,0);
lcd.setCursor(10, 1);
lcd.write( (char)223);
Boton=1;
Sig_Estado = 2;
}
//// Estado 40 venimos del menu d econfiguracion ajuste de Diametro de rueda
else if( Estado == 40)
{
int dia_rueda_min = 0;
int dia_rueda_Max = 300;
int8_t res;
res = rotary();
float res2;
if (res!=0){
num = num + res;
res2=int(res);//Covertimos el valor de res a entero para poder saltar de 0.5 en 0.5
dia_rueda = dia_rueda + (res2/2); //Calculamos el diametro de rueda de 0.5 en 0.5 mm(si queremos mas ajuste tocar aquí)
if (dia_rueda > dia_rueda_Max) dia_rueda=dia_rueda_Max;
if (dia_rueda < dia_rueda_min) dia_rueda=dia_rueda_min;
lcd.setCursor(1, 0);
lcd.print("Diametro rueda");
lcd.setCursor(4, 1);
lcd.print(" ");
lcd.setCursor(4, 1);
lcd.print(dia_rueda,1);
lcd.setCursor(11, 1);
lcd.print("mm");
}
if (Boton ==0){
EEPROM.put(0, dia_rueda);
Boton=1;
Sig_Estado = 4; }
}
//// Estado 41 venimos del menu de configuracion ajuste de pulsos encoder
else if( Estado == 41)
{
int encoder_min = 0;
int encoder_Max = 1024;
int8_t res;
res = rotary();
if (res!=0){
num = num + res;
pasos_encoder= pasos_encoder + res;
if (pasos_encoder > encoder_Max) pasos_encoder=encoder_Max;
if (pasos_encoder < encoder_min) pasos_encoder=encoder_min;
lcd.setCursor(1, 0);
lcd.print("Pulsos encoder");
lcd.setCursor(6, 1);
lcd.print(" ");
lcd.setCursor(6, 1);
lcd.print(pasos_encoder);
}
if (Boton ==0){
EEPROM.put(10, pasos_encoder);
Boton=1;
Sig_Estado = 4; }
}
}
//Parte para generar los menus
int menuANTIFALLOSLENTO(String *arrayMenu,int size)
{
//Vamos a marcar en que tiempo se hizo cualquier cambio y si se hizo un cambio hace muy poco tiempo y se pulso, ese cambio le damos por malo. ok?
//Pintamos el cursor y marcamos la primera opcion
lcd.clear();
lcd.setCursor(0,0);
lcd.print("> ");
float opcion = 1; //del 1 al 1.75 Opcion 1 //Del 2 al 2.75 opcion 2
int extraOpcion = 0;
float incremento = 1;
//Pinta los 4 primeros del menu como mucho
for(int x = 0; x < size && x <= 1 ; x++) //
{
lcd.setCursor(2,x);
lcd.print(arrayMenu[x]);
}
delay(500);
byte DialPos1 = 0;
byte Last_DialPos1 = 0;
unsigned long tiempoCambioIncremento = 0;
unsigned long tiempoCambioDecremento = 0;
//Si pulsamos el boton central sale del bucle
while(digitalRead(BTN_MENU) == 1)
{
//Leemos el estado del encoder de menu
DialPos1 = (digitalRead(ROT1_EN_B) << 1) | digitalRead(ROT1_EN_A);
// Si la posicion ha cambiado
if(DialPos1 == 3 && (Last_DialPos1 == 1 ||Last_DialPos1 == 2) )
{
//Esta girando en el sentido de las gujas del reloj ?
if (DialPos1 == 3 && Last_DialPos1 == 1)
{
if(opcion <size)
{
opcion += incremento;
tiempoCambioIncremento = millis();
}
}
//Is the dial being turned counter-clockwise ?
if (DialPos1 == 3 && Last_DialPos1 == 2)
{
if(opcion>1)
{
opcion -=incremento;
tiempoCambioDecremento = millis();
}
}
//Si sobrepasamos el limite por debajo
if(opcion < 1 + extraOpcion)
extraOpcion--;
//Si sobrepasamos el limite por encima
if(opcion > 2 + extraOpcion)
extraOpcion++;
//Pintamos de nuevo el menu
lcd.clear();
for(int x = extraOpcion; x < size && x <= (2+extraOpcion) ; x++) //
{
lcd.setCursor(2,x - extraOpcion);
lcd.print(arrayMenu[x]);
}
//Pintamos el cursor
lcd.setCursor(0,opcion-1-extraOpcion);
lcd.print(">");
}
//Remember the last position of the dial so we know when it has changed
Last_DialPos1 = DialPos1;
}
//Aqui hemos salido del bucle ya que hemos pulsado el boton Enter o ATRAS
//En cualquier caso no debería haberse movido ninguna tecla en 250ms?
if(millis() - tiempoCambioIncremento < 250)
opcion -= incremento;//Corregimos aunque no de tiempo a pintarla, ya que salimos del bucle y cambiamos de estado
else if(millis() - tiempoCambioDecremento < 250)
opcion += incremento;
return opcion;
}