Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Reloj preciso con solo usar un Arduino

Componentes y suministros

Arduino Nano R3
Usé un Nano pero debería funcionar con cualquier Arduino
× 1
LCD alfanumérico, 16 x 2
Cualquier pantalla debería funcionar, utilicé esta https://www.amazon.co.uk/ gp / product / B00N8K2BYM / ref =ppx_yo_dt_b_asin_title_o02_s00? ie =UTF8 &psc =1
× 1
Interruptor táctil, accionado por la parte superior
× 3
Potenciómetro de ajuste, 10 kohm
Cualquier recortadora de 10k servirá
× 1
Cables de puente
× 1

Acerca de este proyecto

Comencé esto como un ejercicio académico, pero terminé con un reloj muy preciso. Después de funcionar durante 5 días, no había perdido ni ganado tiempo.

El principal problema de usar solo un Arduino es que la velocidad de su reloj interno no es 100% precisa. Por lo tanto, si solo confía en esto, la cuenta de los milisegundos transcurridos saldrá en un pequeño porcentaje y el reloj que está creando se perderá o ganará tiempo. Mi enfoque fue probar la precisión del Arduino que estaba usando y determinar cuántos milisegundos perdía o ganaba por hora. Todo lo que se necesitaba entonces era programar un ajuste de velocidad para sumar o deducir esta diferencia de los milisegundos registrados internamente cada hora.

Mi otra preocupación era si el reloj Arduino era constantemente inexacto, pero como se indicó, el reloj que programé ha mantenido una hora muy precisa durante 5 días, por lo que parece que la inexactitud es constante.

El segundo problema es que la función interna millis () se restablece cada 50 días aproximadamente y no se puede manipular el recuento de milisegundos. Por lo tanto, la respuesta fue reemplazar la interrupción millis () usando un contador que pudiera manipular y que contara los milisegundos desde la medianoche, reiniciando cada día eliminando cualquier restricción de tiempo de ejecución.

Evaluación de la inexactitud

Para evaluar la inexactitud, asumí que el reloj de mi computadora y, por lo tanto, los milis () en Processing eran precisos. Por lo tanto, creé un programa para Arduino para enviar el número de milisegundos transcurridos desde el apretón de manos a Processing una vez cada 2 segundos y un script para Processing para leer esto y compararlo con sus milisegundos transcurridos mostrando un resultado en tiempo real y la diferencia después de una hora. transcurrido. Esto dio la cantidad de milisegundos que se habían perdido o ganado en una hora y, por lo tanto, el valor a usar para el ajuste de velocidad en el programa de reloj.

El código para el programa Arduino y el script de procesamiento se proporcionan a continuación.

Si no tiene Procesamiento instalado, visite https://processing.org, donde puede descargarlo y obtener información al respecto.

El código del reloj

Las principales áreas de interés en el código del reloj son la configuración de la interrupción, cómo se usa y la forma en que se mantiene y manipula la fecha.

La interrupción

El siguiente código establecerá una interrupción que se activará cada milisegundo. Esto desvía la interrupción utilizada para mantener millis () por lo que millis () y delay () ya no funcionarán.

  // Configurar interrupción de tiempo - millis () se reinicia después de 50 días, por lo que // estamos usando nuestro propio contador de milisegundos que podemos restablecer // al final de cada día // Establecer el modo CTC Comparar interrupción de tiempo y disparo TCCR0A =(1 < 

Este es el código que se llamará cada segundo:

  // Esta interrupción se llama cuando se alcanza el tiempo de comparación // por lo tanto, se llamará una vez por milisegundo según la configuración del registro // OCR0A.ISR (TIMER0_COMPA_vect) {if (currentMode! =SET_TIME) currentTime ++; transcurrido ++;}  

currentTime y transcurrido son variables largas sin firmar. Tenga en cuenta que estos se califican como volátiles cuando se definen, ya que también estamos manipulando las variables en el código principal. Esto obliga al sistema a leer la variable cada vez que se utiliza y no a utilizar un valor almacenado en caché.

currentTime almacena la cantidad de milisegundos desde la medianoche y hay rutinas para convertir esto a HH:MM:SS y restablecerlo cuando establezca la hora.

Cuando han transcurrido 24 horas, el sistema deduce el número de milisegundos en un día de la hora y aumenta la fecha en 1 día. Por lo tanto, el reloj no se ve afectado por el valor máximo que puede almacenar la variable, a diferencia de millis ().

  // Si al final del día restablece la hora y aumenta la fecha if ((currentMode ==SHOW_TIME) &&(currentTime> millisecondsInADay)) {// Al día siguiente // Detiene las interrupciones mientras se restablece la hora noInterrupts (); currentTime - =milisegundosInADay; interrumpe (); currentDate ++; }  

Tenga en cuenta que deshabilitamos las interrupciones mientras manipulamos la variable currentTime, de lo contrario, la llamada de interrupción podría activarse en medio del cálculo para deducir milisegundos InADay corrompiendo el cálculo.

Después de que ha pasado cada hora, el sistema ajusta la cantidad de milisegundos transcurridos por el ajuste de velocidad que calculamos anteriormente, ajustando la hora actual para compensar el reloj interno rápido o lento.

  // Al final de cada hora ajusta el tiempo transcurrido para // la inexactitud en el reloj Arduino if (transcurrido> =milisegundosEnHora) {noInterrupts (); // Ajusta el tiempo para el reloj Arduino de funcionamiento lento / rápido currentTime + =speedCorrection; // Restablecer para contar la siguiente hora transcurrida =0; interrumpe (); }  

Almacenamiento y cálculo de fechas

La fecha se lleva a cabo como una fecha juliana, que es el número de días que han transcurrido desde el lunes 1 de enero de 4713 a. C. Se incluyen rutinas para calcular la fecha juliana y convertirla de nuevo al calendario gregoriano.

  float JulianDate (int iday, int imonth, int iyear) {// Calcula la fecha juliana (probada hasta el año 20.000) unsigned long d =iday; unsigned long m =imonth; unsigned long y =iyear; si (m <3) {m =m + 12; y =y - 1; } unsigned long t1 =(153 * m - 457) / 5; unsigned long t2 =365 * y + (y / 4) - (y / 100) + (y / 400); return 1721118.5 + d + t1 + t2;} void GregorianDate (float jd, int &iday, int &imonth, int &iyear) {// Nota 2100 es el próximo año bisiesto omitido - compensa los años bisiestos omitidos unsigned long f =jd + 68569.5; unsigned long e =(4.0 * f) / 146097; largo sin signo g =f - (146097 * e + 3) / 4; largo sin signo h =4000ul * (g + 1) / 1461001; largo sin signo t =g - (1461 * h / 4) + 31; unsigned long u =(80ul * t) / 2447; unsigned long v =u / 11; i año =100 * (e - 49) + h + v; mes =u + 2 - 12 * v; iday =t - 2447 * u / 80;}  

Los botones de ajuste

El botón Modo avanza el modo actual de Mostrar hora, a Establecer hora, Establecer año, Establecer fecha, Establecer ajuste de velocidad y volver a Mostrar hora. Cada uno de estos se explica por sí mismo y utiliza los otros 2 botones para ajustar la configuración actual.

Una vez que el reloj está funcionando, si está ganando o perdiendo tiempo, puede cambiar el ajuste de velocidad, accediendo al modo Establecer ajuste de velocidad y usando el botón arriba y abajo para aumentar o reducir esto en 5 segundos a la vez.

Código

  • Programa de reloj
  • Programa de temporizador Arduino
  • Procesando el script de prueba del temporizador
Programa de reloj Arduino
Reloj preciso con fecha solo usando y Arduino
 // Paul Brace - Feb 2021 // Reloj simple con fecha creado solo usando un Arduino - sin módulo RTC // El programa incorpora un ajuste de corrección de tiempo para compensar la // velocidad interna del reloj no es 100% exacto.// Una vez que se ha ajustado la velocidad correcta, el reloj es sorprendentemente preciso .// En mi prueba no perdió ni ganó tiempo durante un período de 5 días.// Muestra el tiempo en una pantalla LCD de 16x2 // Botones para configurar la hora // Botón de modo (patilla 2) alterna entre configurar la hora, configurar la fecha y ejecutar // Botón 1 (patilla 3) Incrementa los minutos y el mes y disminuye el ajuste de Año / velocidad // Botón 2 (patilla 4) Incrementa la hora y el día y aumenta Year./speed adj // Visualización de 24 horas // Incluye el controlador de la biblioteca para la visualización:#include  // LiquidCrystal lcd (RS, EN, D4, D5, D6, D7) LiquidCrystal lcd (12, 13 , 6, 7, 8, 9); // crear un objeto lcd y asignar los pines // Definir botones y conexiones de zumbador # definir MODE_BUTTON 2 # definir HOUR_BUTTON 3 // El mismo botón diferentes definiciones para # definir UP_BUTTON 3 // hacer el código más fácil de entender #define DAY_BUTTON 3 # definir MINUTE_BUTTON 4 // El mismo botón, diferentes definiciones para # definir DOWN_BUTTON 4 // hacer que el código sea más fácil de entender #define MONTH_BUTTON 4 // Configuración del modo actual # definir SHOW_TIME 1 // 1 =en ejecución - mostrar tiempo # definir SET_TIME 2 // 2 =tiempo establecido # definir SET_YEAR 3 // 3 =conjunto de año # definir SET_DATE 4 // 4 =conjunto de día / mes #define SET_SPEED_ADJ 5 // 5 =modificar la variable speedCorrectionint speedCorrection =3545; // Número de milisegundos que mi reloj Nano corre lento por hora // número negativo aquí si está corriendo rápido // cambie para que coincida con su Arduino // Variables volátiles cambiadas en una interrupción y // necesitamos forzar al sistema a leer el variable actual // cuando se usa fuera de la interrupción y no usa una versión en caché volátil sin firmar tiempo actual largo; // Duración en milisegundos desde midnightunsigned long lastTime =-1000; // lastTime que ShowTime fue llamado inicializado a -1000 por lo que muestra de inmediato volátil sin firmar largo transcurrido; // Temporizador utilizado para el retardo y el contador de horas largo sin firmar milisegundosInADay; // Milisegundos en 24 horas unsigned long millisecondsInHour; // Milisegundos en 1 horaint currentMode; // 1 =en ejecución - mostrar hora // 2 =tiempo establecido // 3 =año establecido // 4 =día / mes setfloat currentDate; // Julian datefloat lastDate =0.0; // última fecha en la que se llamó ShowDate en currentDay; int currentMonth; int currentYear; char * dayArray [] ={"Tue.", // Mostrará una advertencia del compilador pero funciona bien "Wed.", "Thur.", "Fri . "," Sáb. "," Dom. "," Lunes "}; void setup () {// Configurar interrupción de tiempo - millis () se transfiere después de 50 días, por lo que // estamos usando nuestro propio contador de milisegundos que podemos reiniciar al // final de cada día TCCR0A =(1 < millisecondsInADay)) {// Siguiente día // Detiene las interrupciones mientras se reinicia el tiempo noInterrupts (); currentTime - =milisegundosInADay; interrumpe (); currentDate ++; } // Al final de cada hora ajusta el tiempo transcurrido para // la inexactitud en el reloj Arduino if (transcurrido> =milisegundosEnHora) {noInterrupts (); // Ajusta el tiempo para el reloj Arduino de funcionamiento lento / rápido currentTime + =speedCorrection; // Restablecer para contar la siguiente hora transcurrida =0; interrumpe (); } // Compruebe si se ha pulsado algún botón CheckButtons (); // Mostrar pantalla basada en el cambio de modo actual (currentMode) {case SHOW_TIME:// Mostrar hora y fecha actuales ShowTime (currentTime); ShowDate (currentDate); descanso; case SET_TIME:// Pantalla de visualización para configurar la hora ShowTimeSet (currentTime); descanso; case SET_YEAR:// Pantalla de visualización para configurar el año ShowYearSet (currentDate); descanso; case SET_DATE:// Pantalla de visualización para configurar el día y el mes ShowDDMMSet (currentDate); descanso; case SET_SPEED_ADJ:// Pantalla de visualización para ajustar la corrección de velocidad ShowSpeedSet (); descanso; } Wait (150);} // Esta interrupción se llama cuando se alcanza el tiempo de comparación // por lo tanto, se llamará una vez por milisegundo según la configuración del registro // OCR0A.ISR (TIMER0_COMPA_vect) {if (currentMode! =SET_TIME ) currentTime ++; transcurrido ++;} float JulianDate (int iday, int imonth, int iyear) {// Calcula la fecha juliana (probada hasta el año 20.000) unsigned long d =iday; unsigned long m =imonth; unsigned long y =iyear; si (m <3) {m =m + 12; y =y - 1; } unsigned long t1 =(153 * m - 457) / 5; unsigned long t2 =365 * y + (y / 4) - (y / 100) + (y / 400); return 1721118.5 + d + t1 + t2;} void GregorianDate (float jd, int &iday, int &imonth, int &iyear) {// Nota 2100 es el próximo año bisiesto omitido - compensa los años bisiestos omitidos unsigned long f =jd + 68569.5; unsigned long e =(4.0 * f) / 146097; largo sin signo g =f - (146097 * e + 3) / 4; largo sin signo h =4000ul * (g + 1) / 1461001; largo sin signo t =g - (1461 * h / 4) + 31; unsigned long u =(80ul * t) / 2447; unsigned long v =u / 11; i año =100 * (e - 49) + h + v; mes =u + 2 - 12 * v; iday =t - 2447 * u / 80;} void SplitTime (unsigned long curr, unsigned long &ulHour, unsigned long &ulMin, unsigned long &ulSec) {// Calcular HH:MM:SS a partir del recuento de milisegundos ulSec =curr / 1000; ulMin =ulSec / 60; ulHour =ulMin / 60; ulMin - =ulHour * 60; ulSec =ulSec - ulMin * 60 - ulHour * 3600;} unsigned long SetTime (unsigned long ulHour, unsigned long ulMin, unsigned long ulSec) {// Establece el número de milisegundos desde la medianoche hasta el retorno de la hora actual (ulHour * 60 * 60 * 1000) + (ulMin * 60 * 1000) + (ulSec * 1000);} void Wait (unsigned long value) {// Crea nuestra propia función dealy // Hemos establecido nuestra propia interrupción en TCCR0A // por lo tanto millis () y delay () ya no funcionará unsigned long startTime =transcurrido; while ((transcurrido - tiempo de inicio)  12) {iMonth =1; } // Establece la fecha de almacenamiento basada en la configuración actual currentDate =JulianDate (iDay, iMonth, iYear); } if (digitalRead (DAY_BUTTON) ==LOW) {// Avanzar día int iDay; int iMonth; int iYear; GregorianDate (fecha actual, iDay, iMonth, iYear); iDay ++; si (iDay> 31) {iDay =1; } si (((iMonth ==4) || (iMonth ==6) || (iMonth ==9) || (iMonth ==11)) &&(iDay> 30)) {iDay =1; } if ((iMonth ==2) &&(iDay> 29)) {iDay =1; } if ((iMonth ==2) &&((iYear% 4)! =0) &&(iDay> 28)) {iDay =1; } // Establecer la fecha almacenada en función de la configuración actual // Si posteriormente se ajusta el mes para que el día no sea válido // entonces la pantalla avanzará a la siguiente fecha válida currentDate =JulianDate (iDay, iMonth, iYear); } descanso; case SET_SPEED_ADJ:// aumenta o disminuye la corrección en 5 milisegundos if (digitalRead (UP_BUTTON) ==LOW) {speedCorrection + =5; } if (digitalRead (DOWN_BUTTON) ==LOW) {speedCorrection - =5; } descanso; }}} String FormatNumber (int value) {// Para agregar un 0 a la izquierda si es necesario if (value <10) {return "0" + String (value); } else {return String (valor); }} void ShowTime (unsigned long value) {// Actualiza la pantalla una vez por segundo // o cuando pasa la medianoche if ((value> lastTime + 1000) || (value  
Programa de temporizador Arduino Arduino
Este programa envía el número de milisegundos transcurridos al puerto serie evertir 2 segundos.
 // Paul Brace Feb 2021 // Para usar con el script de procesamiento correspondiente // para comparar millis () de aquí a millis () en // Processing usando la computadora clockint inByte =0; unsigned long firstReading =100000; // millis () al leer por primera vez sentvoid setup () {Serial.begin (9600); // Enviar el byte de saludo a Processing sayHello ();} void loop () {// si se recibe un byte en el puerto serie // luego leerlo, descartarlo y enviar el // valor actual de millis () if (Serial. disponible ()> 0) {// obtener el byte entrante inByte =Serial.read (); // enviar el tiempo transcurrido desde el procesamiento de la primera lectura Serial.print (millis () - firstReading); Serial.print ('E'); // repetir cada 2 segundos de retraso (2000); }} void sayHello () {// Espere hasta que el puerto serie esté disponible // luego envíe el byte de saludo para iniciar el protocolo de enlace while (Serial.available () <=0) {Serial.print ('Z'); // Enviar Z al procesamiento para decir Hola delay (200); } firstReading =millis ();} 
Procesando el script de prueba del temporizador Procesando
Este es el script para Processing que leerá los milisegundos enviados desde Arduino y los comparará con los milisegundos transcurridos en el procesamiento.
 // Paul Brace Feb 2021 // Script para aceptar millis () de Arduino // y compararlo con milis interno () para // evaluar la inexactitud del reloj Arduino .// Se supone que el reloj de la computadora es preciso // -ve =Arduino está funcionando lento, así que ingrese como un ajuste + ve en el programa de reloj // + ve =Arduino es corriendo rápido, así que ingrese como un ajuste -ve para reducir la velocidad del reloj. // crea el puerto serial objectint [] serialBytesArray =new int [15]; // matriz para almacenar bytes entrantesint bytesCount =0; // número actual de bytes recibidos boolean init =false; // falso hasta que se complete el apretón de manos al recibir el carácter Zint fillColor =255; // definir el color de relleno inicial long mills =0; // última lectura recibida largo primero =0; // tiempo de los primeros molinos recibidos para que podamos calcular la diferencia en una hora ahora; // número de milis transcurridos desde que se recibieron los primeros milineslong firstReading =100000; // millis () en el procesamiento del primer mensaje recibido de Arduinolong DiffPerHour =0; // la diferencia después de que haya pasado la primera hora int inByte; // último byte readvoid setup () {// definir algunos parámetros de lienzo y dibujo size (500, 500); fondo (70); noStroke (); // imprime la lista de todos los dispositivos seriales para saber cuál configurar para Arduino // necesitará ejecutar el programa y editar si el puerto correcto no está configurado debajo de printArray (Serial.list ()); // instanta la Cadena de comunicación serial thePortName =Serial.list () [1]; theSerialPort =new Serial (this, thePortName, 9600);} void draw () {// Mostrar fondo de configuración de tiempo (70); llenar (fillColor); textSize (25); texto (hora () + ":" + minuto () + ":" + segundo (), 50, 50); // la última lectura millis enviada por el texto de Arduino ("Entrante transcurrido:" + mills, 50, 100); // el tiempo transcurrido desde que se leyó por primera vez en Processing text ("Local transcurrido:" + (ahora - primera lectura), 50, 150); // muestra el texto de la diferencia actual ("Diff:" + (mills - (ahora - firstReading)), 50, 200); // Verifica si ha pasado 1 hora y si la primera hora almacena la diferencia if (((ahora - firstReading)> =3600000) &&(DiffPerHour ==0)) {DiffPerHour =mills - (ahora - firstReading); } // Muestra la primera diferencia y la diferencia después de la primera hora text ("Diff after 1 hour:" + DiffPerHour, 50, 300);} void serialEvent (Serial myPort) {// lee un byte del puerto serial inByte =myPort.read (); if (init ==false) {// si aún no se ha establecido el protocolo de enlace, ver si el byte del protocolo de enlace if (inByte =='Z') {// si el byte leído es Z myPort.clear (); // borra el búfer del puerto serie init =true; // almacenamos el hecho de que tuvimos el primer saludo myPort.write ('Z'); // le dice al Arduino que envíe más if (first ==0) {first =millis (); }}} else {// si ya hubo el primer saludo // Agregue el último byte del puerto serial a la matriz if (inByte! =69) {// No marque el final del carácter del mensaje E if (bytesCount <14) {serialBytesArray [bytesCount] =inByte; bytesCount ++; }} if (inByte ==69) {// Fin del mensaje // almacenar el tiempo local transcurrido ahora =millis (); // calcula los millis () mills entrantes =0; for (int i =1; i <=bytesCount; i ++) {mills + =(serialBytesArray [i - 1] - 48) * pow (10, (bytesCount - i)); } // Digamos que estamos listos para aceptar el siguiente mensaje // si esta es la primera lectura, establezca la primera diferencia if (firstReading ==100000) {firstReading =now; } myPort.write ('Z'); // Restablecer bytesCount:bytesCount =0; }}} 

Esquemas


Proceso de manufactura

  1. Reloj de visión pov de Arduino
  2. Decodificador DTMF usando solo Arduino
  3. Hacer Monitor Ambilight usando Arduino
  4. Reloj de pared simple con Adafruit 1/4 60 Ring Neopixel
  5. Reloj de palabras simple (Arduino)
  6. Reloj Arduino con tiempos de oración islámicos
  7. Reloj maestro
  8. Voltímetro de bricolaje con Arduino y un teléfono inteligente
  9. Monitor de frecuencia cardíaca con IoT
  10. WebServerBlink usando Arduino Uno WiFi
  11. Reloj de matriz de 7 segmentos