Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Horloge précise en utilisant simplement un Arduino

Composants et fournitures

Arduino Nano R3
J'ai utilisé un Nano mais devrait fonctionner avec n'importe quel Arduino
× 1
LCD alphanumérique, 16 x 2
Tout affichage devrait fonctionner, j'ai utilisé celui-ci https://www.amazon.co.uk/ gp/product/B00N8K2BYM/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1
× 1
Commutateur tactile, actionné par le haut
× 3
Potentiomètre de coupe, 10 kohm
Toute tondeuse 10k fera l'affaire
× 1
Câbles de raccordement
× 1

À propos de ce projet

J'ai commencé cela comme un exercice académique, mais j'ai fini avec une horloge très précise. Après 5 jours de course, il n'avait ni perdu ni gagné de temps.

Le principal problème avec l'utilisation d'un seul Arduino est que sa vitesse d'horloge interne n'est pas précise à 100%. Par conséquent, si vous vous fiez uniquement à cela, le nombre de millisecondes écoulées sera légèrement dépassé et l'horloge que vous créez perdra ou gagnera du temps. Mon approche consistait à tester la précision de l'Arduino que j'utilisais et à déterminer combien de millisecondes il a perdu ou gagné par heure. Il suffisait alors de programmer un ajustement de vitesse pour ajouter ou déduire cette différence des millisecondes suivies en interne chaque heure.

Mon autre préoccupation était de savoir si l'horloge Arduino était systématiquement inexacte, mais comme indiqué, l'horloge que j'ai programmée a maintenu une heure très précise sur 5 jours, il semble donc que l'inexactitude est cohérente.

Le deuxième problème est que la fonction interne millis() se réinitialise tous les 50 jours environ et vous ne pouvez pas manipuler le nombre de millisecondes. Par conséquent, la réponse était de remplacer l'interruption millis () à l'aide d'un compteur que je pouvais manipuler et qui compterait les millisecondes à partir de minuit, réinitialisant chaque jour en supprimant toutes les restrictions de temps d'exécution.

Évaluation de l'inexactitude

Pour évaluer l'inexactitude, j'ai supposé que l'horloge de mon ordinateur, et donc les millis () dans Processing, étaient exactes. J'ai donc créé un programme pour que l'Arduino envoie le nombre de millisecondes écoulées depuis la prise de contact à Processing une fois toutes les 2 secondes et un script pour Processing pour le lire et le comparer à ses millisecondes écoulées affichant un résultat en temps réel et la différence après une heure avait écoulé. Cela donnait le nombre de millisecondes perdues ou gagnées en une heure et donc la valeur à utiliser pour le réglage de la vitesse dans le programme horloge.

Le code du programme Arduino et le script de traitement sont fournis ci-dessous.

Si vous n'avez pas installé Processing, visitez https://processing.org où vous pouvez le télécharger et en savoir plus.

Le code de l'horloge

Les principaux domaines d'intérêt du code d'horloge sont le réglage de l'interruption, son utilisation et la manière dont la date est conservée et manipulée.

L'interruption

Le code suivant définira une interruption qui se déclenchera toutes les millisecondes. Cela détourne l'interruption utilisée pour maintenir millis() donc millis() et delay() ne fonctionneront plus.

 // Configurer l'interruption de temps - millis () s'exécute après 50 jours, donc // nous utilisons notre propre compteur de millisecondes que nous pouvons réinitialiser à // la fin de chaque jour // Définir le mode CTC Comparer temps et interruption de déclenchement TCCR0A =(1 < 

Voici le code qui sera appelé toutes les secondes :

// Cette interruption est appelée lorsque le temps de comparaison a été atteint// sera donc appelée une fois par milliseconde en fonction du // réglage du registre OCR0A.ISR(TIMER0_COMPA_vect) { if (currentMode !=SET_TIME) CurrentTime++ ; écoulé++;}  

currentTime et elapsed sont des variables longues non signées. Notez que ceux-ci sont qualifiés de volatiles lorsqu'ils sont définis car nous manipulons également les variables dans le code principal. Cela oblige le système à lire la variable à chaque fois qu'elle est utilisée et à ne pas utiliser une valeur mise en cache.

currentTime stocke le nombre de millisecondes depuis minuit et il existe des routines pour le convertir en HH:MM:SS et le réinitialiser lorsque vous réglez l'heure.

Lorsque 24 heures se sont écoulées, le système déduit le nombre de millisecondes dans un jour de l'heure et augmente la date d'un jour. L'horloge n'est donc pas impactée par la valeur maximale que la variable peut stocker, contrairement à millis().

 // Si à la fin de la journée réinitialise l'heure et augmente la date if ((currentMode ==SHOW_TIME) &&(currentTime> millisecondsInADay)) { //Jour suivant // Arrête les interruptions pendant la réinitialisation noInterrupts(); currentTime -=millisecondesInADay; interruptions(); dateactuelle++ ; } 

Notez que nous désactivons les interruptions tout en manipulant la variable currentTime, sinon l'appel d'interruption pourrait être déclenché au milieu du calcul pour déduire les millisecondesInADay altérant le calcul.

Après chaque heure écoulée, le système ajuste le nombre de millisecondes écoulées par l'ajustement de vitesse que nous avons calculé plus tôt, ajustant l'heure actuelle pour compenser l'horloge interne rapide ou lente.

 // À la fin de chaque heure, ajustez le temps écoulé pour // l'inexactitude de l'horloge Arduino if (elapsed>=millisecondsInHour) { noInterrupts(); // Ajuster l'heure pour une horloge Arduino lente/rapide currentTime +=speedCorrection; // Remise à zéro pour compter la prochaine heure écoulée =0; interruptions(); } 

Stockage et calcul des dates

La date est considérée comme une date julienne, qui est le nombre de jours qui se sont écoulés depuis le lundi 1er janvier 4713 av. Des routines sont incluses pour calculer la date julienne et la reconvertir en calendrier grégorien.

float JulianDate(int iday, int imonth, int iyear) { // Calcule la date julian (testée jusqu'à l'an 20 000) unsigned long d =iday; m long non signé =imois ; long non signé y =ian ; si (m <3) { m =m + 12; y =y - 1 ; } long non signé t1 =(153 * m - 457) / 5 ; t2 long non signé =365 * y + (y / 4) - (y / 100) + (y / 400); return 1721118.5 + d + t1 + t2;}void GregorianDate(float jd, int &iday, int &imonth, int &iyear) { // Remarque 2100 est la prochaine année bissextile sautée - compense les années bissextiles sautées unsigned long f =jd + 68569.5; e long non signé =(4,0 * f) / 146097 ; long non signé g =f - (146097 * e + 3) / 4; long h non signé =4000ul * (g + 1) / 1461001; t long non signé =g - (1461 * h / 4) + 31; non signé long u =(80ul * t) / 2447; long non signé v =u / 11 ; iannée =100 * (e - 49) + h + v; imois =u + 2 - 12 * v; iday =t - 2447 * u / 80;} 

Les boutons de réglage

Le bouton Mode fait avancer le mode actuel de Afficher l'heure à Définir l'heure, Définir l'année, Définir la date, Définir le réglage de la vitesse et revenir à Afficher l'heure. Chacun d'eux est explicite et utilise les 2 autres boutons pour ajuster le réglage actuel.

Une fois que l'horloge fonctionne, si elle gagne ou perd du temps, vous pouvez modifier le réglage de la vitesse, en accédant au mode Réglage de la vitesse et en utilisant les boutons haut et bas pour augmenter ou réduire ce temps de 5 secondes à la fois.

Code

  • Programme d'horloge
  • Programme de minuterie Arduino
  • Traitement du script de test du minuteur
Programme d'horlogeArduino
Horloge précise avec date juste en utilisant et Arduino
// Paul Brace - février 2021// Horloge simple avec date créée juste en utilisant un Arduino - pas de module RTC// Le programme intègre un réglage de correction de l'heure pour compenser la vitesse d'horloge interne// n'étant pas précis à 100%.// Une fois le réglage de la vitesse correct, l'horloge est étonnamment précise.// Dans mon test, elle n'a perdu ni gagné de temps sur une période de 5 jours.// Affiche l'heure sur un écran LCD 16x2// Boutons pour régler l'heure// Le bouton Mode (broche 2) permet de régler l'heure, la date et l'exécution// Le bouton 1 (broche 3) Incrémente les minutes et le mois et diminue l'ajustement de l'année/de la vitesse// Le bouton 2 (broche 4) Incrémente l'heure et le jour et augmente Year./speed adj// Affichage 24 heures// Inclut le pilote de bibliothèque pour l'affichage :#include // LiquidCrystal lcd( RS, EN, D4,D5, D6, D7)LiquidCrystal lcd(12, 13 , 6, 7, 8, 9); // créer un objet lcd et affecter les broches // Définir les boutons et les connexions du buzzer#define MODE_BUTTON 2#define HOUR_BUTTON 3 // Même bouton différentes définitions pour #define UP_BUTTON 3 // rendre le code plus facile à comprendre #define DAY_BUTTON 3#define MINUTE_BUTTON 4 // Même bouton différentes définitions pour #define DOWN_BUTTON 4 // rendre le code plus facile à comprendre #define MONTH_BUTTON 4// Paramètres du mode actuel#define SHOW_TIME 1 // 1 =running - show time#define SET_TIME 2 // 2 =time set #define SET_YEAR 3 // 3 =année définie#define SET_DATE 4 // 4 =jour/mois défini #define SET_SPEED_ADJ 5 // 5 =modifier la variable speedCorrectionint speedCorrection =3545; // Nombre de millisecondes pendant lesquelles mon horloge Nano tourne lentement par heure // nombre négatif ici si elle fonctionne rapidement // changer pour correspondre à votre Arduino // Variables volatiles modifiées dans une interruption et nous devons forcer le système à lire le variable réelle// lorsqu'elle est utilisée en dehors de l'interruption et n'utilise pas une version en cache volatile non signée longue currentTime ; // Durée en millisecondes à partir de minuit unsigned long lastTime =-1000; // lastTime que ShowTime a été appelé initialisé à -1000 donc montre immédiatement volatile non signé longtemps écoulé ; // Minuterie utilisée pour le délai et le nombre d'heures non signés long millisecondsInADay; // Millisecondes en 24 heuresunsigned long millisecondsInHour; // Millisecondes en 1 heureint currentMode; // 1 =running - show time// 2 =time set// 3 =year set// 4 =day/month setfloat currentDate; // datefloat julienne lastDate =0.0; // dernière date à laquelle ShowDate a été appeléint currentDay;int currentMonth;int currentYear;char *dayArray[] ={ "Mar. ", // Affiche un avertissement du compilateur mais fonctionne correctement " Mer. ", " Jeu. ", " Vendredi . ", "Sat. ", "Sun. ", "Mon. " };void setup() { // Configurer l'interruption de temps - millis () se renouvelle après 50 jours donc // nous utilisons notre propre compteur de millisecondes qui on peut réinitialiser à // la fin de chaque journée TCCR0A =(1 < millisecondsInADay)) { //Suivant jour // Arrête les interruptions pendant la réinitialisation de l'heure noInterrupts(); currentTime -=millisecondesInADay; interruptions(); dateactuelle++ ; } // À la fin de chaque heure, ajustez le temps écoulé pour // l'inexactitude de l'horloge Arduino if (elapsed>=millisecondsInHour) { noInterrupts(); // Ajuster l'heure pour une horloge Arduino lente/rapide currentTime +=speedCorrection; // Remise à zéro pour compter la prochaine heure écoulée =0; interruptions(); } // Vérifie si des boutons ont été pressés CheckButtons(); // Afficher l'affichage basé sur le commutateur de mode actuel (currentMode) { case SHOW_TIME:// Afficher l'heure et la date actuelles ShowTime(currentTime); ShowDate(currentDate); Pause; case SET_TIME :// Écran d'affichage pour le réglage de l'heure ShowTimeSet(currentTime); Pause; case SET_YEAR :// Écran d'affichage pour le réglage de l'année ShowYearSet(currentDate); Pause; case SET_DATE :// Écran d'affichage pour le réglage du jour et du mois ShowDDMMSet(currentDate); Pause; case SET_SPEED_ADJ :// Écran d'affichage pour le réglage de la correction de vitesse ShowSpeedSet(); Pause; } Wait(150);}// Cette interruption est appelée lorsque le temps de comparaison a été atteint// sera donc appelée une fois par milliseconde en fonction du // réglage du registre OCR0A.ISR(TIMER0_COMPA_vect) { if (currentMode !=SET_TIME ) currentTime++; écoulé++;}float JulianDate(int iday, int imonth, int iyear) { // Calcule la date julian (testée jusqu'à l'an 20 000) unsigned long d =iday; m long non signé =imois ; long non signé y =ian ; si (m <3) { m =m + 12; y =y - 1 ; } long non signé t1 =(153 * m - 457) / 5 ; t2 long non signé =365 * y + (y / 4) - (y / 100) + (y / 400); return 1721118.5 + d + t1 + t2;}void GregorianDate(float jd, int &iday, int &imonth, int &iyear) { // Remarque 2100 est la prochaine année bissextile sautée - compense les années bissextiles sautées unsigned long f =jd + 68569.5; e long non signé =(4,0 * f) / 146097 ; long non signé g =f - (146097 * e + 3) / 4; long h non signé =4000ul * (g + 1) / 1461001; t long non signé =g - (1461 * h / 4) + 31; non signé long u =(80ul * t) / 2447; long non signé v =u / 11 ; iannée =100 * (e - 49) + h + v; imois =u + 2 - 12 * v; iday =t - 2447 * u / 80;}void SplitTime(non signé long curr, non signé long &ulHour, non signé long &ulMin, non signé long &ulSec) { // Calculer HH:MM:SS à partir du nombre de millisecondes ulSec =curr / 1000; ulMin =ulSec / 60 ; ulHeure =ulMin / 60 ; ulMin -=ulHeure * 60 ; ulSec =ulSec - ulMin * 60 - ulHour * 3600;}unsigned long SetTime(unsigned long ulHour, unsigned long ulMin, unsigned long ulSec) { // Définit le nombre de millisecondes entre minuit et l'heure actuelle return (ulHour * 60 * 60 * 1000) + (ulMin * 60 * 1000) + (ulSec * 1000);}void Wait(unsigned long value) { // Créer notre propre fonction de dealy // Nous avons défini notre propre interruption sur TCCR0A // d'où millis () et delay() ne fonctionnera plus long startTime =elapsed ; while ((elapsed - startTime)  12) { iMois =1; } // Définir la date stockée en fonction des paramètres actuels currentDate =JulianDate(iDay, iMonth, iYear); } if (digitalRead(DAY_BUTTON) ==LOW) { // Avancer le jour int iDay; int iMois; int iAnnée ; GregorianDate(currentDate, iDay, iMonth, iYear); iDay++ ; if (iDay> 31) { iDay =1; } if (((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; } // Définir la date stockée en fonction des paramètres actuels // Si par la suite ajustez le mois pour que le jour ne soit pas valide // alors l'affichage passera à la prochaine date valide currentDate =JulianDate(iDay, iMonth, iYear); } Pause; case SET_SPEED_ADJ:// augmente ou diminue la correction de 5 millisecondes if (digitalRead(UP_BUTTON) ==LOW) { speedCorrection +=5; } if (digitalRead(DOWN_BUTTON) ==LOW) { speedCorrection -=5; } Pause; } }}String FormatNumber(int value) { // Pour ajouter un 0 au début si nécessaire if (value <10) { return "0" + String(value); } else { return String(valeur); }}void ShowTime(valeur longue non signée) { // Mise à jour de l'affichage une fois par seconde // ou lors du dépassement de minuit if ((valeur> lastTime + 1000) || (valeur  
Programme de minuterie ArduinoArduino
Ce programme envoie le nombre de millisecondes écoulées au port série toutes les 2 secondes.
// Paul Brace février 2021// À utiliser avec le script de traitement correspondant// pour comparer millis() d'ici à millis() dans // Traitement en utilisant l'horloge de l'ordinateur inByte =0 ; firstReading long non signé =100000 ; // millis() lors de la première lecture de sentvoid setup() { Serial.begin(9600); // Envoie l'octet hello au traitement sayHello();}void loop() { // si un octet est reçu sur le port série // alors lisez-le et supprimez-le et envoyez la valeur // actuelle de millis() if (Serial. available()> 0){ // récupère l'octet entrant inByte =Serial.read(); // envoie le temps écoulé depuis le traitement de la première lecture Serial.print(millis() - firstReading); Serial.print('E'); // répéter toutes les 2 secondes delay(2000); }}void sayHello(){ // Attendez que le port série soit disponible // puis envoyez hello byte pour démarrer la négociation while (Serial.available() <=0){ Serial.print('Z'); // Envoie Z au traitement pour dire Hello delay(200); } firstReading =millis();}
Traitement du script de test du minuteurTraitement
Il s'agit du script de traitement qui lira les millisecondes envoyées par l'Arduino et les comparera aux millisecondes écoulées dans le traitement.
// Paul Brace février 2021 // Script pour accepter les millis () d'Arduino // et le comparer à millis () interne pour// évaluer l'inexactitude de l'horloge Arduino.// Suppose que l'horloge de l'ordinateur est précise// -ve =Arduino est lent alors entrez comme un ajustement +ve dans le programme d'horloge// +ve =Arduino est s'exécutant rapidement alors entrez comme un ajustement -ve pour ralentir l'horloge downimport processing.serial.*;Serial theSerialPort; // crée le port série objectint[] serialBytesArray =new int[15]; // tableau pour stocker les octets entrants bytesCount =0; // nombre actuel d'octets reçusboolean init =false; // false jusqu'à ce que la poignée de main soit terminée en recevant le caractère Zint fillColor =255; // définition de la couleur de remplissage initialelong mills =0; // dernière lecture reçuelong first =0; // heure des premiers moulins reçus afin que nous puissions calculer la différence sur une heure maintenant ; // nombre de millis écoulés depuis que les premiers millièmes ont été reçuslong firstReading =100000 ; // millis() dans le traitement du premier message reçu d'Arduinolong DiffPerHour =0; // la différence après que la première heure se soit écoulée int inByte; // dernier octet readvoid setup() { // définit des paramètres de canevas et de dessin size (500, 500); arrière-plan (70); noStroke(); // imprime la liste de tous les périphériques série afin que vous sachiez lequel définir pour l'Arduino // vous devrez exécuter le programme et le modifier si le port correct n'est pas défini sous printArray(Serial.list()); // instancie la chaîne de communication série thePortName =Serial.list ()[1] ; theSerialPort =new Serial(this, thePortName, 9600);}void draw() { // Affiche l'arrière-plan des paramètres d'heure (70); fill(fillColor); textSize (25); text(hour() + ":" + minute() + ":" + seconde(), 50, 50); // le dernier millis lu envoyé par le texte Arduino ("Incoming elapsed:" + mills, 50, 100); // le courant écoulé depuis la première lecture dans Processing text("Local elapsed:" + (now - firstReading), 50, 150); // affiche la différence actuelle text("Diff:" + (mills - (now - firstReading)), 50, 200); // Vérifiez si 1 heure s'est écoulée et si la première heure stocke la différence if (((now - firstReading)>=3600000) &&(DiffPerHour ==0)){ DiffPerHour =mills - (now - firstReading); } // Affiche la première différence et la différence après la première heure text("Diff after 1 hour:" + DiffPerHour, 50, 300);}void serialEvent(Serial myPort) { // lit un octet depuis le port série inByte =monPort.read(); if (init ==false) { // si pas encore de poignée de main l'octet voir si la poignée de main if (inByte =='Z') { // si l'octet lu est Z myPort.clear(); // efface le tampon du port série init =true; // stocke le fait que nous avons eu le premier hello myPort.write('Z'); // dit à l'Arduino d'en envoyer plus if (first ==0){ first =millis(); } } } else { // s'il y avait déjà eu le premier bonjour // Ajoute le dernier octet du port série au tableau if (inByte !=69) { // Ne vérifie pas la fin du caractère de message E if (bytesCount <14) { serialBytesArray[bytesCount] =inByte; Nombre d'octets++ ; } } if (inByte ==69) { // Fin du message // stocker le temps local écoulé maintenant =millis(); // calcule les millis () entrants mills =0; for (int i =1; i <=bytesCount; i++) { mills +=(serialBytesArray[i - 1] - 48) * pow(10, (bytesCount - i)); } // Dites que nous sommes prêts à accepter le message suivant // s'il s'agit de la première lecture, définissez la première différence if (firstReading ==100000) { firstReading =now; } monPort.write('Z'); // Réinitialiser bytesCount :bytesCount =0 ; } }}

Schémas


Processus de fabrication

  1. horloge de vision Arduino pov
  2. Décodeur DTMF utilisant uniquement Arduino
  3. Créer un moniteur Ambilight à l'aide d'Arduino
  4. Horloge murale simple utilisant Adafruit 1/4 60 Ring Neopixel
  5. Horloge de mots simple (Arduino)
  6. Horloge Arduino avec heures de prière islamique
  7. horloge maîtresse
  8. Voltmètre DIY utilisant Arduino et Smartphone
  9. Moniteur de fréquence cardiaque utilisant l'IoT