//librairies #include // Ecran LCD sur le bus I2C #include // Horloge RTC #include #include // Driver du moteur pas à pas // Constantes const int ledPin[8] = {2, 3, 4, 5, 6, 7, 8, 9}; const String nom_phase[8] = {"NL", "PC", "PQ", "GC", "PL", "GD", "DQ", "DC"}; const int UpButtonPin = A1; const int DwButtonPin = A2; const int RsButtonPin = A3; const float REFLUNE = 9227.70903; // NOUVELLE LUNE date julienne : 13 janvier 2021 à 05h01m UT const int stepsPerRevolution = 32 * 64; // nombre de pas par revolution du moteur : 2048 // Variables globales int numero_phase = 0; // de 0 à 8 les 8 phases principales float JD; // date julienne calculée float k; // nombre décimal de lunaisons depuis la date de référence bool mode_auto = true; // mode automatique grâce à l'horloge RTC ou choix de la date char sdate[12]; // String formatée dans la procédure JJMMAAA(JD) pour convertir la date julienne en date grégorienne float Mposition = 0; // Position du moteur (il faut l'initialiser au départ) int long_press = 0; // permet de compter la durée sur le bouton OK/RESET bool goRAZ = true ; // booleen qui lance la procédure d'initialisation s'il est à valeur "true". // Objects LiquidCrystal_I2C lcd(0x27, 16, 2); // écran LCD sur le port I2C DS3231 clock; // I2C RTCDateTime dt; Stepper myStepper(stepsPerRevolution, 10, 11, 12, 13); // initialise la stepper library sur les pins 10 à 13 //############ INITIALISATION ########################### void setup() { Serial.begin(9600); // option : port série ordi pour débogage, permet de faire des Serial.print dans la console clock.begin(); // démarrer l'horloge //clock.setDateTime(2021, 01, 04, 10, 56, 00); // pour configurer (une fois) l'horloge à l'heure UT puis on commente cette ligne par la suite //clock.setDateTime(__DATE__, __TIME__); // ou alors : Send sketch compiling time to Arduino mais attention on est alors plus en heure UT lcd.init(); // initialise le lcd lcd.backlight(); // rétroéclairage de l'écran LCD lcd.clear(); // effacer l'écran des glitches au démarrage pinMode(UpButtonPin, INPUT_PULLUP); // bouton J+1 sur le pin A1 en pull-up : état bas quand on appuie pinMode(DwButtonPin, INPUT_PULLUP); // bouton J-1 sur le pin A2 en pull-up : état bas quand on appuie pinMode(RsButtonPin, INPUT_PULLUP); // bouton ok sur le pin A3 en pull-up : état bas quand on appuie for (int i = 0 ; i < 9; i++) { // définition des pin pour les 8 LED des phases sur les pin 2 à 9 pinMode(ledPin[i], OUTPUT); } myStepper.setSpeed(10); // défini la vitesse du moteur à 60 tour/mn: } //############ PROGRAMME PRINCIPAL ########################### void loop() { dt = clock.getDateTime(); // Quelle heure est-il? quel jour? donné par RTC // Calcul du jour julien à partir de ces données si on est en mode auto if (mode_auto) JD = Julien(dt.day, dt.month, dt.year, dt.hour, dt.minute); k = (JD - REFLUNE) / 29.53; // calcul de k en comptant le nombre de jours depuis ou avant la date de reférence while (k < 0) { // puis en divisant par une lunaison moyenne est de 29,53j. k = k + 1; // on ramene le résultat dans un intervalle [0,1] } // Bien sûr il y a plus simple mais c'était pour utiliser pédagogiquement un while while (k > 1) { k = k - 1; } numero_phase = round(k * 8) % 8; // on fait correspondre une phase principale dans l'intervalle [0,7] affiche_heure(); // gestion de l'affichage sur le LCD (date, heure, fraction de lunaison, phase... ) phase_led(); // allume une LED correspondant à la phase if (digitalRead(UpButtonPin) == LOW) { // bouton J+1 while (digitalRead(UpButtonPin) == LOW) {} // debounce : halt tant qu'il reste appuyé JD = int(JD) + 0.5; // se placer à midi. JD++; // incrément JD de 1j mode_auto = false; // mode auto désactivé : on fige la valeur de JD } if (digitalRead(DwButtonPin) == LOW) { // bouton J-1 while (digitalRead(DwButtonPin) == LOW) {} JD = int(JD) + 0.5; // se placer à midi. JD--; // désincrément JD de 1j mode_auto = false; } if (digitalRead(RsButtonPin) == LOW) { lcd.clear(); while (digitalRead(RsButtonPin) == LOW) { // tant que le bouton Ok/RESET est appuyé on incrémente long_press long_press++; lcd.setCursor(0, 0); lcd.print((long_press < 100) ? "RAZ : Non" : "RAZ : Oui"); goRAZ = (long_press > 100) ? true : false; } long_press = 0; mode_auto = true; // retour en mode auto } if (goRAZ) { // appel de la procédure RAZ si besoin RAZ(); goRAZ = false; } if (abs(k - Mposition) > .001) { // sur un changement de k, changer la position du moteur et enregistrer la nouvelle position int sens = ((k - Mposition) > 0) ? - 2048 : 2048; // évite de faire plus 1/2 tour par modulo 2048 myStepper.step(sens / 30); // optionnel : petit effet pour précéder un changement de position. delay (500); myStepper.step((abs(k - Mposition) < 0.5) ? (int)(sens * abs(k - Mposition)) - sens / 30 : (int)(sens * (abs(k - Mposition) - 1)) - sens / 30); Mposition = k; } } //############## AFFIHAGE SUR LE LCD ##################### void affiche_heure() { lcd.setCursor(0, 0); lcd.print(JJMMAAAA(JD)); // appel de la fonction JJMMAAAA pour convertir JD en string jj/mm/aaaa lcd.print(" "); if (mode_auto) { if (dt.hour < 10) lcd.print("0"); // on prévoit de mettre un 0 si le nombre est plus petit que 10 : ex 08 au lieu de 8 lcd.print(dt.hour); if (dt.second % 2 == 0) lcd.print(":"); else lcd.print(" "); // astuce pour faire clignoter les ":" sur les secondes paires if (dt.minute < 10) lcd.print("0"); // on prévoit de mettre un 0 si le nombre est plus petit que 10 : ex 08 au lieu de 8 lcd.print(dt.minute); } else lcd.print("midi "); lcd.setCursor(0, 1); lcd.print(JD, 2); // affiche le jour julien (modifié) avec 2 décimales lcd.print(" "); lcd.print(nom_phase[numero_phase]); // affiche le nom de la phase correspondant à numéro_phase dans la liste de noms de phase lcd.print(" "); if (k * 29.53 < 10) lcd.print(" "); lcd.print(k * 29.53, 1); // age de la lune en j avec 1 décimale lcd.print("j"); } //############## LED PHASES DE LA LUNE ##################### void phase_led() { // allume la Led qui correspond à la phase et éteint les autres for (int i = 0; i < 9; i++) { // pour chaque i on allume la LED i si elle correspond : sinon on l'éteint digitalWrite(ledPin[i], (numero_phase == i) ? HIGH : LOW); } } //############## INITIALISATION DU MOTEUR ##################### void RAZ() { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Remise A Zero "); lcd.setCursor(0, 1); lcd.print("avec +/- puis Ok"); while (digitalRead(RsButtonPin) == HIGH) { if (digitalRead(UpButtonPin) == LOW) myStepper.step(-1); if (digitalRead(DwButtonPin) == LOW) myStepper.step(1); } Mposition = 0; lcd.clear(); } //############## CALCUL DU JOUR JULIEN ######################## // fonction de conversion d'une date en jour julien décimal à partir de DD/MM/YYYY HH:MN // jour julien tronqué (-2450000) pour éviter les problèmes de chiffres significatifs des float (ou double) sur arduino float Julien (int DD, int MM, int YY, int HH, int MN) { float JJ = floor(365.25 * (((MM < 3) ? YY - 1 : YY) + 4716)) + floor(30.6001 * (((MM < 3) ? MM + 12 : MM) + 1)) + DD + 2 - floor(((MM < 3) ? YY - 1 : YY) / 100.0) + floor((floor(((MM < 3) ? YY - 1 : YY) / 100.0)) / 4.0) - 1524.5 - 2450000; JJ = JJ + (HH + MN / 60.0) / 24.0; return JJ; } //############## CONVERSION DU JOUR JULIEN en DATE JJ/MM/AAAA ### // fonction de conversion d'un jour julien en date JJ/MM/AAAA cf J.Meeus String JJMMAAAA (float jj) { float A, B, C, D, E, Z, M, F, alpha; int J, AA; Z = floor(jj + 0.5); F = jj - (int)(jj); // on garde la partie décimale hors du calcul if (Z + 2450000 < 2299161) { // pour en arriver là on remonte beaucoup en arrière !! A = Z + 2450000; } else { alpha = floor((Z + 2450000 - 1867216.25) / 36524.25); A = Z + 2450000 + 1 + alpha - floor(alpha / 4.0); } B = A + 1524; C = floor((B - 122.1) / 365.25); D = floor(365.25 * C); E = floor((B - D) / 30.6001); J = (int)(B - D - floor(30.6001 * E) + F ); // calcul du jour (entier) M = (E < 14) ? E - 1 : E - 13; // calcul du mois AA = (M > 2) ? C - 4716 : C - 4715 ; // calcul de l'année sprintf(sdate, "%02d/%02d/%04d", J, (int)M, (int)AA); return sdate; }