// // ######################### // # HORLOGE CAMILLE # // ######################### // # Guy Magli 31.08.2019 # // # 08.09.2019 # // ######################### // # Conception, cablages # // # mises a jour, # // # contact... # // # www.magli.fr # // ######################### // // Afin d'eviter les problemes d'affichage et d'impression les signes diacritiques // ont ete retires des commentaires et des chaines de caracteres. // // ! ======================== ! // ! LIBRAIRIES ET PARAMETRES ! // ! ======================== ! // #include // Pour la communication avec un peripherique. #include // Pour utilisation de l'horloge RTC. #include // Pour le servo moteur. // // ! ================================================= ! // ! VARIABLES GLOBALES, CONSTANTES ET INITIALISATIONS ! // ! ================================================= ! // // Pour les messages // ///////////////////////////////////////////////////// // // // A adapter selon l'enfant destinataire du cadeau // // // String cPrenom = "CAMILLE "; // Terminer par une espace int iJourNaissance = 13; // Pour l'affichage du BON ANNIVERSAIRE int iMoisNaissance = 2; // Idem int iJourFete = 14; // Pour l'affichage de la BONNE FETE int iMoisFete = 7; // Idem // // ///////////////////////////////////////////////////// // String cTexte; // Ligne a afficher sur les leds char cAfficheur[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Les afficheurs sont vides String cPanneDePile = "PANNE DE PILE "; // Message d'erreur en cas de panne du module RTC String cFin = " "; // Serie d'espaces pour la fin des lignes affichees char cChar; // Extraction d'un caractere des chaines a afficher RTC_DS1307 RTC; // Constante pour le module horloge // // Pour l'interrupteur permettant le reglage de l'heure d'ete ou d'hiver // bool bBoutonAppuye = false; unsigned long lDateAntiRebond = 0; int iCompteurDeClicks = 0; #define TEMPS_ANTI_REBOND_MS 30 // // Pour les calculs sur les dates et les heures. // DateTime now; unsigned long iHeures = 0; // Nombre d'heures. String cHeures = ""; // Equivalent en chaine de caracteres. unsigned long iMinutes = 0; // Idem pour les minutes. String cMinutes = ""; unsigned long iJours = 0; // La date. String cJours = ""; unsigned long iMois = 0; // Le mois. String cMois = ""; unsigned long iAnnees = 0;// L'annee. String cAnnees = ""; unsigned long iJoursDeLaSemaine = 0; // Jour de la semaine. String cJoursDeLaSemaine = ""; int iDizaines = 0; // Pour l'affichage des heures et des minutes au debut et a la fin de l'animation. int iUnites = 0; // Idem int t; // Pour les boucles diverses // // Parametres pour l'afficheur a LEDS // Les chiffres correspondent aux adresses 0xc0 0xc2 0xc4 0xc6 0xc8 0xca 0xcc 0xce // const int strobe = 4; // STB const int clock = 3; // CLK const int data = 2; // DIO #define SEGMENT_A 0x01 // A #define SEGMENT_B 0x02 // --- #define SEGMENT_C 0x04 // F : : B #define SEGMENT_D 0x08 // -G- #define SEGMENT_E 0x10 // E : : C #define SEGMENT_F 0x20 // --- #define SEGMENT_G 0x40 // D // // Les chiffres // const unsigned char cChiffres[] = { SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F, // 0 SEGMENT_B + SEGMENT_C, // 1 SEGMENT_A + SEGMENT_B + SEGMENT_G + SEGMENT_E + SEGMENT_D, // 2 SEGMENT_A + SEGMENT_B + SEGMENT_G + SEGMENT_C + SEGMENT_D, // 3 SEGMENT_F + SEGMENT_G + SEGMENT_B + SEGMENT_C, // 4 SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_C + SEGMENT_D, // 5 SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_E + SEGMENT_C + SEGMENT_D, // 6 SEGMENT_A + SEGMENT_B + SEGMENT_C, // 7 SEGMENT_A + SEGMENT_F + SEGMENT_B + SEGMENT_G + SEGMENT_E + SEGMENT_C + SEGMENT_D, // 8 SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_F + SEGMENT_G + SEGMENT_D, // 9 }; // // Les lettres // const unsigned char cLettreA = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_G; // Comme le R const unsigned char cLettreB = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F + SEGMENT_G; const unsigned char cLettreC = SEGMENT_A + SEGMENT_F + SEGMENT_E + SEGMENT_D; const unsigned char cLettreD = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F; // Comme le O et le Q const unsigned char cLettreE = SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_E + SEGMENT_D; const unsigned char cLettreF = SEGMENT_A + SEGMENT_F + SEGMENT_E + SEGMENT_G; const unsigned char cLettreG = SEGMENT_A + SEGMENT_F + SEGMENT_E + SEGMENT_D + SEGMENT_C; // Comme le N const unsigned char cLettreH = SEGMENT_F + SEGMENT_E + SEGMENT_G + SEGMENT_B + SEGMENT_C; const unsigned char cLettreI = SEGMENT_B + SEGMENT_C; const unsigned char cLettreJ = SEGMENT_B + SEGMENT_C + SEGMENT_D; // Pas de K const unsigned char cLettreL = SEGMENT_F + SEGMENT_E + SEGMENT_D; const unsigned char cLettreM = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C; // Comme le N const unsigned char cLettreN = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C; // Comme le M const unsigned char cLettreO = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F; // Comme le D et le Q const unsigned char cLettreP = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_G; const unsigned char cLettreQ = SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_D + SEGMENT_E + SEGMENT_F; // Comme le D et le 0 const unsigned char cLettreR = SEGMENT_E + SEGMENT_F + SEGMENT_A + SEGMENT_B + SEGMENT_C + SEGMENT_G; // Comme le A const unsigned char cLettreS = SEGMENT_A + SEGMENT_F + SEGMENT_G + SEGMENT_C + SEGMENT_D; const unsigned char cLettreT = SEGMENT_F + SEGMENT_E + SEGMENT_G; // en minuscule const unsigned char cLettreU = SEGMENT_F + SEGMENT_E + SEGMENT_D + SEGMENT_C + SEGMENT_B; // Comme le V const unsigned char cLettreV = SEGMENT_F + SEGMENT_E + SEGMENT_D + SEGMENT_C + SEGMENT_B; // Comme le U // Pas de W // Pas de X const unsigned char cLettreY = SEGMENT_F + SEGMENT_G + SEGMENT_B + SEGMENT_C + SEGMENT_D; // Pas de Z // // La ponctuation // const unsigned char cEspace = 0x00; const unsigned char cPoint = 0x80; const unsigned char cApostrophe = SEGMENT_F; const unsigned char cTraitDUnion = SEGMENT_G;// // // Initialisation du moteur // Servo sMoteur; // // // ! ===== ! // ! SETUP ! // ! ===== ! // void setup() { Serial.begin(9600); // // Pour l'ecran a LEDS. // pinMode(strobe, OUTPUT); pinMode(clock, OUTPUT); pinMode(data, OUTPUT); sendCommand(0x8f); reset(); sendCommand(0x44); // // Pour la detection du mouvement. // pinMode(5, INPUT); // C'est un connecteur d'entree. digitalWrite(5, LOW); // // Pour l'horloge. // Wire.begin(); // // Pour le moteur. // sMoteur.attach(6); // Broches du moteur sMoteur.write(0); // // // Pour l'interrupteur permettant le reglage heures d'ete ou d'hiver. // pinMode(7, INPUT_PULLUP); // // Pour signaler le mauvais fonctionnement. // effaceTout(); litLaDateEtLHeure(); if ((iHeures < 0) || (iHeures > 23) || (iMinutes < 0) || (iMinutes > 59) || (iJours < 0) || (iJours > 31) || (iMois < 0) || (iMois > 12) || (iAnnees < 2019) || (iAnnees > 2119)) // L'heure est incoherente ou la date est incoherente. { for (t = 0; t < 17; t++) { cChar = cPanneDePile[t]; affiche(cChar); delay(150); decale(); } while (1 == 1) // Si la pile (ou le module RTC) est en panne, inutile d'aller plus loin. { } } } // // ! ==== ! // ! LOOP ! // ! ==== ! // void loop() { if (digitalRead(5) == HIGH) // Si un mouvement est detecte. { litLaDateEtLHeure(); switch (iMois) // Mois en lettres. { case 1 : cMois = " JANVIER "; break; case 2 : cMois = " FEVRIER "; break; case 3 : cMois = " MARS "; break; case 4 : cMois = " AVRIL "; break; case 5 : cMois = " MAI "; break; case 6 : cMois = " JUIN "; break; case 7 : cMois = " JUILLET "; break; case 8 : cMois = " AOUT "; break; case 9 : cMois = " SEPTEMBRE "; break; case 10 : cMois = " OCTOBRE "; break; case 11 : cMois = " NOVEMBRE "; break; case 12 : cMois = " DECEMBRE "; break; } iAnnees = now.year(); // L'annee. cAnnees = (String) iAnnees; iJoursDeLaSemaine = now.dayOfTheWeek(); // Le jour de la semaine. switch (iJoursDeLaSemaine) // Le jour de la semaine en lettres. { case 0 : cJoursDeLaSemaine = "DIMANCHE "; break; case 1 : cJoursDeLaSemaine = "LUNDI "; break; case 2 : cJoursDeLaSemaine = "MARDI "; break; case 3 : cJoursDeLaSemaine = "MERCREDI "; break; case 4 : cJoursDeLaSemaine = "JEUDI "; break; case 5 : cJoursDeLaSemaine = "VENDREDI "; break; case 6 : cJoursDeLaSemaine = "SAMEDI "; break; } // On affiche tout de suite l'heure, des la detection d'un mouvement. afficheHeure(); // On fait tourner la figurine. if ((iHeures >= 8) && (iHeures <= 20)) { presenteFigurine();} delay(2500); // 2,5 Secondes de pause pour lire l'heure. effaceTout(); // Efface tous les afficheurs. // // On choisit le debut du message. // if ((iJours == 1) && (iMois == 1)) // Est-ce Nouvel-An (message prioritaire) ? { cTexte = "BONNE ANNEE "; } else { if ((iJours == 25) && (iMois == 12)) // Est-ce Noel ? { cTexte = "BON NOEL "; } else { if ((iJours == iJourNaissance) && (iMois == iMoisNaissance)) { cTexte = "BON ANNIVERSAIRE "; // Est-ce la date anniversaire ? } else { if ((iJours == iJourFete) && (iMois == iMoisFete)) { cTexte = "BONNE FETE "; // Est-ce la date de la fete ? } else { // Si ca n'est rien de tout ca, alors on dit if (iHeures < 12) { cTexte = "BONJOUR "; // BONJOUR le matin } else { if (iHeures > 18) // BONNE NUIT le soir { cTexte = "BONNE NUIT "; } else { cTexte = ""; // ou rien entre les deux (seulement le prenom) } } } } } } // // On affiche le message deroulant. // cTexte = cTexte + cPrenom + " " + "IL EST " + cHeures + "H" + cMinutes + " " + "NOUS SOMMES " + cJoursDeLaSemaine + cJours + cMois + cAnnees + cFin; for (t = 0; t <= cTexte.length(); t++) { cChar = cTexte[t]; affiche(cChar); delay(200); decale(); } // // On fait tourner la figurine. // if ((iHeures >= 8) && (iHeures <= 20)) { cacheFigurine();} // // On recrit l'heure qui est l'information la plus importante. // afficheHeure(); delay(10000); // durant 10 Secondes effaceTout(); } } // // ! ========== ! // ! PROCEDURES ! // ! ========== ! // // : ------------------------------------- : // : Initialisation de l'afficheur digital : // : ------------------------------------- : // void sendCommand(uint8_t value) { digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, value); digitalWrite(strobe, HIGH); } // void reset() { sendCommand(0x40); // set auto increment mode digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc0); for (uint8_t i = 0; i < 16; i++) { shiftOut(data, clock, LSBFIRST, 0x00); } digitalWrite(strobe, HIGH); } // // : -------------------------------- : // : Efface totalement l'ecran a LEDS : // : -------------------------------- : void effaceTout() { digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc0); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc2); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc4); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc6); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc8); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xca); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xcc); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xce); shiftOut(data, clock, LSBFIRST, 0x00); digitalWrite(strobe, HIGH); } // // : ------------------------------------------- : // : Decale vers la gauche les afficheurs a Leds : // : ------------------------------------------- : // void decale() { int t; for (t = 0; t < 7; t++) { cAfficheur[t] = cAfficheur[t + 1]; } } // // : -------------------- : // : Affiche sur les Leds : // : -------------------- : // void affiche(char cChar) { switch ((cChar)) { case 'A' : cAfficheur[7] = cLettreA; break; case 'B' : cAfficheur[7] = cLettreB; break; case 'C' : cAfficheur[7] = cLettreC; break; case 'D' : cAfficheur[7] = cLettreD; break; case 'E' : cAfficheur[7] = cLettreE; break; case 'F' : cAfficheur[7] = cLettreF; break; case 'G' : cAfficheur[7] = cLettreG; break; case 'H' : cAfficheur[7] = cLettreH; break; case 'I' : cAfficheur[7] = cLettreI; break; case 'J' : cAfficheur[7] = cLettreJ; break; case 'L' : cAfficheur[7] = cLettreL; break; case 'M' : cAfficheur[7] = cLettreM; break; case 'N' : cAfficheur[7] = cLettreN; break; case 'O' : cAfficheur[7] = cLettreO; break; case 'P' : cAfficheur[7] = cLettreP; break; case 'Q' : cAfficheur[7] = cLettreQ; break; case 'R' : cAfficheur[7] = cLettreR; break; case 'S' : cAfficheur[7] = cLettreS; break; case 'T' : cAfficheur[7] = cLettreT; break; case 'U' : cAfficheur[7] = cLettreU; break; case 'V' : cAfficheur[7] = cLettreV; break; case 'Y' : cAfficheur[7] = cLettreY; break; case ' ' : cAfficheur[7] = cEspace; break; case '.' : cAfficheur[7] = cPoint; break; case '-' : cAfficheur[7] = cTraitDUnion; break; case '/' : cAfficheur[7] = cApostrophe; break; case '1' : cAfficheur[7] = cChiffres[1]; break; case '2' : cAfficheur[7] = cChiffres[2]; break; case '3' : cAfficheur[7] = cChiffres[3]; break; case '4' : cAfficheur[7] = cChiffres[4]; break; case '5' : cAfficheur[7] = cChiffres[5]; break; case '6' : cAfficheur[7] = cChiffres[6]; break; case '7' : cAfficheur[7] = cChiffres[7]; break; case '8' : cAfficheur[7] = cChiffres[8]; break; case '9' : cAfficheur[7] = cChiffres[9]; break; case '0' : cAfficheur[7] = cChiffres[0]; break; } digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc0); shiftOut(data, clock, LSBFIRST, cAfficheur[0]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc2); shiftOut(data, clock, LSBFIRST, cAfficheur[1]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc4); shiftOut(data, clock, LSBFIRST, cAfficheur[2]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc6); shiftOut(data, clock, LSBFIRST, cAfficheur[3]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc8); shiftOut(data, clock, LSBFIRST, cAfficheur[4]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xca); shiftOut(data, clock, LSBFIRST, cAfficheur[5]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xcc); shiftOut(data, clock, LSBFIRST, cAfficheur[6]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xce); shiftOut(data, clock, LSBFIRST, cAfficheur[7]); digitalWrite(strobe, HIGH); } // /////////////////////////////////////////////////////////////////////////// // Gere la pression sur les boutons // // Voir la page // // http://www.diegoyourself.com/index.php?article=arduino_bouton&page=0 // /////////////////////////////////////////////////////////////////////////// // void EtatDuBouton(int entreeDigitale, // Parametre : entree digitale a lire bool& iBoutonAppuye, // Parametre : etat du bouton unsigned long& lDateAntiRebond, // Parametre : etat de l'anti-rebond int& iCompteurDeClicks) // Parametre : compteur de clicks { // lire l'etat de l'entree dans une nouvelle variable temporaire bool etatSignal = !digitalRead(entreeDigitale); // si le bouton semble avoir ete appuye (pas de signal, ou signal = 0/false) if (etatSignal) { // si l'anti-rebond est deja en train d'ignorer les rebonds if (lDateAntiRebond != 0) { // obtenir et determiner combien de temps s'est ecoule depuis le debut // de l'anti-rebond ( = date actuelle - date de debut) unsigned long tempsEcoule = millis() - lDateAntiRebond; // si le temps ecoule est superieur ou egal au temps d'anti-rebond if (tempsEcoule >= TEMPS_ANTI_REBOND_MS) { // Considerer alors que le bouton est appuye iBoutonAppuye = true; // arreter l'anti-rebond lDateAntiRebond = 0; // comme le bouton vient d'etre considere comme appuye (front montant) // c'est le moment d'incrementer le compteur de clicks iCompteurDeClicks++; // Afficher le compteur de clicks } } // sinon, si le bouton est actuellement considere comme relache else if (!iBoutonAppuye) { // activer l'anti-rebond en obtenant la date actuelle du systeme lDateAntiRebond = millis(); } // sinon, le bouton est deja considere comme appuye, il n'y a rien a faire } // sinon, le bouton semble avoir ete relache else { // si le bouton etait appuye if (iBoutonAppuye) { // le considerer maintenant comme relache iBoutonAppuye = false; } // sinon, le bouton etait deja relache ou l'anti-rebond etait en cours else { // arreter l'anti-rebond s'il etait en cours lDateAntiRebond = 0; } } } // // : ------------------------------ : // : Affiche l'heure et les minutes : // : ------------------------------ : // // __HH__ __MN__ // void afficheHeure() { litLaDateEtLHeure(); // Cherche les dizaines et les unites pour les heures if (iHeures >= 10) { iDizaines = (int) iHeures / 10; iUnites = iHeures - (iDizaines * 10); } else { iDizaines = 0; iUnites = iHeures; } // Affiche les dizaines et les unites des heures sur les digits idoines __HH__ __MN__ digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc2); shiftOut(data, clock, LSBFIRST, cChiffres[iDizaines]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xc4); shiftOut(data, clock, LSBFIRST, cChiffres[iUnites]); digitalWrite(strobe, HIGH); // Cherche les dizaines et les unites pour les minutes if (iMinutes >= 10) { iDizaines = (int) iMinutes / 10; iUnites = iMinutes - (iDizaines * 10); } else { iDizaines = 0; iUnites = iMinutes; } // Affiches les dizaines et les unites des minutes sur les digits idoines __HH__ __MN__ digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xca); shiftOut(data, clock, LSBFIRST, cChiffres[iDizaines]); digitalWrite(strobe, HIGH); digitalWrite(strobe, LOW); shiftOut(data, clock, LSBFIRST, 0xcc); shiftOut(data, clock, LSBFIRST, cChiffres[iUnites]); digitalWrite(strobe, HIGH); } // // : ----------------- : // : Lit le module RTC : // : ----------------- : // void litLaDateEtLHeure() { now = RTC.now(); // On lit l'heure et on extrait iHeures = now.hour(); // l'heure EtatDuBouton(7, bBoutonAppuye, lDateAntiRebond, iCompteurDeClicks); if (bBoutonAppuye == true) // On est en ete { iHeures++; if (iHeures > 23) { iHeures = 0; } } cHeures = (String) iHeures; if (iHeures < 10) { cHeures = "0" + cHeures; } // Formatage iMinutes = now.minute(); // les minutes cMinutes = (String) iMinutes; if (iMinutes < 10) { cMinutes = "0" + cMinutes; } // Formatage iJours = now.day(); // la date du jour cJours = (String) iJours; if (iJours < 10) { cJours = "0" + cJours; } iMois = now.month(); // le mois iAnnees = now.year(); } // // : ----------------- : // : Cache la figurine : // : ----------------- : // void cacheFigurine() { for (int position = 0; position < 90; position++) { sMoteur.write(position); delay(30); } } // // : ------------------ : // : Montre la figurine : // : ------------------ : // void presenteFigurine() { for (int position = 90; position >=0; position--) { sMoteur.write(position); delay(30); } }