Ayuda para el primer gran reto de un dummy

Yo jugando con arduino llevo muy poco tiempo (y en C lo mismo mas 15 días, jejeje). No te puedo decir nada sobre resetearlo, ni idea de lo mal que le pueda llegar a sentar, esperemos si algún compañero nos puede ilustrar al respecto.

Sobe blink() ... nunca use la librería :* pero es cuestión de ensayo y error .. si no funciona, yo intentaría lo que mencionas de controlar el tiempo e ir alternando el valor con un espacio, no se cuantos milis, pero otra vez ensayo y error :grin:

El tema que mencionas del desborde de milis(), hay otras soluciones. cuando desborda arranca en 0 de nuevo ... y hasta hay puedo leer :zipper_mouth_face:

Hola rarito_forever Y Marcial.

Prueba con esta función que llama a la dirección de memoria 0 con lo que reinicializa el arduino, acuérdate de grabar las variables de alguna manera "EEPROM"

void(* resetFunc) (void) = 0;//función de reinicio 
void setup()
{
  Serial.begin(9600);
   Serial.println("EMPEZAMOS  " );delay(300);

 }

void loop()
{
  Serial.println(millis());
  if(millis() > 1000)
  {
   Serial.println("RESET RESET  RESET  " );delay(300);
resetFunc();  

}
 }

Espero que te sea de ayuda

saludos

Buenas pacoooh, desconocia que se pudiera hacer eso (la ignorancia provoca felicidad :grin:).
Yo me referia a controlar el valor de millis() y cuando sea muy bajito esta claro que acaba de desbordar, que te parece algo asi:

#include <LiquidCrystal.h>
 
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12);

unsigned long T_High=0;            // Milesimas de estado high
unsigned long T_Ciclo=30000;       // Milesimas del ciclo
unsigned long Milis_Ciclo=0;       // Para controlar el temporizador del ciclo
unsigned long Milis_High=0;        // Para controlar el temporizador de activo
unsigned long Ultimo_Milis=0;      // Para controlar el desborde millis()

// Los 2 botones
byte buttonPin = 2;
byte buttonPin_2 = 4;
byte Salida = 5;

// para button state change de cada boton
bool BtnSumar=false;
bool BtnDigito=false;
bool AntSumar=false;
bool AntDigito=false;

byte Digito=0;
byte Valores[4]={0,0,0,0};

void setup() 
{
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);  
  pinMode(buttonPin_2, INPUT); 
  pinMode(Salida, OUTPUT);
  digitalWrite(Salida, LOW); 
  
  lcd.begin(16, 2); 
  PintaTiempo();
  
}


void loop() 
{ 
  if (millis()<10)                      // millis() acaba de desbordar
  {
    Milis_Ciclo= Milis_Ciclo - Ultimo_Milis + millis();
    Milis_High = Milis_High - Ultimo_Milis + millis();
    delay(10-millis());
  }
  else
  {
    Ultimo_Milis=millis();
  }
  
  if (millis() > Milis_Ciclo)            // Final ciclo, cargamos nuevo tiempo y activamos salida
  {
    Milis_Ciclo = millis() + T_Ciclo;    
    Milis_High = millis() + T_High;
    digitalWrite(Salida, HIGH);                 
  }
  if (millis() > Milis_High)            // Final salida high, desactivar salida
  {
    digitalWrite(Salida, LOW);;
  }
   
  BtnSumar=digitalRead(buttonPin);
  if (BtnSumar && AntSumar != BtnSumar)    // Boton añadir valor cambia a activo
  {
    Serial.println("Pulsado boton aumentar valor");
    Valores[Digito]++;
    if (Valores[Digito]>9) {Valores[Digito]=0;}
    PintaTiempo();
  }
  AntSumar=BtnSumar;
    
  BtnDigito=digitalRead(buttonPin_2);
  if (BtnDigito && AntDigito != BtnDigito)    // Boton digito cambia a activo
  {
    Serial.println("Pulsado boton cambio digito");
    Digito++;                    // Pasamos a siguiente digito
    if (Digito>3) {Digito=0;}    // Del cuarto digito al primero
    T_High=Valores[0]*10 + Valores[1]*100 + Valores[2]*1000 + Valores[3]*10000;  // Almacenamos el nuevo tiempo
    if (T_High>T_Ciclo)          // Si el tiempo high es mayor que el del ciclo pasamos el tiempo a 0
    {
      Valores[0] = Valores[1] = Valores[2] = Valores[3] = 0;
      T_High=0;
    }
    PintaTiempo();
  }
  AntDigito=BtnDigito;
}
void PintaTiempo()
{
  lcd.setCursor(0,0);
  lcd.print(Valores[3]);
  lcd.setCursor(1,0);
  lcd.print(Valores[2]);
  lcd.setCursor(2,0);
  lcd.print(":");
  lcd.setCursor(3,0);
  lcd.print(Valores[1]);
  lcd.setCursor(4,0);
  lcd.print(Valores[0]);
  
  Serial.print(Valores[3]); 
  Serial.print(Valores[2]);
  Serial.print(":");
  Serial.print(Valores[1]);
  Serial.print(Valores[0]);
  Serial.print( "    --->   ");
  Serial.println(T_High); 
}

Hola Marcial, creo que te puede funcionar si la función PintaTiempo no dura mas de 10 ms
mira el tiempo que tarda en ejecutarse no vaya a ser que en el momento que desborda no compruebe millis()<10, o incrementa 10 ms para que no pase

....
   Valores[0] = Valores[1] = Valores[2] = Valores[3] = 0;
      T_High=0;
    }
   long timer=micros();
  PintaTiempo();
Serial.println(micros()-timer);
  }
 AntDigito=BtnDigito;
}....

mira también el tiempo total de loop

hace poco me encontré con este post para controlar el valor de millis() pero no me funciona con la ide 1.0.5 no se…

Hola,

Echo en falta una descripción algo más detallada de:

1.- Lo que quieres hacer.

2.- Qué tienes encima de la mesa (además del Arduino: pulsadores, Pantalla LCD, . . .)

Lo mejor es que expliques algo más detalladamente esto; después entramos en el problema concreto del software.

Saludos

Hola de nuevo, pues probando, probando....

encontré la manera de cambiar el valor de millis(), alterando el valor de una de las variables de la función prueba este código:

extern volatile unsigned long timer0_millis  ;

 void setup()
{
  Serial.begin(9600);
   Serial.println("EMPEZAMOS  " );delay(300);

  timer0_millis=10000;// cambiamos valor de millis


 }

void loop()
{
 Serial.println(millis());
  if(millis() > 18000) 
  {
 timer0_millis=0;
  }
  


  
 }

esta variable se encuentra en el archivo wiring.c http://github.com/arduino/Arduino/blob/master/hardware/arduino/cores/arduino/wiring.c desconozco si puede alterar el funcionamiento de arduino con tanto cambio

saludos

:fearful:

Estas hecho un fenomeno

Hola. Perdón por terciar en vuestra conversación, pero creo que no sería muy complicado medir los millis transcurridos incluso con desbordamiento de por medio.
Lo primero que hay que tener en cuenta es que el desbordamiento se produce cada casi 50 días, y en muchas aplicaciones el arduino no va a estar encendido tanto tiempo.
Si, pese a todo, queremos controlar la medida de un intervalo de tiempo incluso en el momento del desbordamiento, creo que mejor que resetear el timer cada dos por tres, es más efectivo (sobre todo si hubiera que controlar varios timers independientes y simultáneos) detectar y corregir el desbordamiento. Para detectar el desbordamiento, en lugar de controlar si es muy bajito (lo de los 10 milisegundos que proponía Marcial) es tan sencillo como controlar sencillamente si es menor que la última medida. Algo así:

// para establecer el punto en el que se cumple el timer
milisinicio=millis();
milisiguiente=milisinicio + milisamedir;

// para comprobar si se ha alcanzado el timer
miliactual=millis();
if (milisiguiente < milisinicio) {// el cálculo del siguiente timer causa desbordamiento
    if (milisactual < milisinicio && milisactual >= milisiguiente); // cumplido timer desbordado
} else {
    if (milisactual >=milisiguiente); // cumplido timer normal sin desbordar
}

Otra opción es calcular en cada iteración el tiempo transcurrido:

transcurrido=millis()-millisanterior;

¿La fórmula daría resultado correcto incluso con desbordamiento de por medio?. No estoy seguro, pero intentando recordar un poco sobre complementos a dos y demás creo que sí.
Saludos.

Noter, como sueles hacer, has encontrado la solución ideal.

:slight_smile: :slight_smile: :slight_smile:
Supongo que como tú (que se te ve muy desenvuelto en programación), más sabe el diablo por viejo…
Mi primera experiencia comenzó con uno de estos allá por el año 1982 de nuestro señor.

Puñetero peek y poke ...

Sí. Yo también logré cuelgues muy chulos con los poke :cold_sweat: Del zx81 recuerdo el comando fast, que aceleraba la ejecución del programa a cambio de desconectar la pantalla hasta que volvías a modo slow. La gran innovación del spectrum, aparte del modo gráfico y los ocho colores era la desaparición de esos dos comandos pues trabajaba en fast y con pantalla de continuo :astonished:. Dios. Parezco el abuelo cebolleta con sus historias. :roll_eyes:

Los avances fueron increibles en esos tiempos. Hoy, un telefono tiene mas potencia que cualquiera de esos equipos.
Yo llegue a utilizar (poco tiempo) una calculadora programable, con un BASIC muy básico :stuck_out_tongue: y tarjetas perforadas como sistema de almacenamiento. Con 3 K de memoria casi hacias de todo.

Mas adelante con los primeros pc 8086 y 8088 eso si que era programar… Una vez , por una apuesta, llegue a hacer un virus (muy rudimentario) con instrucciones msdos 2.0, que colgaba el equipo hasta que lo formatearas de nueva. (muchos tubo que formatear el responsable del aula de informática, jajajaja)

Hola a todos otra vez. Me alegra ver que no soy el único con la duda del control del tiempo al pasar los 50 días y aún me alegra mas conocer la solución. Se ha puesto muy interesante el tema. Si alguien quiere aportar algo mas, bienvenido el y su aportación. Yo mientras voy tomando nota de todo. Vffgaston: te agradezco tu interés pero no te puedo dar más datos ni información simplemente porque no los hay. Como dije al principio no hay proyecto todavía, solo mil ideas inconexas, muchas dudas, ganas de aprender y un pequeño reto que va un poco mas allá de donde llegan los ejemplos del IDE. El tema del control del tiempo sin recurrir a un modulo RTC es una de las cosas que mas me daba que pensar, de las que menos claro veía. Cuando llegue el momento de que haya proyecto no dudare en facilitaros toda la información, seguro que os necesitare. Gracias.

OK. Seguiré el hilo.

En todo caso: creo que lo mejor para aprender es proponerse un objetivo concreto (por modestísimo que sea; por eso te preguntaba lo del cacharrerío, para imaginarme qué se podría hacer con ello).

Saludos

Hola otra vez.
Al final en mi caso ha sido antes el huevo que la gallina. En una cena con amigos y amigos de amigos he encontrado una persona que le sacara utilidad a lo que tenía entre manos. Así, al final si que hay proyecto. Él ya tiene una instalación que le da una señal de salida al cumplirse unas determinadas condiciones, y lo que quiere es doblar esa señal a una fija y otra con tiempo variable. Para hacerlo he puesto un 3er pulsador que emula el pulso de la señal para iniciar actividad. Le he puesto un pequeño delay para los rebotes, solo para asegurarme de que si falla algo no sea de aquí el problema, pero lo eliminare antes de darlo por acabado. He aprovechado el código que me ofreció Marcial, lo he entendido y alterado para adaptarlo a mis necesidades. He implementado código para leer y escribir en la eeprom para no perder el valor del tiempo que hay fijado tal y como se me había sugerido. Al final ha quedado un sketch que si bien seguramente no será muy académico si que es funcional al 100% y cumple con lo que esperaba de el. Lo que no he sido capaz es de aplicar la solución para el desbordamiento de Millis(), y eso que me lo habían dado “mascado”. De donde no hay no se puede sacar.
Estaría muy agradecido si alguien me dice como (o me lo hace) aplicar la solución por si acaso. Gracias.

#include <LiquidCrystal.h>
#include <EEPROM.h>
byte direccion = 0;

LiquidCrystal lcd(7, 8, 9, 10, 11 , 12);
unsigned long T_High=0;            // Milesimas de estado high
unsigned long T_Ciclo=30000;       // Milesimas del ciclo
unsigned long Milis_Ciclo=0;       // Para controlar el temporizador del ciclo
unsigned long Milis_High;        // Para controlar el temporizador de activo

// Los  botones
byte buttonPin = 2;
byte buttonPin_2 = 4;
byte buttonPin_3 = 6;
byte Salida = 5;
byte salida_2 = 13; 

// para button state change de cada boton
bool BtnSumar=false;
bool BtnDigito=false;
bool AntSumar=false;
bool AntDigito=false;
bool activo = false;
byte lastButtonState = 0;   
byte buttonState = 0;

long ultimo_reg = 0;
byte seg = 0;

byte pantalla_activa;
byte Digito=0;
byte Valores[4]={};





void setup() 
{
  pinMode(buttonPin, INPUT);  
  pinMode(buttonPin_2, INPUT); 
  pinMode(buttonPin_3, INPUT);
  pinMode(Salida, OUTPUT);
  pinMode(salida_2, OUTPUT);
  digitalWrite(Salida, LOW);
  digitalWrite(salida_2, LOW); 

  Valores[3] = EEPROM.read(direccion);
  if( Valores[0] >= 255 )
  {
    Valores[0] = Valores[1] = Valores[2] = Valores[3] = 0;
  }
  else
  {
    Valores[2] = EEPROM.read(direccion++);
    Valores[1] = EEPROM.read(direccion++);
    Valores[0] = EEPROM.read(direccion++);
    direccion=0;
    T_High=Valores[0]*10 + Valores[1]*100 + Valores[2]*1000 + Valores[3]*10000;
  }


  lcd.begin(16, 2); 
  pantalla_monitoreo();
}


void loop() 
{
  if (activo == true)
  {
    digitalWrite(salida_2, HIGH);
    if (millis() > Milis_Ciclo)            // Final ciclo, cargamos nuevo tiempo y activamos salida
    {
      Milis_Ciclo = millis() + T_Ciclo;    
      Milis_High = millis() + T_High;
      digitalWrite(Salida, HIGH);                 
    }
    if (millis() > Milis_High)            // Final salida high, desactivar salida
    {
      digitalWrite(Salida, LOW);
      ;
    }
  }
  else
  {
    digitalWrite(salida_2, LOW);
    digitalWrite(Salida, LOW);
  }

  // Boton para activar salidas
  buttonState = digitalRead(buttonPin_3);
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      if (activo == false) 
      {
        activo = true;
        if (pantalla_activa == 0)
        {
          lcd.clear(); 
          pantalla_monitoreo(); 
        }
      }
      else
      {
        activo = false;
        if (pantalla_activa == 0)
        {
          lcd.clear(); 
          pantalla_monitoreo(); 
        }
      }
    }
  }
  delay(250);
  lastButtonState = buttonState;

  //Boton aumentar valores digito
  BtnSumar=digitalRead(buttonPin);
  if (BtnSumar && AntSumar != BtnSumar)    // Boton añadir valor cambia a activo
  {
    switch (pantalla_activa)
    {
    case 0:
      lcd.clear();
      pantalla_pregunta();
      break;

    case 1:
      Digito=0;
      Valores[0] = Valores[1] = Valores[2] = Valores[3] = 0;
      lcd.clear();
      PintaTiempo();
      break;

    case 2:
      Valores[Digito]++;
      if (Valores[Digito]>9) {
        Valores[Digito]=0;
      }
      lcd.clear();
      PintaTiempo();
      break;
    }
  }
  AntSumar=BtnSumar;

  //Boton fijar valor
  BtnDigito=digitalRead(buttonPin_2);
  if (BtnDigito && AntDigito != BtnDigito)    // Boton digito cambia a activo
  {
    switch (pantalla_activa)
    {
    case 0:
      pantalla_monitoreo();
      break;

    case 1:
      lcd.clear();
      pantalla_monitoreo();
      break;

    case 2:
      Digito++; 
      if (Digito>3)  
      {  
        T_High=Valores[0]*10 + Valores[1]*100 + Valores[2]*1000 + Valores[3]*10000;// Almacenamos el nuevo tiempo
        EEPROM.write(direccion, Valores[3]);
        EEPROM.write(direccion++, Valores[2]);
        EEPROM.write(direccion++, Valores[1]);
        EEPROM.write(direccion++, Valores[0]);
        direccion = 0;
        if (T_High<T_Ciclo) 
        {
          lcd.clear();
          pantalla_monitoreo();
        }    // Del cuarto digito al primero
        else if (T_High>T_Ciclo)          // Si el tiempo high es mayor que el del ciclo pasamos el tiempo a 0
        {
          Digito=0;
          Valores[0] = Valores[1] = Valores[2] = Valores[3] = 0;
          T_High=0;
          PintaTiempo();
        }
        break;
      }

    }
  }
}


// Función pantalla principal
void pantalla_monitoreo()
{
  pantalla_activa = 0;
  lcd.setCursor(0,0); 
  lcd.write("SALIDAS ");
  if (activo == true)
  {
    lcd.setCursor(8,0); 
    lcd.write("ON");
  } 
  else
  {
    lcd.setCursor(8,0); 
    lcd.write("OFF");
  } 
  lcd.setCursor(0,1); 
  lcd.write("T ON S1 = ");
  lcd.setCursor(10,1); 
  lcd.print(Valores[3]);
  lcd.setCursor(11,1);
  lcd.print(Valores[2]);
  lcd.setCursor(12,1);
  lcd.print("'");
  lcd.setCursor(13,1);
  lcd.print(Valores[1]);
  lcd.setCursor(14,1);
  lcd.print(Valores[0]);
}

// Función pantalla pregunta
void pantalla_pregunta()
{ 
  pantalla_activa = 1;
  lcd.setCursor(0,0); 
  lcd.write("CAMBIAR TIEMPO?");
  lcd.setCursor(0,1); 
  lcd.write("1=VOLVER   2=0K");
}


// Función tiempo seleccionado      
void PintaTiempo()

{
  pantalla_activa = 2;
  lcd.setCursor(0,0);
  lcd.print(Valores[3]);
  lcd.setCursor(1,0);
  lcd.print(Valores[2]);
  lcd.setCursor(2,0);
  lcd.print(":");
  lcd.setCursor(3,0);
  lcd.print(Valores[1]);
  lcd.setCursor(4,0);
  lcd.print(Valores[0]);
}

Échale un ojo a ver que te parece:

void loop() 
{
   Anteriormilis=millis();   // Almacenamos millis() para controlar el desborde
   
   ...
  
  if (activo == true)
  {
    digitalWrite(salida_2, HIGH);
    if (millis() > Milis_Ciclo)            // Final ciclo, cargamos nuevo tiempo y activamos salida
    {
      Milis_Ciclo = millis() + T_Ciclo;    
      Milis_High = millis() + T_High;
      digitalWrite(Salida, HIGH);                 
    }
    if (millis() > Milis_High)            // Final salida high, desactivar salida
    {
      digitalWrite(Salida, LOW);
    }
   
    ...

    if (millis()<Anteriormilis)    // Si es millis es menor que el que hemos almacenado, es qaue ha desbordado y empezado de 0
    {
      Milis_Ciclo = (Anteriormilis - Milis_Ciclo) + millis(); // Nuevo valor para Milis_Ciclo : el timepo que le falta de consumir + millis()
      ...                                                     // Igual con todas las variables que sirvan para lo mismo 
    }
  }

PD: Se me olvidaba comentarte que la epron del arduino tiene una vida limitada, http://arduino.cc/es/Reference/EEPROMWrite

Esto si que es rapidez. Ya he integrado en el código la solución que me ofreces, de aquí a 50 días sabré si lo he hecho bien :astonished: (es broma, no lo dejare 50 días en marcha, si hay problemas ya me vendrán a buscar). No acabo de entender a que otras variables te refieres al decir lo de “Igual con todas las variables que sirvan para lo mismo”. Quieres decir con todas las variables que utilizan millis() para su calculo supongo. Lo de los ciclos de lectura y escritura ya lo sabía pero no creo que lleguen al límite con la utilidad que le darán, parece que sera una cosa bastante constante y repetitiva incluso en el factor tiempo. Lo que no acabo de tener claro es si seria buena practica el uso de un contador para que no sobrescriba siempre los datos en la misma dirección, o considerando (como entiendo que es) que el limite de ciclos es global y no por direcciones, dejarlo hacer siempre en el mismo sitio. ¿Cómo lo ves tú? Gracias otra vez por tu tiempo.

Sobre el tema de los tiempos, si me refería a que si utilizas varias variables para control de tiempo en sitios distintos, que las actualices todas juntas. Sobre la vida útil de la eepron, supongo que sera grabaciones ne la misma dirección, pues la vida útil estara limitada por problemas físicos. Sobre contar o no el numero de accesos ... si pero solo si es en números romanos para conseguir una buena precisión :P, o eso o ser lo suficientemente sensato como para ver si se trata de una acceso diario o un acceso cada 10 décimas de segundo, y tener controlado el tema para que de tiempo al menos a cobrar el trabajo antes de que casque , jajajaj

Ok. Gracias por las aclaraciones. Espero haber sido un alumno aplicado ,haber seguido bien las indicaciones y al final que todo esto se vea en el funcionamiento del artilugio. Y si no, como dije el otro día, ya me vendrán a buscar. Gracias por todo a todos y en especial a ti Marcial. Nos vemos