Go Down

Topic: Reloj Arduino sin RTC (Read 10132 times) previous topic - next topic

surbyte

#30
Jan 28, 2017, 04:11 pm Last Edit: Jan 28, 2017, 06:16 pm by surbyte
Aunque lo dicho por Alfaville ya es contundente, si quieres un debate mas profundo (está en inglés) al respecto, que a mi me interesó por cierto, lee esto Will analogread(6) be able to control ADC6?

EDITO: corregido el enlace

Alfaville

surbite ha aparecido el problema del "http duplicado" en el link y no se accede a él.

Saludos

Neros

Gracias, si ha sido interesante! Una cosa que me sorprendía cuando estuve investigando el por qué no me funcionaba el A6 y A7 era que el UNO (al cual intente pasar mi proyecto para comprobar si era un problema de mi NANO) tuviera menos pines analógicos que el NANO y con este post que me has linkeado he obtenido la respuesta. No funcionaba el enlace pero lo he buscado en google.


Aprovecho y os hago un pequeño update.


En cuanto a la precisión del reloj, se me desvía frente al casio medio segundo cada dos días, por lo que ya el casio no sirve de referencia al poder ser esa desviación culpa a partes iguales de la precisión de ambos relojes. Como ya os comenté, a ese nivel ya no me preocupa la precisión.

Los siguientes objetivos son:
-Incorporar una alarma.
-Optimizar el código e intentar aprender a utilizar las interrupciones de software.


La parte de la alarma ya la he hecho de forma chapucera:

He añadido dos nuevos pulsadores, un LED y un zumbador activo.
Al pulsar uno de los pulsadores nuevos se muestra en la pantalla la hora de la alarma y mientras se mantenga pulsado se puede configurar de la misma forma que antes se configuraba la hora.
Este pulsador también apaga la alarma cuando esta sonando.
El otro pulsador nuevo enciende el LED e indica que la alarma sonará la siguiente vez que llegue la hora. De esta forma puedo apagar la alarma cuando suena pero no tengo que volver a activarla para el día siguiente.

Se que es todo ahora mismo bastante ineficiente, pero bueno, espero mejorarlo con el tiempo.







Tengo muchas ideas también de qué mas funciones añadirle:

-alarmas diarias
-sensor de luz para atenuar la intensidad luminosa de los displays por la noche
-alguna forma creativa para apagar la alarma
-optimizar el uso de pulsadores para evitar usar tantos pines del arduino
-añadir display para fecha y dia de la semana
-utilizar "shift registers" (no me se el nombre en español, 74hc595) en vez de los 75hc4511 que estoy usando ahora
-puede que me pase eventualmente a display LCD

y la lista sigue...

La cuestión es que tengo muy poco tiempo para dedicarle a esto así que dejo el post abierto para subir los progresos y las dudas que me vayan surgiendo pero es probable que pase tiempo entre novedad y novedad.

Muchas gracias a todos, he aprendido un montón en lo que llevo hasta ahora y espero seguir haciendolo cuando los estudios me lo permitan.

Neros

Se me olvidaba el código (omito la declaración de variables):

Code: [Select]


//BUCLE
void loop() {

  //pulsadores

  for (int i = 0; i < 7; i++) { //almacenamiento de los datos del bucle anterior
    estado_pulsador_ant[i] = estado_pulsador[i];
  }

  for (int i = 0; i < 7; i++) { //lectura de los pulsadores
    estado_pulsador[i] = digitalRead(pulsadores[i]);
  }



  if (estado_pulsador[5] == 1) {
    if ((estado_pulsador[0] == 0) && (estado_pulsador[0] != estado_pulsador_ant[0])) {
      minutos++;
    }

    if ((estado_pulsador[1] == 0) && (estado_pulsador[1] != estado_pulsador_ant[1])) {
      minutos = minutos + 10;
    }

    if ((estado_pulsador[2] == 0) && (estado_pulsador[2] != estado_pulsador_ant[2])) {
      horas++;
    }

    if ((estado_pulsador[3] == 0) && (estado_pulsador[3] != estado_pulsador_ant[3])) {
      horas = horas + 10;
    }

    if ((estado_pulsador[4] == 0) && (estado_pulsador[4] != estado_pulsador_ant[4])) {
      contador = micros();
      segundos = 0;
      estado_punto = 0;
      //timer1=timer2;
    }

  } else {

    if ((estado_pulsador[0] == 0) && (estado_pulsador[0] != estado_pulsador_ant[0])) {
      al_min_unidades++;
    }

    if ((estado_pulsador[1] == 0) && (estado_pulsador[1] != estado_pulsador_ant[1])) {
      al_min_decenas++;
    }

    if ((estado_pulsador[2] == 0) && (estado_pulsador[2] != estado_pulsador_ant[2])) {
      al_hor_unidades++;
    }

    if ((estado_pulsador[3] == 0) && (estado_pulsador[3] != estado_pulsador_ant[3])) {
      al_hor_decenas++;
    }
  }

  if ((estado_pulsador[6] == 0) && (estado_pulsador[6] != estado_pulsador_ant[6])) {
    estado_led ^= 1;
    digitalWrite(led_al, estado_led);
  }


  //lógica de segundos minutos horas dias meses y año, utilizando contador para saber cuando ha pasado un segundo

  if ((micros() - contador) >= 1001401) { //hago que cada segundo sea un milisegundo más largo a ver si compenso el error
    contador += 1001401;
    segundos++;
    estado_punto ^= 1; //cambiar cada segundo el punto de ON a OFF
  }

  if (segundos > 59) {
    segundos = 0;
    minutos++;
  }
  if (minutos > 59) {
    minutos = 0;
    horas++;
  }
  if (horas > 23) {
    horas = 0;
    dia++;
  }

  if ((mes == 1) || (mes == 3) || (mes == 5) || (mes == 7) || (mes == 8) || (mes == 10) || (mes == 12)) {
    if (dia > 31) {
      dia = 1;
      mes++;
    }
  } else if (mes == 2) {
    if (dia > 28) {
      dia = 1;
      mes++;
    }
  } else {
    if (dia > 30) {
      dia = 1;
      mes++;
    }
  }

  if (mes > 12) {
    mes = 1;
    anno++;
  }

  //overflow de la alarma
   if((al_min_unidades)>9){
    al_min_unidades=0;
    al_min_decenas++;
  }
  if((al_min_unidades+al_min_decenas*10)>59){
    al_min_unidades=0;
    al_min_decenas=0;
    al_hor_unidades++;
  }
  if((al_hor_unidades)>9){
    al_hor_unidades=0;
    al_hor_decenas++;
  }
  if((al_hor_unidades+al_hor_decenas*10)>23){
    al_hor_unidades=0;
    al_hor_decenas=0;
  }




  //división en dígitos

  seg_decenas = int(segundos / 10);
  seg_unidades = segundos - seg_decenas * 10;

  min_decenas = int(minutos / 10);
  min_unidades = minutos - min_decenas * 10;

  hor_decenas = int(horas / 10);
  hor_unidades = horas - hor_decenas * 10;

  dia_decenas = int(dia / 10);
  dia_unidades = dia - dia_decenas * 10;

  mes_decenas = int(mes / 10);
  mes_unidades = mes - mes_decenas * 10;

  anno_miles = int(anno / 1000);
  anno_centenas = int((anno - anno_miles * 1000) / 100);
  anno_decenas = int((anno - anno_miles * 1000 - anno_centenas * 100) / 10);
  anno_unidades = anno - anno_miles * 1000 - anno_centenas * 100 - anno_decenas * 10;

  //sonido alarma

  if ((min_unidades == al_min_unidades) && (min_decenas == al_min_decenas) && (hor_unidades == al_hor_unidades) && (hor_decenas == al_hor_decenas)&&(estado_led==1)&&(al_on_off==1)){
    digitalWrite(alarma, estado_punto);
  }
  if ((estado_pulsador[5] == 0) && (estado_pulsador[5] != estado_pulsador_ant[6])) {
    al_on_off=0;
    digitalWrite(alarma,LOW);  
  }
  if((estado_led==1)&&((min_unidades==(al_min_unidades+1))||(min_unidades==(al_min_unidades-1)))){
    al_on_off=1;
  }



  //control de displays


  if (estado_pulsador[5] == 1) { //mostrar hora si no se pulsa nada

    //minutos
    digitalWrite(dec_hor, LOW);
    for (int i = 0; i < 4; i++) {
      if (((min_unidades >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(ud_min, HIGH);
    delay(2.5);



    digitalWrite(ud_min, LOW);
    for (int i = 0; i < 4; i++) {
      if (((min_decenas >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(dec_min, HIGH);
    delay(2.5);




    //horas
    digitalWrite(dec_min, LOW);
    digitalWrite(punto, estado_punto); //para que el punto intermedio se ilumine si le toca
    for (int i = 0; i < 4; i++) {
      if (((hor_unidades >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(ud_hor, HIGH);
    delay(2.5);


    digitalWrite(ud_hor, LOW);
    digitalWrite(punto, LOW); //para que no se iluminen los puntos de los otros digitos
    for (int i = 0; i < 4; i++) {
      if (((hor_decenas >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(dec_hor, HIGH);
    delay(2.5);






  } else { //mostrar hora de la alarma si se pulsa el pulsador de alarma





    //minutos
    digitalWrite(dec_hor, LOW);
    for (int i = 0; i < 4; i++) {
      if (((al_min_unidades >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(ud_min, HIGH);
    delay(2.5);



    digitalWrite(ud_min, LOW);
    for (int i = 0; i < 4; i++) {
      if (((al_min_decenas >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(dec_min, HIGH);
    delay(2.5);




    //horas
    digitalWrite(dec_min, LOW);
    digitalWrite(punto, estado_punto); //para que el punto intermedio se ilumine si le toca
    for (int i = 0; i < 4; i++) {
      if (((al_hor_unidades >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(ud_hor, HIGH);
    delay(2.5);


    digitalWrite(ud_hor, LOW);
    digitalWrite(punto, LOW); //para que no se iluminen los puntos de los otros digitos
    for (int i = 0; i < 4; i++) {
      if (((al_hor_decenas >> i) & 1) == 1) {
        digitalWrite(output[i], HIGH);
      } else {
        digitalWrite(output[i], LOW);
      }
    }
    digitalWrite(dec_hor, HIGH);
    delay(2.5);

  }


}

Anilandro

Perdonad que me entrometa en este tema, pero condicionantes del software aparte, lo más normal es que la mayor variación de tiempo corresponda a la temperatura. La frecuencia de resonancia de los materiales piezoeléctricos depende de sus dimensiones, y la dilatación con la temperatura afecta a estas y por tanto a la frecuencia. Unos materiales tienen más estabilidad que otros, pero resulta que en muchas placas de Arduino el "cristal" no es realmente de cuarzo, aunque por el encapsulado lo parezca, si no de material cerámico, mucho más barato, y tanto su precisión inicial como la variación por temperatura son bastante mediocres.

...La estabilidad de un oscilador cerámico, siendo alta, es un par de órdenes de magnitud inferior a la de un cuarzo, pero perdiendo algo de tiempo podría hacerse una tabla de "temperatura/error_en_tiempo" y teniendo en cuenta sus parámetros, corregir por software.

Por otra parte, es de prever que para variaciones pequeñas de temperatura (pequeñas con respecto a la escala Kelvin absoluta) el comportamiento sea bastante lineal, con lo cual bastaría insertar en la programación una sencilla fórmula correctiva, evitando la ocupación de memoria de un array, así como el cálculo de interpolación necesario entre valores.

Un saludo a todos 

surbyte

Pero para hacer lo que dices Anilandro, hace falta un sensor de temperatura, para saber donde se está parado.

Neros

Anilandro no es intromision, para eso esta el post! Muy interesante aporte, pero dada la poca variación de temperatura de mi habitación creo que es suficiente con corregir con una constante.

villamany

Hola, primeramente saludar a todos, acabo de registrarme en el foro.
No se si sera adecuado ponerlo por aquí pero creo que puede aportar algo al tema.

Estoy realizando mi primer proyecto desde cero con Arduino, concretamente es para Arduino UNO. Se trata de una incubadora que debe llevar entre otras cosas el control mas o menos preciso del tiempo transcurrido.

Ayer haciendo mis primeras pruebas observe que mi Arduino "se retrasa" aproximadamente unos 20 segundos cada hora!!...

Esto no cuadra mucho con la precision de un cuarzo por muy malo que sea. Observando la placa vi que el resonador de cuarzo es solo para el conversor USB mientras que el micro realmente usa un resonador cerámico con una precision bastante inferior. Pues bien, buscando opciones para sustituirlo por uno de cuarzo me he topado con unas fotos de unos clones que usan un cuarzo para el micro en vez del cerámico... y mirando en el cajon de los trastos resulta que tengo varios de ellos por aqui. La verdad es que pese a ser un clon me esta dando bastante mas precision y ha resuelto mi problema.

Pablo_Lucini

Por mi experiencia,  he realizado cronometros sin RTC con arduinos idénticos comprados conjuntamente ( misma partida ) y todos diferían un poco entre si ( un segundo cada 2 o tres horas ) estando todos juntos a la misma temperatura. Indudablemente si necesitás presición hay que usar un RTC.

Go Up