#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 6 //DT
#define ROT1_EN_B 5 //CLK
#define BTN_MENU 4 //Boton seleccion menu
//Definimos boton reset
byte reset= 7; //Boton reset
//Definimos los pines de entrada del encoder de medida
#define EN_MED_A 2 //DT
#define EN_MED_B 3 //CLK
volatile unsigned int temp1, counter3 = 0; //Esta variable aumentará o disminuirá dependiendo de la rotación del encoder.
//Variables para antirebote de encoder de menu
uint8_t lrmem = 3;
int lrsum = 0;
int num = 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;
//Variables para el calculo con el encoder de medida
int sensor01;
int sensor02;
int stepOld;
int step;
long PulseCount;
float PulsePost;
//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);
}
//Calculos de movimiento con encoder de medición
void checkState(){
sensor01 = digitalRead(EN_MED_A);
sensor02 = digitalRead(EN_MED_B);
if(sensor01 == 1 && sensor02 == 1){
step = 0;
if(stepOld == 1){
PulseCount--;
}
if(stepOld == 3){
PulseCount++;
}
stepOld = 0;
}
if(sensor01 == 0 && sensor02 == 1){
step = 1;
if(stepOld == 2){
PulseCount--;
}
if(stepOld == 0){
PulseCount++;
}
stepOld = 1;
}
if(sensor01 == 0 && sensor02 == 0){
step = 2;
if(stepOld == 3){
PulseCount--;
}
if(stepOld == 1){
PulseCount++;
}
stepOld = 2;
}
if(sensor01 == 1 && sensor02 == 0){
step = 3;
if(stepOld == 0){
PulseCount--;
}
if(stepOld == 2){
PulseCount++;
}
stepOld = 3;
}
}
void setup()
{
////Leemos los datos de la eeprom de diametro de rueda y pasos de encoder y los asignamos a sus variables
EEPROM.get(0,dia_rueda);
EEPROM.get(10,pasos_encoder);
////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);
////A pulso ascendente de codificador activó ai0(). AttachInterrupt 0 es el DigitalPin n.º 2 en el Arduino.
attachInterrupt(0, ai0, RISING);
////B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
attachInterrupt(1, ai1, RISING);
pinMode(reset, INPUT_PULLUP);//Definimos el pin del boton como entrada con pullup para no tener que usar resistencia externa
//// variables calculos encoder medición
attachInterrupt(0, checkState, CHANGE);
attachInterrupt(1, checkState, CHANGE);
////Variables para realizar el conteo encoder de medida
PulseCount = 0;
PulsePost = 0;
// 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 ai0() {
// ai0 is activated if DigitalPin nr 6 is going from LOW to HIGH
// Check pin 7 to determine the direction
if(digitalRead(7)==LOW) {
counter3++;
}else{
counter3--;
}
}
void ai1() {
// ai0 is activated if DigitalPin nr 7 is going from LOW to HIGH
// Check with pin 6 to determine the direction
if(digitalRead(6)==LOW) {
counter3--;
}else{
counter3++;
}
}
void loop()
{
////Contador encoder medida
if( counter3 != temp1 ){
Serial.println (counter3);
temp1 = counter3;
}
///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 estado anterior 23
else if( Estado == 2)
{
PulsePost=(360.0/pasos_encoder)*(PulseCount/4);
lcd.setCursor(0, 0);
if (PulsePost ==360 || PulsePost ==-360){
PulsePost=0;
PulseCount = 0;
}
lcd.setCursor(3, 1);
if(PulsePost > -1){
lcd.print(" ");
}
if(PulsePost< 10 && PulsePost > -10){
lcd.print(" ");
}
if(PulsePost < 100 && PulsePost > -100){
lcd.print(" ");
}
lcd.print(PulsePost);
lcd.write( (char)223);
if (Boton == 0){
Boton=1;
Sig_Estado = 1;
}
if (digitalRead(reset)==LOW && Estado==2) {
PulsePost=0;
PulseCount = 0;
Sig_Estado = 2;
}
}
////Estado 3 modo distancia y calculo de la misma estado anterior 22
else if( Estado == 3)
{
dis_recorrida= ((((dia_rueda*PI)/pasos_encoder)*(PulseCount/4))/10);
lcd.setCursor(4, 1);
if(dis_recorrida > -1){
lcd.print(" ");
}
if(dis_recorrida< 10 && dis_recorrida > -10){
lcd.print(" ");
}
if(dis_recorrida < 100 && dis_recorrida > -100){
lcd.print(" ");
}
lcd.print(dis_recorrida,2);
//lcd.setCursor(13, 1);
lcd.print(" Cm ");
if (Boton == 0){
Boton=1;
Sig_Estado = 1;
}
if (digitalRead(reset)==LOW && Estado==3) {
dis_recorrida=0;
PulseCount = 0;
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 Modo distancia ===> 3 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.");
Boton=1;
Sig_Estado = 3;
}
////Estado 23 Modo grados ===> 2 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 ");
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;
}