//////////////////////////////////////////////////////////// // // // Horloge Parlante MP3 avec module RTC // // Et DFPlayer Mini pour lecture mp3 // // Mise à l'Heure + Choix sonneries // // // // Arnaud Houllemare 2019 // // // // This code is released under GPLv2 license. // // // //////////////////////////////////////////////////////////// #include // Librairie du module horloge #include "DFRobotDFPlayerMini.h" // Librairie du lecteur DFPlayer #include "SoftwareSerial.h" // Librairie de liaison série logicielle #include "LedControl.h" // Librairie 8X7 Led #include // Librairie de gestion de l'EEProm pour sauvegarde des options LedControl lc=LedControl(4,3,2,1); // Clk:3, Din::4, CS:2 SoftwareSerial mySoftwareSerial(10, 11); // RX =10, TX =11 DFRobotDFPlayerMini myDFPlayer; #define SayIt 6 // Pin de lecture forcée #define mahH 9 // Pin MàH Heures #define mahM 8 // Pin MàH Minutes #define cloche 10 // Pin Choix Sonnerie #define tempo 650 // Tempo d'attente lors de la lecture DS3231 rtc(SDA, SCL); // Initialise le module RTC // DS3231: SDA pin -> Arduino Analog 4 or the dedicated SDA pin // SCL pin -> Arduino Analog 5 or the dedicated SCL pin String TimeStr; // Chaîne reçue du ùodule RTC int unitsOut; // Numéro du message à lire pour les unités int tensOut; // Numéro du message à lire pour les dizaines int units; // unités issues de la décomposition d'un nombre int tens; // dizaines issues de la décomposition d'un nombre int HeuDec; // Heures en nombre récupéré du RTC int MinDec; // Minutes en nombre récupéré du RTC int SecDec; // Secondes en nombre récupéré du RTC int TypSon; // Type Sonnerie index 0 à 4. Par défaut: 0 int Sonnerie; // Numéro de fichier de Sonnerie void setup() { if(EEPROM.read(0)==255) EEPROM.put(0,0); // initialise le TypSon à 0, la première fois TypSon = EEPROM.read(0); // Récupère le type de sonnerie dans l'EEProm if(EEPROM.read(2)==255) EEPROM.put(2,29); // initialise le fichier sonnerie à 29 (Reveil Officier), la première fois Sonnerie = EEPROM.read(2); // Récupère le toggle lecture dans l'EEprom mySoftwareSerial.begin(9600); // Ouverture d'une communication série if (!myDFPlayer.begin(mySoftwareSerial)) {} // Use softwareSerial to communicate with mp3. myDFPlayer.volume(25); // Set volume value. From 0 to 30 rtc.begin(); // Initialise l'objet RTC // rtc.setTime(16, 57, 0); // Mise à l'heure logicielle au moins une fois initialement. (HH,MM,SS format 24h) pinMode(SayIt, INPUT_PULLUP); // Pin de lecture de l'heure en mode INPUT pinMode(mahH, INPUT_PULLUP); // Pin Mise à L'Heure Heures en mode INPUT pinMode(mahM, INPUT_PULLUP); // Pin Mise à L'Heure Minutes en mode INPUT pinMode(cloche, INPUT_PULLUP); // Pin choix sonnerie en mode INPUT lc.shutdown(0,false); // Autorise l'affichage lc.setIntensity(0,8); // Définit l'intensité de l'affichage lc.clearDisplay(0); // Efface l'affichage } void loop() { TimeStr=(rtc.getTimeStr()); // Récupération de la chaîne de l'heure du module RTC MinDec = TimeStr.substring(3,5).toInt(); // On extrait et convertit en int les minutes HeuDec = TimeStr.substring(0,2).toInt(); // On extrait et convertit en int les heures SecDec = TimeStr.substring(6,8).toInt(); // On extrait et convertit en int les secondes AfficheHeure(); // Affichage de l'Heure if ((MinDec == 0) && (SecDec < 1)) // Si c'est l'heure pleine et dans la première seconde { if (HeuDec == 0) // il est minuit { for (int i=1; i <= 12; i++) Sonne(Sonnerie); // on sonne douze fois LitHeure(HeuDec,MinDec); // Lit l'heure si actif } else if (HeuDec <= 12) // entre minuit et midi inclus { for (int i=1; i <= HeuDec; i++) Sonne(Sonnerie); // on sonne l'heure LitHeure(HeuDec,MinDec); // Lit l'heure si actif } else if (HeuDec < 24) // si c'est l'après midi { for (int i=1; i <= (HeuDec % 12); i++) Sonne(Sonnerie); // on enlève 12 (pour éviter les 24 coups à minuit) et son sonne l'heure LitHeure(HeuDec,MinDec); // Lit l'heure si actif } } if ((MinDec == 30) && (SecDec < 1)) { Sonne(Sonnerie); // Si c'est la demie, on sonne une fois LitHeure(HeuDec,MinDec); // Lit l'heure si actif } if (digitalRead(mahH) == LOW) ajusteH(); // Ajuste l'Heure if (digitalRead(mahM) == LOW) ajusteM(); // Ajuste Les Minutes if (digitalRead(cloche) == LOW) ChoixSonnerie(); // Choix de la sonnerie if (digitalRead(SayIt) == LOW) // Si le bouton de demande d'heure est activé, on dit l'heure et les minutes { Sonne(Sonnerie); // Pour faire joli, on sonne une fois avant de dire l'heure LitHeure(HeuDec,MinDec); } } void Parse(int nombre) // Décomposition d'un nombre en unités et dizaines { units = nombre % 10; // les unités sont le nombre modulo 10 tens = (nombre - units) /10; // le nombre de dizaine est le nombre moins les unités divisé par 10 // Traitement des unités unitsOut = units; // Pour les unités, pas de soucis, la variable est juste là pour l'élégance du script // Traitement des dizaines if (tens == 1 && units > 0) // Gestion du cas particulier de la langue française 11,12,13...19 { tensOut = 10 + units; // met dans tensOut le numéro destiné à dire 11,12,13 etc unitsOut = 11; // met dans unitsOut un numéro de cas qui ne fait rien } else { tensOut = tens; // met dans tensOut le numéro destiné à dire 20,30,40 ou 50 if (units == 0) unitsOut = 11; // si unités=0, met dans unitsOut un numéro de cas qui ne fait rien } } void SayUnit(int n) { switch(n) { case 0: Parle(1); break; // Dit 'Zéro' case 1: Parle(2); break; // Dit 'Une' case 2: Parle(3); break; // Dit 'Deux' case 3: Parle(4); break; // Dit 'Trois' case 4: Parle(5); break; // Dit 'Quatre' case 5: Parle(6); break; // Dit 'Cinq' case 6: Parle(7); break; // Dit 'Six' case 7: Parle(8); break; // Dit 'Sept' case 8: Parle(9); break; // Dit 'Huit' case 9: Parle(10); break; // Dit 'Neuf' case 10: Parle(11); break; // Dit 'Dix' case 11: break; } } void SayTens(int n) { switch(n) { case 1: Parle(11); break; // Dit 'Dix' case 2: Parle(21); break; // Dit 'Vingt' case 3: Parle(22); break; // Dit 'Trente' case 4: Parle(23); break; // Dit 'Quarante' case 5: Parle(24); break; // Dit 'Cinquante' case 11: Parle(12); break; // Dit 'Onze' case 12: Parle(13); break; // Dit 'Douze' case 13: Parle(14); break; // Dit 'Treize' case 14: Parle(15); break; // Dit 'Quatorze' case 15: Parle(16); break; // Dit 'Quinze' case 16: Parle(17); break; // Dit 'Seize' case 17: Parle(18); break; // Dit 'Dix-Sept' case 18: Parle(19); break; // Dit 'Dix-Huit' case 19: Parle(20); break; // Dit 'Dix-Neuf' } } void LitHeure(int HeuDec,int MinDec) { Parle(27); // 'Il est...' Parse(HeuDec); // décompose les heures en dizaines d'heures et unités d'heures LitNombre(); // Lit la décomposition Parle(25); // Dit 'heures' (sans liaison...) if (MinDec != 0) // Si les minutes sont différentes de 0, lit les minutes { Parse(MinDec); // décompose les minutes en dizaines de minutes et unités de minutes LitNombre(); // Lit la décomposition Parle(26); // Dit 'minutes' } } void LitNombre() { SayTens(tensOut); // Dit les dizaines if (tensOut == 0 && unitsOut == 11) Parle(1); // Dit 'Zéro' si nécessaire (dizaines = 0 et unités = 0 par le pointeur 11) if (tensOut > 1 && unitsOut == 1) Parle(28); // Ajoute si nécessaire 'Et' SayUnit(unitsOut); // Sinon dit les unités } void Parle(int n) // séquence de lecture du mp3 et sa temporisation nécessaire ! { myDFPlayer.play(n); delay(tempo); } void ajusteH() { HeuDec++; // Incrémente l'Heure HeuDec = HeuDec % 24; // modulo 24 pour être entre 0 et 23 rtc.setTime(HeuDec, MinDec, 0); // Met le RTC à l'heure AfficheHeure(); // Affiche l'Heure (nécessaire ?) delay(500); // Courte pause } void ajusteM() { MinDec++; // Incrémente les Minutes MinDec = MinDec % 60; // modulo 60 pour être entre 0 et 59 rtc.setTime(HeuDec, MinDec, 0); // Met le RTC à l'heure AfficheHeure(); // Affiche l'Heure (nécessaire ?) delay(500); // Courte pause } void AfficheHeure() { //Affiche secondes lc.setChar(0,0,TimeStr.charAt(7),false); lc.setChar(0,1,TimeStr.charAt(6),false); //Affiche minutes lc.setChar(0,3,TimeStr.charAt(4),false); lc.setChar(0,4,TimeStr.charAt(3),false); //Affiche heures lc.setChar(0,6,TimeStr.charAt(1),false); lc.setChar(0,7,TimeStr.charAt(0),false); cligno(); } void ChoixSonnerie() { TypSon++; // TypSon est le choix de sonnerie de 0 à 4 TypSon = TypSon % 5; // Prend le modulo 5 switch(TypSon) // Selon le numéro du choix de sonnerie { case 0: { Sonnerie = 29; // Numéro mp3 correspondant Sonne(Sonnerie); // Joue la sonnerie EEPROM.put(2,Sonnerie); // Mémorise dans l'EEProm le numéro de fichier de sonnerie EEPROM.put(0,TypSon); // Mémorise dans l'EEProm le type de sonnerie break; // Fin du traitement } case 1: { Sonnerie = 30; // Numéro mp3 correspondant Sonne(Sonnerie); // Joue la sonnerie EEPROM.put(2,Sonnerie); // Mémorise dans l'EEProm le numéro de fichier de sonnerie EEPROM.put(0,TypSon); // Mémorise dans l'EEProm le type de sonnerie break; // Fin du traitement } case 2: { Sonnerie = 31; // Numéro mp3 correspondant Sonne(Sonnerie); // Joue la sonnerie EEPROM.put(2,Sonnerie); // Mémorise dans l'EEProm le numéro de fichier de sonnerie EEPROM.put(0,TypSon); // Mémorise dans l'EEProm le type de sonnerie break; // Fin du traitement } case 3: { Sonnerie = 32; // Numéro mp3 correspondant Sonne(Sonnerie); // Joue la sonnerie EEPROM.put(2,Sonnerie); // Mémorise dans l'EEProm le numéro de fichier de sonnerie EEPROM.put(0,TypSon); // Mémorise dans l'EEProm le type de sonnerie break; // Fin du traitement } case 4: { Sonnerie = 33; // Numéro mp3 correspondant Sonne(Sonnerie); // Joue la sonnerie EEPROM.put(2,Sonnerie); // Mémorise dans l'EEProm le numéro de fichier de sonnerie EEPROM.put(0,TypSon); // Mémorise dans l'EEProm le type de sonnerie break; // Fin du traitement } } } void Sonne(int Sonnerie) { myDFPlayer.play(Sonnerie); // Joue la sonnerie sélectionnée delay(2 * tempo); // Une tempo une peu plus longue entre chaque Sonnerie } // Clignotement des barres séparatrices void cligno() { lc.setLed(0,2,7,true); lc.setLed(0,5,7,true); delay(500); lc.setLed(0,2,7,false); lc.setLed(0,5,7,false); delay(500); }