OBjetivos

 

  • Aprovechar nuestro circuito Zero Crossing detection AC.
  • Usar la regularidad de la frecuencia de red para diseñar un reloj.
  • Mostrar el resultado en un display I2C de 16×02..
  •  

    Material requerido.

     

    Vista principal Arduino Nano, aunque un Arduino UNO o equivalente, también sirve
    Opto acoplador Un opto acoplador integrado H11AA1 o H11AA2.
     R 33 Kohm Un par de resistencias de 33kΩ
    Img_3_4 Img_3_6 Una Protoboard más cables.

     LCD 16x02
    Un Display LCD 16×2

     

    Una idea sobre un reloj

     

    En la sesión anterior dejamos en el aire la posibilidad de usar la estabilidad de la frecuencia alterna que nos suministran las eléctricas, para diseñar un reloj de precisión basándonos en le numero de pulsos que recibimos por segundo.

    Como nadie ha recogido el testigo, no he podido resistirme a hacerlo. Hace mucho años, este fue uno de mis primeros proyectos que diseñé para coger confianza (Porque acaban de darme un titulo y no estaba muy seguro de si servia o no para algo)

    El circuito no tiene mayor dificultad, es de nuevo el circuito de zero crossing detection que vimos anteriormente, y bastará con jugar con el software y un display para poder usar los 50 Hz como base de tiempos, ya que son 100 pulsos por segundo, o sea de una centésima precisamente cada uno.

    • No nos olvidamos de los amigos del otro lado del charco que tienen a 60 HZ la corriente, lo tendremos en cuanta para que el reloj funcione a ambos lados del Atlántico. 

    Así que me ha parecido que para algunos de nuestros pacientes lectores, podría ser de interés volver sobre el tema de los cálculos de horas y de segundos a horas y minutos, porque como no me harto de insistir, el manejo de horas y fechas es clave en muchos de los proyectos que nos planteamos, y siempre es mejor trabajarlo con ejemplos sencillos que muestran la idea básica, que con grandes proyectos mucho mas difíciles de seguir.

    Así pues, poneros cómodos, que vamos a montar ese dichoso reloj a base de nuestro ya conocido opto acoplador  H11AA1, y de un display I2C que siempre es resultón para escribir lo queráis.
     

    Esquema del protoboard

     

    La idea básica consiste en usar el mismo circuito Zero Cross Detection para corriente alterna que en la ultima sesión e incorporarle un display I2C de 16 caracteres por dos lineas y escribir el programa de cero para nuestro nuevo objetivo: Un reloj de precisión.

    Esquema de protoboard arduino

    Cuando conectemos nuestro H11AA1 a la corriente AC, nuestro Arduino detectará el Zero Crossing y podemos usar ese número de pulsos por segundo para sincronizar un reloj con precisión de centésimas a 50 Hz.
     

    Programa de control

     

    Para empezar vamos a necesitar varias librerías, para el manejo del display LCD y del I2C: Prog_89B_3

    #include <Wire.h>
    #include <LCD.h>
    #include <LiquidCrystal_I2C.h>

    Si tenemos un display normal, estará en la dirección 0x27 hexadecimal, y podemos instanciarlo de la forma habitual:

    #define I2C_ADDR    0x27
    LiquidCrystal_I2C             lcd(I2C_ADDR,2, 1, 0, 4, 5, 6, 7);

    En el setup, vamos a definir la interrupción que nos indica el cruce por cero de la tensión (100 veces por segundo)

    pinMode(2, INPUT_PULLUP);
    attachInterrupt(0, Zero_Cross, FALLING) ;

    Y ahora preparemos el LCD display:

           lcd.begin (16,2);    // Inicializar el display con 16 caraceres 2 lineas
           lcd.setBacklightPin(3,POSITIVE);
           lcd.setBacklight(HIGH);
    
           lcd.home ();        // go home
           lcd.print("Prometec.net");  // Escribimos la primera línea

    Vamos con la funcion call back asociada con la interrupción o ISR (Recordad Interrupt Service Routine)

    void Zero_Cross()
       {    contador++ ;   
            // if (contador % 120 == 0) // Si tu AC es a 120 Hz
            if (contador % 100 == 0)
                { ++Segundos ;
                  contador = 0 ;
                }
       }

    Recordad que tenemos que procurar mantener al mínimo las operaciones que realizamos en una ISR para prevenir complicaciones.

    En este caso siempre que entramos a la ISR incrementamos un contador para saber cuántos pulsos llevamos. Si el resto de contador con 100 es 0, significa que hay que incrementar el número de segundos transcurridos.

    O sea, incrementar el número de segundos cada 100 pulsos. Aquí no hacemos nada más. Salimos zumbando.

    • Si tu AC va a 60 Hz, necesitas contar 120 pulsos por cada segundo y bastará con que quites el comentario a la línea que calcula el resto respecto a 120 y comentes la de 100. 

    Para el loop lo que vamos a hacer es imprimir la hora en el display una vez por segundo, y para evitar molestos delays utilizamos un típico sistema de control de tiempo transcurrido.

    • Recordar que a medida que vuestra habilidad como programadores crece (Enormemente a estas alturas) iros olvidando de los delays, porque dan más problemas de los que arreglan y solo merecen la pena en programas muy simples.
    • Además, está la siempre presente cuestión de la elegancia, y la devoción incondicional de los colgados de vuestros amigos, que se desvanecerá fulminantemente si os empeñáis en seguir usando delays. 

    Siempre podéis usar algo así:

    void loop()
        {  if ( millis()-t >= 1000)
              { // Serial.print(contador) ;
                t = millis() ;
                Print_Time() ;
              }
        }

    Esta forma de comprobar si ha pasado un lapso definido de tiempo, evitará bloquear vuestro programa y seguir haciendo algo mientras no se cumpla el lapso prefijado. El programa solo entrara en el código interno una vez por segundo.

    A medida que los programas se van complicando, no es buena idea congelar el procesador cada tanto tiempo. Queremos que trabaje que para eso le pagamos.

    Y por último nos queda la función que imprima los valores de tiempo en el display:

    void Print_Time()
       {
          lcd.setCursor ( 0, 1 );        // go to the 2nd line
          unsigned long horas = Segundos / 3600 ;  // Tomamos la parte entera
          unsigned long minutos = ( Segundos % 3600 ) / 60 ;
          unsigned long secs  = Segundos % 60 ;
     
          lcd.print (horas) ;
          lcd.print (":");
          lcd.print (minutos) ;
          lcd.print (":");
          lcd.print (secs) ;
          lcd.print ("  ");
      }

    Lo único que merece la pena comentar esta en el cálculo de las horas y minutos a partir de los segundos que tenemos almacenados en Segundos. Veamos como calcular las horas.

    Hagamos un ejemplo. Tomemos una hora cualquiera como las 3 cuarto y 36 segundos que serían:

    Segundos = 3 * 3.600 + 15 * 60 + 36 = 11.736

    Hasta aquí bien, tenemos que Segundos tiene un valor de 11.736. ¿Cómo calculamos la hora? Fácil. Las horas son la parte entera de dividir Segundos entre 3.600 y despreciar el resto:

    Horas = Segundos / 3600  =  11.736 / 3600 = 3
    • Como Horas y Segundos son int, hacemos la división entera despreciando el resto

    ¿Y los segundos? Fácil de nuevo, son el resto de dividir por 60 los Segundos totales:

    Segs = Segundos % 60
    Segs = 11.736 % 60 = 36

    ¿Y los minutos, que hemos dejado para el final sospechosamente? Pues son un pelín más complicados pero nada que pueda arredraros.

    Si hacemos la división del número de segundos entre 3.600 tendremos como resultado el número de horas, como vimos arriba y el resto representa los segundos, incluyendo los minutos. Por eso si ahora tomamos la división entera de esto con respecto a 60, tendremos el número de minutos en el cociente y el de segundos en el resto. Traduciendo:

    (Segundos %  3.600) = Numero de segundos más minutos en segundos
    (Segundos %  3.600) / 60 = número de minutos (Tomamos solo la parte entera)

    Por alguna razón este tipo de conversiones suelen resultar muy complicadas de seguir para la mayor parte de la gente, así que no me hagáis caso. Sacad la calculadora y comprobad lo que os digo aquí.

    • Esto debería ser una costumbre. No hagáis caso de lo que dice nadie (Yo incluido, que me equivoco mucho). Probadlo por vosotros mismos y os sorprenderá la rapidez con la que avanzaréis. 

    Poco nos queda ya más que poner el reloj en hora. En mi caso son las 6:59:48 y por eso voy a inicializar el reloj a:

    unsigned long Segundos =  6*3600L + 59*60L + 48L ;

    Y ya no queda más que mostraros un mini video con el resultado:

     

    Resumen de la sesión

     

  • Hemos reutilizado nuestro circuito Zero Crossing detection basado en H11AA1.
  • Aprovechamos los pulsos de la corriente AC para usarlos como base de tiempos para un reloj preciso.
  • MOstramos el resultado en un display LCD 16×02.