// Version 10: Ejecución de Menus sin librerías adicionales: --> Funcionando!
// - Menus (en desarrollo bajo la Version 5 (actual):
// * Menu 0: Empezar o Configurar --> Funcionando
// * Menu 1: Calibración Compas --> Funcionando
// * Menu 2: Calibración diámetro de rueda --> Funcionando
// * Menu 3: Ajuste Trip (+1km, +10km, display valor de Trip) --> En desarrollo
// - Calibración del diametro de rueda completada
// - Calibración del compas completada
// - Modo carrera Funcionando
// - Introduccion de interrupcion para sensor de efecto HALL --> Funcionando
// - Almacenamiento de variables de la configuración --> Funcionando y terminado!
// - Botón D4: Vuelta a Menu desde modo Carrera
// - Botón D5: Almacenamiento de valor Trip en Memoria EEPROM
/*
Arduino Magnetometer
A5 SCL
A4 SDA
3.3V VCC
GND GND
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h> // HMC5883L Magnetometer Library
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Variables para gestión de Menús-------------------------------------------------------------------------------------------
int upButton = 7; //|
int downButton = 6; //|
int selectButton = 2; //|
int menu = 1; //|
int ReturnButton = 4; //|*******
int SaveButton = 5; //|*******
//---------------------------------------------------------------------------------------------------------------------------
// Variables para gestión de entradas de variables para compas, Trip y diametro de Rueda-------------------------------------
//|
const int Button_Encrease = 7; //Button declinationAngle increase //|
const int Button_Decrease = 6; //Button declinationAngle decrease //|
const int Button_Set = 2; //Button: Set/Reset //|
const int sensor_HALL = 10; //Entrada del sensor de efecto HALL //|
const int Button_Return_Menu = 4; //Button vuelta a menu desde modo Carrera //|*******
const int Button_Save_Trip = 5; //Button almacenamiento en memoria valor Trip en modo Carrera //|*******
int Value0; //|
int Value1; //|
int Value2; //|
int Value3; //|
int Value4; //|*******
int Value5; //|*******
//---------------------------------------------------------------------------------------------------------------------------
//Variables del modo Trip----------------------------------------------------------------------------------------------------
float diametro; //Almacenaremos aquí el valor previamente almacenado en la EEPROM *************************************
int SensorRueda; //Valor sensor HALL
int SensorLastState; //Valor Last State sensor HALL
unsigned long ContadorRueda; //Contador de vueltas de la rueda
float TripMoto; // Correccion del Trip con resolcuión de 0,01 Km //´Modidifcar el código para que el aumento sea de 0.01Km //|*******
float metros; // Distancia recorrida en metros
float km; // Distancia recorrida en Km con 2 decimales
float offset; // Variable para el calculo del offset del Trip
const int timeThreshold = 63; // Tiempo de debuncing para la interrupcion --> Mejorar mediante Condensador 1uF ;;150ms = Version de prueba ;; 47 ms = 160 km/h ;; 63 ms = 120 km/h
int counter = 0;
long startTime = 0;
int ini = 0;
//---------------------------------------------------------------------------------------------------------------------------
//Lectura de entradas para compás, Trip y diametro de rueda------------------------------------------------------------------
void ReadEntries(){ //|
Value0 = digitalRead(Button_Encrease); //|
Value1 = digitalRead(Button_Decrease); //|
Value2 = digitalRead(Button_Set); //|
Value3 = digitalRead(sensor_HALL); //|
SensorRueda = digitalRead(sensor_HALL); //--> Redundante pero ayuda a comprension del codigo //|
Value4 = digitalRead(Button_Return_Menu); //|*******
Value5 = digitalRead(Button_Save_Trip); //|*******
} //|
//---------------------------------------------------------------------------------------------------------------------------
void wheelCounter(){
if (millis() - startTime > timeThreshold)
{
ContadorRueda = ContadorRueda + 1;
startTime = millis();
}
}
//---------------------------------------------------------------------------------------------------------------------------
void TripWheel(){ //Modificado para uso con la interrupcion del puerto D3
if (ini == 0){
ContadorRueda = 0;
ini = 1;
}
if (counter != ContadorRueda){
counter = ContadorRueda;
if (counter == 1 && ini && 0){
counter = 0;
ContadorRueda = 0;
ini = 1;
}
}
metros = ContadorRueda*diametro;
km = metros/1000;
//do { //Comprueba que el nuevo valor del sensor se High para determinar que puede salir del bucle
// ReadEntries(); //Hay que leer solamente el valor del sensor HALL para salir del bucle en version final //|**************************
//}while (SensorRueda == LOW && SensorLastState == LOW);
//SensorLastState = HIGH; //Reinicia el valor del último estado del sensor
}
//---------------------------------------------------------------------------------------------------------------------------
//Variables para el compás---------------------------------------------------------------------------------------------------
//|
// Assign a unique ID to this sensor at the same time //|
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345); //|
//|
unsigned long previousMillis = 0; //|
unsigned long previousMillisSpeed = 0; //|
unsigned long previousMillisDistance = 0; //|
const long displayRefreshInterval = 500; //|
const long autoSaveAfter = 3000; //|
//|
float heading; //|
float declinationAngle; //|
float headingDegrees; //|
float offset_declinationAngle; //Almacenaremos aquí el valor previamente almacenado en la EEPROM *************************** //|
//---------------------------------------------------------------------------------------------------------------------------
//Función de lectura de datos del sensor magnético para el compas------------------------------------------------------------
void ReadCompas(){ //|
unsigned long currentMillis = millis(); //|
//|
// Get a new compass event //|
sensors_event_t event; //|
mag.getEvent(&event); //|
//|
// Hold the module so that Z is pointing 'up' and you can measure the heading with x&y //|
// Calculate heading when the magnetometer is level, then correct for signs of axis. //|
//float heading = atan2(event.magnetic.y, event.magnetic.x); //|
//float heading = atan2(event.magnetic.z, event.magnetic.x); //|
//float heading = atan2(event.magnetic.z, event.magnetic.y); //|
heading = atan2(event.magnetic.x, event.magnetic.y); //|
//|
// Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
// Find yours here: http://www.magnetic-declination.com/ //|
// Mine is: -13* 2' W, which is ~13 Degrees, or (which we need) 0.22 radians //|
// If you cannot find your Declination, comment out these two lines, your compass will be slightly off. //|
declinationAngle = 0.059 + offset_declinationAngle; //0.22; //|
heading += declinationAngle; //|
//|
// Correct for when signs are reversed. //|
if(heading < 0) //|
heading += 2 * PI; //|
//|
// Check for wrap due to addition of declination. //|
if(heading > 2 * PI) //|
heading -= 2 * PI; //|
//|
// Update data and display //|
if (currentMillis - previousMillis >= displayRefreshInterval) { //|
previousMillis = currentMillis; //|
//|
// Convert radians to degrees for readability. //|
headingDegrees = heading * 180 / M_PI; //|
} //|
} //|
//---------------------------------------------------------------------------------------------------------------------------
// Funciones para almacenar los nuevos valores de declinación magnética y del diámetro de rueda en memoria EEPROM---------//|
void eepromDec(){ //|
EEPROM.put(0, offset_declinationAngle); //Almacenamiento valor declinacion mag. en menu //|
delay(100); //|
} //|
//|
void eepromdia(){ //|
EEPROM.put(4, diametro);//Almacenamiento valor diametro en menu //|
delay(100); //|
} //|
//|
void eepromTrip(){ //Almacenamiento valor Trip (Contador Rueda) desde modo Carrera //|*******
EEPROM.put(8,km); //|
delay(100); //|
EEPROM.put(12,offset); //|
delay(100); //|
} //|
//------------------------------------------------------------------------------------------------------------------------//|
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
// Initialise the compass
if(!mag.begin()) {
Serial.println(F("Ooops, no HMC5883 detected... Check your wiring!"));
}
//ContadorRueda = 0; //El estatus inicial de la rueda se toma de la memoria, y se puede resetear en menú //|*******
//TripMoto = 0;
//metros = 0;
//km = 0;
//offset = 0; //El estatus inicial de la rueda se toma de la memoria, y se puede resetear en menú //|*******
EEPROM.get(0, offset_declinationAngle); //Obtención del offset de la declinación magnética
EEPROM.get(4, diametro); //Obtención del diametro actual de la rueda
EEPROM.get(8, km); //Obtención del Contador Rueda para cálculo del Trip almacenado //|*******
EEPROM.get(12,offset); //Obtención del valor offset almacenado //|*******
if (km > 0){
TripMoto = km + offset;
metros = km * 1000;
ContadorRueda = metros/diametro;
ini = 1;
}
if (km = 0 || km < 0){
km = 0;
metros = 0;
ContadorRueda = 0;
ini = 0;
}
attachInterrupt(digitalPinToInterrupt(sensor_HALL), wheelCounter, FALLING);
pinMode(upButton, INPUT_PULLUP);
pinMode(downButton, INPUT_PULLUP);
pinMode(selectButton, INPUT_PULLUP);
pinMode(sensor_HALL, INPUT_PULLUP);
pinMode(ReturnButton, INPUT_PULLUP); //|*******
pinMode(SaveButton, INPUT_PULLUP); //|*******
Value0 = HIGH;
Value1 = HIGH;
Value2 = HIGH;
Value3 = HIGH;
Value4 = HIGH;
Value5 = HIGH;
SensorRueda = HIGH;
SensorLastState = HIGH;
updateMenu();
}
void loop() {
if (!digitalRead(downButton)){
menu++;
updateMenu();
delay(100);
while (!digitalRead(downButton));
}
if (!digitalRead(upButton)){
menu--;
updateMenu();
delay(100);
while(!digitalRead(upButton));
}
if (!digitalRead(selectButton)){
executeAction();
updateMenu();
delay(100);
while (!digitalRead(selectButton));
}
if (!digitalRead(ReturnButton)){ //|*******
menu = 0;
executeAction();
updateMenu();
Serial.println(("Boton volver"));
delay(100);
while (!digitalRead(ReturnButton)); //|*******
}
//if (!digitalRead(SaveButton)){ //Para guardar no hace falta entrar en ningun menú //|*******
// eepromTrip();
// lcd.clear();
// lcd.setCursor(0,0);
// lcd.print("Guardando...");
// delay(1500); // Ajustar valor....***********************************************************************************************
//}
}
//Funciones de gestion de menú-----------------------------------------------------------------------------------------------
void updateMenu() { //|
switch (menu) { //|
case 0: //|
menu = 1; //|
break; //|
case 1: //|
lcd.clear(); //|
lcd.setCursor(0,0); //|
lcd.print((char)126); //|
lcd.setCursor(1,0); //|
lcd.print("Empezar"); //|
lcd.setCursor(1, 1); //|
lcd.print("Conf.Decl.Mag."); //|
break; //|
case 2: //|
lcd.clear(); //|
lcd.setCursor(1,0); //|
lcd.print("Empezar"); //|
lcd.setCursor(0,1); //|
lcd.print((char)126); //|
lcd.setCursor(1, 1); //|
lcd.print("Conf.Decl.Mag."); //|
break; //|
case 3: //|
lcd.clear(); //|
lcd.setCursor(0,0); //|
lcd.print((char)126); //|
lcd.setCursor(1,0); //|
lcd.print("Conf.Diam.Rueda"); //|
//lcd.setCursor(1,0); //|
//lcd.print((char)126); //|
lcd.setCursor(1,1); //|
lcd.print("Ajuste Trip");
break; //|
case 4: //|******
lcd.clear(); //|******
//lcd.setCursor(0,0); //|******
//lcd.print((char)126); //|******
lcd.setCursor(1,0); //|******
lcd.print("Conf.Diam.Rueda"); //|******
lcd.setCursor(0,1); //|******
lcd.print((char)126); //|******
lcd.setCursor(1,1); //|******
lcd.print("Ajuste Trip"); //|******
break; //|******
case 5: //|
menu = 4; //|
break; //|
} //|
} //|
//|
void executeAction() { //|
switch (menu) { //|
case 1: //|
delay(500);
action1();
break; //|
case 2: //|
action2(); //|
break; //|
case 3: //|
action3(); //|
break; //|
case 4: //|******
action4(); //|******
break; //|******
} //|
} //|
//---------------------------------------------------------------------------------------------------------------------------
//Funciones para la ejecución de los diferentes modos (Modo carrera o configuración de parámetros----------------------------
void action1() { //Función para modo carrera: Lectura y muestreo de los valores del Trip y del compás
ReadEntries();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Km:"); //--> Posicion 4
lcd.setCursor(0,1);
lcd.print("Rumbo:"); //--> Posicion 6
lcd.setCursor(7,0);
lcd.print(TripMoto,2); // Distancia recorrida + corrección del Trip
lcd.setCursor(7,1);
lcd.print(headingDegrees);
do{
if (Value4 != HIGH) {
Serial.println("Value 4 HIGH");
}
if (Value0 == LOW && Value1 == HIGH && Value2 == HIGH){ //Aumentamos el offset del Trip en 0,01 Km
delay(150);
if (Value0 == LOW){
offset = offset + 0.01;
TripMoto = km + offset;
}
}
if (Value0 == HIGH && Value1 == LOW && Value2 == HIGH){ //Se reduce el offset del Trip en 0,1 Km
delay(150);
if (Value1 == LOW){
offset = offset - 0.01;
TripMoto = km + offset;
if (TripMoto = 0 || TripMoto < 0){
TripMoto = 0;
km = 0;
metros = 0;
offset = 0;
ContadorRueda = 0;
}
}
}
if (Value0 == HIGH && Value1 == HIGH && Value2 == LOW && Value3 == HIGH && Value4 == HIGH && Value5 == HIGH){ //Se resetea a cero el valor del Trip
delay(150);
if (Value2 == LOW){
ContadorRueda = 0;
TripMoto = 0;
metros = 0;
km = 0;
offset = 0;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Km:"); //--> Posicion 3
lcd.setCursor(0,1);
lcd.print("Rumbo:"); //--> Posicion 6
}
}
//if (Value0 == HIGH && Value1 == HIGH && Value2 == HIGH && Value3 == HIGH && Value4 == LOW && Value5 == HIGH){
// delay(150);
// if (Value4 == LOW){
// menu = 4;
// //updateMenu();
// executeAction();
// }
//}
if (Value0 == HIGH && Value1 == HIGH && Value2 == HIGH && Value3 == HIGH && Value4 == HIGH && Value5 == LOW){
delay(150);
if (Value5 == LOW){
eepromTrip();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Guardando...");
delay(1500);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Km:"); //--> Posicion 3
lcd.setCursor(0,1);
lcd.print("Rumbo:"); //--> Posicion 6
}
}
//if (SensorRueda == LOW && SensorLastState == HIGH){
// delay(100);
// if (SensorRueda == LOW){
// SensorLastState = LOW;
// TripWheel();
// }
//}
TripWheel();
ReadCompas();
TripMoto = km + offset;
lcd.setCursor(7,0);
lcd.print(TripMoto,2); // Distancia recorrida + corrección del Trip
lcd.setCursor(7,1);
lcd.print(headingDegrees);
//lcd.setCursor(12,0); // Solo para depurar/verificar
//lcd.print(metros,1); // Solo para depurar/verificar
//lcd.setCursor(12,1); // Solo para depurar/verificar
//lcd.print(ContadorRueda); // Solo para depurar/verificar
//lcd.setCursor(5,1);
//lcd.print(km,1); //Distancia medida por la rueda sin correccion del trip
//lcd.setCursor(10,1);
//lcd.print(offset);
ReadEntries();
}while(Value4 != LOW);
menu = 0;
//executeAction(); //|*******
updateMenu();
//Guardar en EEPROM
//lcd.clear();
//lcd.setCursor(0,0);
//lcd.print("Volviendo a Menu");
//delay(1500);
}
void action2() { //Función de calibración del compás
delay(300);
ReadEntries();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Rumbo:"); //-->6
lcd.setCursor(0,1);
lcd.print("Declinacion:"); //-->12
do{
if (Value0 == LOW && Value2 == HIGH){
delay(150);
if (Value0 == LOW){
offset_declinationAngle = offset_declinationAngle + 0.01;
}
}
if (Value1 == LOW && Value2 == HIGH){
delay(150);
if (Value1 == LOW){
offset_declinationAngle = offset_declinationAngle - 0.01;
}
}
delay(150);
ReadCompas();
lcd.setCursor(6,0);
lcd.print(headingDegrees);
lcd.setCursor(12,1);
lcd.print(declinationAngle);
ReadEntries();
}while(Value2 == HIGH);
eepromDec();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Guardando...");
delay(1500);
}
void action3() { //Función de calibración del diametro de la rueda
delay(300);
ReadEntries();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Diam. Rueda:");
do{
if (Value0 == LOW && Value2 == HIGH){
delay(150);
if (Value0 == LOW){
diametro = diametro + 0.01;
}
}
if (Value1 == LOW && Value2 == HIGH){
delay(150);
if (Value1 == LOW){
diametro = diametro - 0.01;
}
}
delay(150);
lcd.setCursor(12,0);
lcd.print(diametro);
ReadEntries();
}while(Value2 == HIGH);
eepromdia();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Guardando...");
delay(1500);
}
void action4() { //Función de ajuste del Trip (en km) //|******
delay(300);
ReadEntries();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Trip (km):");
lcd.setCursor(0,1);
lcd.print(TripMoto);
do{
if (Value0 == LOW && Value2 == HIGH){
delay(150);
if (Value0 == LOW){
km = km + 1;
TripMoto = km + offset;
//TripMoto = TripMoto + 1;
}
}
if (Value1 == LOW && Value2 == HIGH){
delay(150);
if (Value1 == LOW){
km = km - 1;
TripMoto = km + offset;
TripMoto = TripMoto - 1;
if (TripMoto < 0){
TripMoto = 0;
km = 0;
offset = 0;
ContadorRueda = 0;
}
}
}
delay(150);
lcd.setCursor(0,1);
lcd.print(TripMoto);
ReadEntries();
//offset = 0;
//km = TripMoto;
//metros = km * 1000;
//ContadorRueda = diametro * metros;
}while(Value2 == HIGH);
eepromTrip();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Guardando...");
delay(1500);
}
//---------------------------------------------------------------------------------------------------------------------------