/*Jaime J. Diaz T.
creado:
30-sep-2019
*/
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <SPI.h>
#include <SD.h>
/*
* Cambiar para archivos tipo "SECONDARY/LITHIUM/500ma/DISCHG_DATA/12345_nn.CSV"
* "SECONDARY/LITHIUM/500mA/DECO_CONX/12345_nn.CSV"
* "SECONDARY/LITHIUM/500mA/RESUME/12345_nn.TXT"
* "PRIMARY/CARBON_ZINC/1000mA/DISCHG_DATA/12345_nn.CSV"
* 123456789012345678901234567890123456789012345678901234
* >> path.reserve(54)
*/
#define pilaCarbon "PRIMARY/CARBON_ZINC"
#define pilaAlcalina "PRIMARY/ALCALINE"
#define pilaLitio "PRIMARY/LITHIUM"
#define pilaOtra "PRIMARY/OTHER"
#define bateriaNI_MH "SECONDARY/NI_MH"
#define bateriaLitio "SECONDARY/LITHIUM"
#define bateriaOtra "SECONDARY/OTHER"
#define mA50 "/50mA"
#define mA100 "/100mA"
#define mA500 "/500mA"
#define mA1000 "/1000mA"
#define mA2000 "/2000mA"
#define datos "/DISCHG_DATA"
#define datosLength 12
#define curvaConexion "/DECO_CONX"
#define curvaConexionLength 10
#define resumen "/RESUME"
#define resumenLength 7
#define center_x 128 //EEPROM.read(0) //posicion central x
#define center_y 128 //EEPROM.read(1) //posicion central y
#define jog 20 //EEPROM.read(2) //zona neutra joystick
//#define max_x EEPROM.read(3) //posicion a tope X
//#define min_x EEPROM.read(4) //posicion a tope x
//#define max_y EEPROM.read(5) //posicion a tope Y
//#define min_y EEPROM.read(6) //posicion a tope y
#define more EEPROM.read(7) //para 2da velocidad
#define less EEPROM.read(8) //para 2da velocidad
#define rightDir 'X' //EEPROM.read(9) //para orientacion joystick
#define upDir 'Y' //EEPROM.read(10) //para orientacion joystick
//LiquidCrystal lcd (1, 3, 4, 5, 6, 7); //lcd, nombre de variable: 1>RS;3>E;4>D4;5>D5;6>D6;7>d7.
LiquidCrystal_I2C lcd(0x27, 20, 4);
//boolean debug = false; //Para correr secciones de depuracion.
//Serial.begin(9600); //Depuracion por monitor serie.
word count; //Cuenta medidas en descarga entre medidas FEM.
//Cuenta scroll.
PROGMEM const byte pin_x = A3; //escobilla de potenciometro x en A3
PROGMEM const byte pin_y = A2; //escobilla de potenciometro y en A2
byte x; //para analogRead eje x, y manipulacion String path
byte y; //para analogRead eje y, y manipulacion String path
char dirUpDn = '0'; //transformacion a direccion U/D, u/d, 0
char dirLfRt = '0'; //transformacion a direccion R/L, r/l, 0
volatile boolean pushButton = false; //Estado del boton de inicio.
File dataFile; //A usar en save__OnSD
String path; //Para crear ruta de archivos.
byte fileNumber; //Para selecionar archivo
char numBateria[] = "00000"; //Numero de bateria (0 - 99999)
void setup() {
SD.begin(SS); //iniciamos SD, eliminar al integrar en otro programa
path.reserve(54); //Fijamos tamaño, cambiar segun directory y fileName# (+1).
EEPROM.get(12,numBateria); //Recuperamos ultimo usado.
pinMode(2, INPUT_PULLUP); //Resistencia interna conectada al pulsador.
//Interrupt 0 en pin 2
attachInterrupt(0, ifButtonPressed, FALLING); //Fijamos un interrupt al pulsador de joystick.
//lcd.begin(16,2); //LCD de 2 lineas, 16 caracteres
lcd.init(); // initialize the LCD dsplay
//
//______________Solicitamos selecion de bateria
//
lcd.clear(); //Borramos y ponemos al principio
lcd.print(F("Selecione Bateria y Archivo")); //Damos instrucciones
lcd.setCursor(0,1); //Segunda linea
lcd.print(F("Use el joystic, pulsando termina")); //Damos instrucciones
while(dirUpDn == '0' && dirLfRt == '0'){
while(dirUpDn == '0' && dirLfRt == '0' && count < 17){
count ++;
joystickInput(); //Probamos joystick
lcd.scrollDisplayLeft();
delay(250);
}
while(dirUpDn == '0' && dirLfRt == '0' && count > 0){
count --;
lcd.scrollDisplayRight();
joystickInput(); //Probamos joystick
delay(250);
}
}
//
//___________Ya se movio el joystick, comienza seleccion
//
pushButton == false; //descartamos pulsaciones anteriores del boton.
while (pushButton == false){ //mientras no se pulse el boton.
if (dirUpDn == '0'){ //si no se mueve el joystick
joystickInput(); //Probamos joystick
continue; //y volvemos hasta q se pulse el boton.
}
switch (dirUpDn){ //lectura joystick para el primer menu tipo bat.
case 'U': //arriba
fileNumber++; //aumenta
case 'u': //arriba
fileNumber++; //aumenta
case 'd': //abajo
fileNumber--; //disminuye
case 'D': //abajo
fileNumber--; //disminuye
}
fileNumber = fileNumber % 7;
fileNumber = fileNumber + 1; //limitar a las posibles
switch (fileNumber){
case 1:
lcd.clear();
lcd.print(F(">"));
lcd.print( pilaCarbon );
lcd.setCursor(1,1);
lcd.print( pilaAlcalina );
case 2:
lcd.clear();
lcd.print(F(">"));
lcd.print( pilaAlcalina );
lcd.setCursor(1,1);
lcd.print( pilaLitio );
case 3:
lcd.clear();
lcd.print(F(">"));
lcd.print( pilaLitio );
lcd.setCursor(1,1);
lcd.print( pilaOtra );
case 4:
lcd.clear();
lcd.print(F(">"));
lcd.print( pilaOtra );
lcd.setCursor(1,1);
lcd.print( bateriaNI_MH );
case 5:
lcd.clear();
lcd.print(F(">"));
lcd.print( bateriaNI_MH );
lcd.setCursor(1,1);
lcd.print( bateriaLitio );
case 6:
lcd.clear();
lcd.print(F(">"));
lcd.print( bateriaLitio );
lcd.setCursor(1,1);
lcd.print( bateriaOtra );
case 7:
lcd.clear();
lcd.print(F(">"));
lcd.print( bateriaOtra );
lcd.setCursor(1,1);
lcd.print( pilaCarbon );
}
if ( pushButton == true ){
pushButton = false;
lcd.setCursor(0,1);
lcd.print(F("VUELVA A PULSAR PARA CONFIRMAR"));
delay(500); //Esperamos medio segundo.
if ( pushButton == false ){
lcd.clear(); //Borramos y ponemos al principio
lcd.print(F("Selecione Bateria y Archivo")); //Si no se confirma boton.
}
}
if ( pushButton == true ){
lcd.clear(); //Borramos y ponemos al principio
lcd.print(F("Crea directorio")); //Indica actividad.
path = F("");
switch ( fileNumber ){
case 1:
path =+ pilaCarbon;
case 2:
path =+ pilaAlcalina;
case 3:
path =+ pilaLitio;
case 4:
path =+ pilaOtra;
case 5:
path =+ bateriaNI_MH;
case 6:
path =+ bateriaLitio;
case 7:
path =+ bateriaOtra;
}
}
joystickInput(); //Volvemos a probar joystick
}
//
//__________________Seleccion corriente de descarga
//
//
lcd.clear(); //Borramos y ponemos al principio
lcd.print(F("Selecione corriente de descarga")); //Damos instrucciones
lcd.setCursor(0,1); //Segunda linea
lcd.print(F("Use el joystic, pulsando termina")); //Damos instrucciones
while(dirUpDn == '0' && dirLfRt == '0'){
while(dirUpDn == '0' && dirLfRt == '0' && count < 17){
count ++;
joystickInput(); //Probamos joystick
lcd.scrollDisplayLeft();
delay(250);
}
while(dirUpDn == '0' && dirLfRt == '0' && count > 0){
count --;
lcd.scrollDisplayRight();
joystickInput(); //Probamos joystick
delay(250);
}
}
lcd.clear(); //Borramos
lcd.print(F(">")); //Indicamos actividad
pushButton == false; //descartamos pulsaciones anteriores del boton.
while (pushButton == false){ //mientras no se pulse el boton
if (dirUpDn == '0'){ //si no se mueve el joystick
joystickInput(); //Probamos joystick
continue; //y volvemos hasta q se pulse el boton.
}
switch (dirUpDn){ //lectura joystick para el primer menu tipo bat.
case 'U': //arriba
fileNumber++; //aumenta
case 'u': //arriba
fileNumber++; //aumenta
case 'd': //abajo
fileNumber--; //disminuye
case 'D': //abajo
fileNumber--; //disminuye
}
fileNumber = fileNumber % 5;
fileNumber = fileNumber + 1; //limitar a las posibles
switch (fileNumber){
case 1:
lcd.clear();
lcd.print(F(">"));
lcd.print( mA50 );
lcd.setCursor(1,1);
lcd.print( mA100 );
case 2:
lcd.clear();
lcd.print(F(">"));
lcd.print( mA100 );
lcd.setCursor(1,1);
lcd.print( mA500 );
case 3:
lcd.clear();
lcd.print(F(">"));
lcd.print( mA500 );
lcd.setCursor(1,1);
lcd.print( mA1000 );
case 4:
lcd.clear();
lcd.print(F(">"));
lcd.print( mA1000 );
lcd.setCursor(1,1);
lcd.print( mA2000 );
case 5:
lcd.clear();
lcd.print(F(">"));
lcd.print( mA2000 );
lcd.setCursor(1,1);
lcd.print( mA50 );
}
if ( pushButton == true ){
pushButton = false;
lcd.setCursor(0,1);
lcd.print(F("VUELVA A PULSAR PARA CONFIRMAR"));
delay(500);
if ( pushButton == false ){
lcd.clear(); //Borramos y ponemos al principio
lcd.print(F(">")); //Si no se confirma boton.
}
}
if ( pushButton == true ){
lcd.clear(); //Borramos y ponemos al principio
lcd.print(F("Crea directorio")); //Indica actividad.
switch ( fileNumber ){
case 1:
path =+ mA50;
case 2:
path =+ mA100;
case 3:
path =+ mA500;
case 4:
path =+ mA1000;
case 5:
path =+ mA2000;
}
}
joystickInput();
}
path =+ datos;
if (!SD.exists(path)) { //Si aun no hay el directorio.
if (!SD.mkdir(path)) { //Crear directorio.
SDerror(); //Si falla, rutina de error.
}
}
path.remove(path.length() - datosLength);
path =+ curvaConexion;
if (!SD.exists(path)) { //Si aun no hay el directorio.
if (!SD.mkdir(path)) { //Crear directorio.
SDerror(); //Si falla, rutina de error.
}
}
path.remove(path.length() - curvaConexionLength);
path =+ resumen;
if (!SD.exists(path)) { //Si aun no hay el directorio.
if (!SD.mkdir(path)) { //Crear directorio.
SDerror(); //Si falla, rutina de error.
}
}
//path.remove(path.length() - resumenLength); //?? Mejor dejar para buscar
// // numero secuencial de archivo.
//
//
//________Selector de numero de bateria_____________________________
//
/* debe añadir a path "/12345"
*
* aqui fileNumber apunta a unidades, decenas,....; cambia con dirLfRt
* y numBateria es el numero de bateria; cambia con dirUpDn segun fileNumber.
*
* tal vez mejor guardar en EEPROM 12345 y nn para usarlo en openFile
* ya que son tres directorios [x]HECHO
*
*/
lcd.clear();
lcd.print(F("Numero Bateria:")); //Damos instrucciones.
lcd.setCursor(1,1); //Segunda posicion (dejamos un espacio), segunda linea.
lcd.print(numBateria); //
fileNumber = 5; //Cursor en unidades.
lcd.setCursor(fileNumber,1); //(fileNumber aqui es puntero del cursor)
lcd.cursor(); //Encendemos cursor.
joystickInput();
pushButton == false; //descartamos pulsaciones anteriores del boton.
while (pushButton == false){ //mientras no se pulse el boton
if (dirUpDn == '0' && dirLfRt == '0'){ //si no se mueve el joystick
joystickInput(); //Probamos joystick otra vez
continue; //y volvemos hasta q se pulse el boton.
}
switch (dirLfRt){ //lectura joystick.
case 'L': //izda
fileNumber --; //disminuye
case 'l': //izda
fileNumber --; //disminuye
case 'R': //dcha
fileNumber ++; //aumenta
case 'r': //dcha
fileNumber ++; //aumenta
//(lcd y char[] indice 0 a la izda)
}
fileNumber = fileNumber % 5; //limitar a las posibles
lcd.setCursor(fileNumber + 1 , 1); //mueve cursor
switch (dirUpDn){ //lectura joystick.
case 'U': //arriba
numBateria[fileNumber,fileNumber] = ( numBateria[fileNumber,fileNumber] + 1 ) %10; //aumenta
case 'u': //arriba
numBateria[fileNumber,fileNumber] = ( numBateria[fileNumber,fileNumber] + 1 ) %10; //aumenta
case 'd': //abajo
numBateria[fileNumber,fileNumber] = ( numBateria[fileNumber,fileNumber] - 1 ) %10; //disminuye
case 'D': //abajo
numBateria[fileNumber,fileNumber] = ( numBateria[fileNumber,fileNumber] - 1 ) %10; //disminuye
/* No se porque, pero creo que no hace lo que quiero >>> debug */
}
lcd.noCursor(); //Quitamos el cursor para que no baile
lcd.setCursor(1,1); //Segunda posicion, segunda linea.
lcd.print(numBateria); //Actualiamos valor.
lcd.setCursor(fileNumber + 1 , 1); //vuelve cursor a posicion seleccion.
lcd.cursor(); //enciende cursor.
/* DEBUG
* if (debug) {
* Serial.print(numBateria); //debug
* Serial.println(fileNumber); //debug
* }
*/
if ( pushButton == true ){
pushButton = false;
lcd.setCursor(0,1);
lcd.print(F("VUELVA A PULSAR PARA CONFIRMAR"));
delay(500);
}
if ( pushButton == false ){
lcd.clear(); //Borramos
lcd.print(F("Numero Bateria:")); //Damos instrucciones.
lcd.setCursor(1,1); //Segunda posicion, segunda linea.
lcd.print(numBateria); //Actualizamos valor.
lcd.setCursor(fileNumber + 1,1); //vuelve cursor a posicion seleccion.
lcd.cursor(); //enciende cursor.
}
joystickInput(); //Probamos joystick
}
lcd.clear(); //Borramos y ponemos al principio
lcd.print(F("Crea directorio")); //Indica actividad.
EEPROM.put(12,numBateria); //Guarda numero en EEPROM
path =+ F("/");
path =+ numBateria; //Sigue completando path.
//
//
//________Generador de numero secuencial de archivo_________________
/* en V0.1 es de la forma:
* SECONDARY/LITHIUM/L500_nnD.CSV
* en V0.2 cambia a:
* SECONDARY/LITHIUM/500mA/DISCHG_DATA/12345_nn.CSV
*/
fileNumber = 0;
path =+ F("_00.TXT"); //Añade "_nn.TXT"
x = path.indexOf('.'); //Busca el "."
for ( ; fileNumber <100; fileNumber ++){ //Prueba hasta 99
y = fileNumber / 10; //Decenas
path.setCharAt(x - 2, y);
y = fileNumber - y * 10; //Unidades
path.setCharAt(x - 1, y);
char pathName[path.length() + 1]; //Crea char del tamaño necesario.
path.toCharArray(pathName , path.length() + 1); //Pasa variable String a char.
if(! SD.exists(pathName)){ //Si no existe
EEPROM.update(11,fileNumber); //Guarda numero
break; //Deja de probar
}
}
path.remove(path.length() - ( resumenLength + 13));//Quita "/RESUME/12345_nn.TXT".
}
void loop() { //Aqui va el programa dischargeBatery
//[tal vez]
}
//____________________________________________________________________________________________
//
//_ifButtonPressed____________________________________________________________________________
//
void ifButtonPressed() {
noInterrupts(); //Atomic
detachInterrupt(0); //Desactiva interrupt en pin 2.
delayMicroseconds(50); //Debounce
if(digitalRead(2) == LOW){ //Si sigue pulsado
pushButton = true; //Marca pulsacion de boton de inicio.
}
interrupts(); //Reactiva interrupts
return;
}
//
//_joystickInput______________________________________________________________________________
//
void joystickInput(){
x = analogRead(pin_x) / 4; //Joystick x (0 - 255)
y = analogRead(pin_y) / 4; //Joystick y (0 - 255)
if(x >= (center_x - jog) && x <= (center_x + jog) && y >= (center_y - jog) && y <= (center_y + jog)){
dirUpDn = '0'; //Si no se movio joystick
dirLfRt = '0'; //indicarlo y volver
return;
}
//____________Si llegamos aqui, es que se movio el joystick, buscamos como se movio.
//Transformamos valores x e y de analogRaed() a 1,2,3,4 segun esten en la zona:
// min__less->1 || less__(center-jog)->2 || (center+jog)__more->3 || more__max->4.
xPosition();
yPosition();
//Transformamos a direccion arriba/abajo, izda/dcha
if( rightDir == 'X' ){
switch ( x ){
case 0 :
dirLfRt = '0';
break;
case 1 :
dirLfRt = 'L';
break;
case 4:
dirLfRt = 'R';
break;
case 2:
dirLfRt = 'l';
break;
case 3:
dirLfRt = 'r';
}
if( upDir == 'Y'){
switch ( y ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'D';
break;
case 4:
dirUpDn = 'U';
break;
case 2:
dirUpDn = 'd';
break;
case 3:
dirUpDn = 'u';
}
}
else if( upDir == 'y'){
switch ( y ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'U';
break;
case 4:
dirUpDn = 'D';
break;
case 2:
dirUpDn = 'u';
break;
case 3:
dirUpDn = 'd';
}
}
}
else if( rightDir == 'x' ){
switch ( x ){
case 0 :
dirLfRt = '0';
break;
case 1 :
dirLfRt = 'R';
break;
case 4:
dirLfRt = 'L';
break;
case 2:
dirLfRt = 'r';
break;
case 3:
dirLfRt = 'l';
}
if( upDir == 'Y'){
switch ( y ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'D';
break;
case 4:
dirUpDn = 'U';
break;
case 2:
dirUpDn = 'd';
break;
case 3:
dirUpDn = 'u';
}
}
else if( upDir == 'y'){
switch ( y ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'U';
break;
case 4:
dirUpDn = 'D';
break;
case 2:
dirUpDn = 'u';
break;
case 3:
dirUpDn = 'd';
}
}
}
else if( rightDir == 'Y' ){
switch ( y ){
case 0 :
dirLfRt = '0';
break;
case 1 :
dirLfRt = 'L';
break;
case 4:
dirLfRt = 'R';
break;
case 2:
dirLfRt = 'l';
break;
case 3:
dirLfRt = 'r';
}
if( upDir == 'X'){
switch ( x ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'D';
break;
case 4:
dirUpDn = 'U';
break;
case 2:
dirUpDn = 'd';
break;
case 3:
dirUpDn = 'u';
}
}
else if( upDir == 'y'){
switch ( x ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'U';
break;
case 4:
dirUpDn = 'D';
break;
case 2:
dirUpDn = 'u';
break;
case 3:
dirUpDn = 'd';
}
}
}
else if( rightDir == 'y' ){
switch ( y ){
case 0 :
dirLfRt = '0';
break;
case 1 :
dirLfRt = 'R';
break;
case 4:
dirLfRt = 'L';
break;
case 2:
dirLfRt = 'r';
break;
case 3:
dirLfRt = 'l';
}
if( upDir == 'X'){
switch ( x ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'D';
break;
case 4:
dirUpDn = 'U';
break;
case 2:
dirUpDn = 'd';
break;
case 3:
dirUpDn = 'u';
}
}
else if( upDir == 'x'){
switch ( x ){
case 0 :
dirUpDn = '0';
break;
case 1 :
dirUpDn = 'U';
break;
case 4:
dirUpDn = 'D';
break;
case 2:
dirUpDn = 'u';
break;
case 3:
dirUpDn = 'd';
}
}
}
return;
}
//
//_xPosition___________________________________________________________________________________
//
void xPosition(){
if(x > (center_x - jog) && x < (center_x - jog)){
x = 0; //centro
}
else if(x < less){
x = 1; //a tope minimo
}
else if(x > more){
x = 4; //a rope maximo
}
else if(x >= less && x < (center_x - jog)){
x = 2; //un poco menos
}
else{
x = 3; //un poco mas
}
}
//
//_yPosition___________________________________________________________________________________
//
void yPosition(){
if(y > (center_y - jog) && y < (center_y - jog)){
y = 0; //centro
}
else if(y < less){
y = 1; //a tope minimo
}
else if(y > more){
y = 4; //a tope maximo
}
else if(y >= less && y < (center_y - jog)){
y = 2; //un poco menos
}
else{
y = 3; //un poco mas
}
}
//
//
//_SDerror_______________________________________________________________________________
//
void SDerror (){
lcd.clear();
lcd.print(F("SD ERROR"));
while(true){
lcd.display();
delay(1000);
lcd.noDisplay();
delay(1000);
}
}
//
//
//_openFile______________________________________________________________________________
//
void openFile(byte fileNumber) {
/*DEUG
* if (debug) {
Serial.print(freeMemory()); //debug
}
if (debug) {
Serial.println(F(" ...open file...")); //debug
}
*/
if (fileNumber == 1) {
path += datos; //Nombre de archivo datos descarga.
}
if (fileNumber == 2) {
path += resumen; //Nombre de archivo resumen descarga.
}
if (fileNumber == 3) {
path += curvaConexion; //Nombre de archivo datos conex/dconex.
}
path += F("/");
path += EEPROM.get(12,numBateria); //Numero de bateria.
path += F("_");
path += EEPROM.read(11); //Numero secuencial de archivo.
if (fileNumber == 1) {
path += F(".CSV"); //Extension de archivo datos descarga.
}
if (fileNumber == 2) {
path += F(".TXT"); //Extension de archivo resumen descarga.
}
if (fileNumber == 3) {
path += F(".CSV"); //Extension de archivo datos conex/dconex.
}
char pathName[path.length() + 1]; //Crea char del tamaño necesario.
path.toCharArray(pathName , path.length() + 1); //Pasa variable String a char.
/* DEBUG
* if (debug) {
* Serial.print(path); //debug
* Serial.print(F(", ")); //debug
* Serial.print(pathName); //debug
* Serial.print(F(", ")); //debug
* Serial.println(path.length()); //debug
* }
*/
dataFile = SD.open(pathName , FILE_WRITE); //Abre archivo para guardar datos.
/* DEBUG
* if (debug) {
Serial.print(freeMemory()); //debug
}
if (debug) {
Serial.println(F("..file opened..")); //debug
}
*/
return;
}