WebRadioRéveilWifi -4-
Par makoto doushite le mardi, 6 février 2018, 15:42 - Électronique - Lien permanent
Je vais (enfin !!) reprendre la conception de mon WebRadioReveilWifi, après que tant de temps ait passé…
Il est désormais fonctionnel et me réveille correctement tous les matins, et c'est dans une suite de plusieurs billets que je vais détailler la réalisation étape par étape.
L'horloge :
- Pour rappel, j'avais câblé un prototype de l'horloge sur une carte à trou, elle même branchée sur un Arduino.
Cette maquette m'a pas mal servi à apprendre Arduino et voir où les expérimentations me menaient, afin de bien dimensionner la suite.
C'est ainsi que j'ai pu router un circuit imprimé, puis graver percer et souder la plaque…
Cependant même si on croit avoir toujours tout prévu, j'ai tout de même dû modifier certaines choses sur mon circuit, une erreur fâcheuse et des modifications de dernières minutes.
C'est donc le circuit final réalisé sur Kicad que je vais livrer ici (en annexe du billet), il ne correspondra pas aux photos, sur lesquelles apparaissent donc les modifications et bricolage de rattrapages.
- Le Schéma structurel de la carte principale :
- Le circuit de la carte principale :
- Liste des composants:
Nom Type et valeur Shield1 Arduino Pro Mini 5V P1, P6 Pin header x3 P2 Pin header x6 P5 Pin header x2 P3 Pin header HE10-10 P4 Bornier 2 vis D1, D2 Led Verte D3, D4 Led Rouge D5 Photodiode LSL100 ou Photorésistance 5516 R6, R7 Résistances 1kΩ R11 Résistances 2,2kΩ R12 à R18 Résistances 39Ω R19 Résistances 150Ω R20 à R26 Résistances 39Ω R27 Résistances 150Ω R28 à R34 Résistances 39Ω R35 Résistances 150Ω R36 à R42 Résistances 39Ω R43 Résistances 150Ω Afficheur1, 2, 3, 4 Afficheur 7 segments SA10-21GWA-Kingbright 25,4 mm Vert Q1, Q2, Q3, Q4, Q5 BC547 C7, C8, C9,C10 Condensateur 100nF U1, U2, U3, U4 74HC595
- Le Schéma structurel de la carte des boutons :
- Le circuit de la carte des boutons :
- Liste des composants:
Nom Type et valeur C1, C2, C3, C4, C5, C6 Condensateur 100nF SW1, SW2, SW3, SW4, SW5, SW6 Petit bouton poussoir R1, R2, R3, R4, R5, R6 Résistances 10kΩ P1 Pin header HE10-10
- Une fois les plaques gravées, il restait à percer tous les trous, à 0,8 mm et 1 mm de diamètre avec ma perceuse à colonne imprimée3D .
Une petit video !
- Voici les cartes et les composants parés pour la soudure.
- Mais avant, car réalisé en simple face, je n'ai pu faire autrement que de passer quelques liaisons sur l'autre face, et donc ici de devoir souder quelques fils en lieu et place.
- Pour plier les pattes des résistances, je me suis aidé d'un plioir imprimé3D… Étant donné le grand nombre de résistances, c'était pas du luxe !
- Je pense que la suite se passe de trop de commentaire, avec la soudure progressive les composants, des plus maigres aux plus épais.
- Le module RTC (Real Time Clock) à base de DS3231 peut se trouver tout fait, mais ici je disposait seulement du composant, voulant rester compatible avec le concept du module enfichable, j'ai tout simplement réalisé une petite carte qui fait le même job, avec sa pile de sauvegarde !
- Liste des composants:
Nom Type et valeur C6 Condensateur 100nF R9, R10 Résistances 10kΩ U5 DS3231N BT1 Support de pile Bouton 3V (CR2032) P1 Pin header x6
- Voilà donc tout est prêt, avec la carte principale qui accueillera (en haut) les 4 afficheurs 7 segments, les quatre 74HC595, (à droite) l'Arduino, (à gauche) la plaquette de boutons reliée au centre de la carte principale par une nappe de connecteur, (en bas) le capteur de mouvement (PIR) et le module RTC.
L'ampli audio :
- Dans l'épisode précédent, j'avais donc câblé un petit ampli à base de LM386 sur une plaquette labo afin d'en valider le fonctionnement, puis j'en ai dessiné un circuit sur Kicad qui a été réalisé en simple face et que l'on va voir ci-après.
Cependant, comme pour l'horloge, j'ai un moment perdu de vue mes desiderata, et en rajoutant une source audio, je me suis plus tard rendu compte que j'avais oublié une partie du circuit pour le mélange des signaux entrants.
Et ce n'est pas tout… En intégrant l'ampli dans le boîtier du WebRadioRéveil que nous verrons dans un autre billet, j'ai vite compris que j'allais devoir retirer un certains nombre de connecteurs.
Le circuit final réalisé sur Kicad (en annexe du billet), contient donc toutes les modifications et ne correspondra donc pas tout à fait aux photos.
- Le schéma structurel de l'ampli :
- Le circuit de l'ampli :
- Liste des composants:
Nom Type et valeur C13, C14, C15, C16 Condensateur électrochimique polarisé 47µF 16V C2, C5, C8, C11 Condensateur électrochimique polarisé 10µF 16V C3, C9 Condensateur électrochimique polarisé 470µF 16V C4, C10 Condensateur 33nF C6, C12 Condensateur 100nF C1, C7 Condensateur 1µF R4, R5, R6, R7 Résistances 2,2kΩ R8, R9 Résistance 100Ω R1, R3 Résistances 1,2kΩ R2 Résistances 1,5kΩ RV1, RV2 Potentiomètre Double 10kΩ U1, U2 LM386N-3 D1 Led Jaune 3 mm SP1, SP2 Petit Haut Parleur
- Une petit video !
- Tous les composants parés pour la soudure !
On verra donc plus tard que ce sont les deux jacks audio, le jack alim et le bornier que j'ai dû retirer. Et de rajouter une petite carte intégrant le mélangeur audio.
Le code :
- Une fois le hardware terminé, il reste à revoir et améliorer le code commencé la dernière fois.
Tout le système assemblé proprement sur table pour coder sereinement.
À gauche de Raspberry Pi et sa carte de boutons pour piloter manuellement la radio, au dessus l'ampli audio relié au Raspberry Pi , et donc à droite l'horloge avec son Arduino, son module RTC et sa carte de boutons.
- Le code et les deux librairies nécessaire pour Arduino sont disponible en annexe du billet.
Ce code est à utiliser avec Arduino 1.5.5
/****** Domaine publique, youpi ! ******/ /****** Ce code est à utiliser avec Arduino 1.5.5 *****/ #include <Wire.h> // Communication avec le RTC #include <Tone.h> // Sonnerie ChipTune, voir Librairie #include "Chronodot.h" // Fonctions du Chronodot, voir Librairie modifiée /****************/ /* Déclarations */ /****************/ #define CHRONODOT_ADDRESS 0x68 /****** Signaux ******/ #define datapin 10 // pin 10 pour les données vers les registres à décallages 74HC595 #define clockpin 11 // pin 11 pour l'horloge qui coordonne les registres à décallages #define latchpin 8 // pin 8 pour le déclencheur des registres à décallages /****** Boutons poussoir ******/ #define BoutonMinutes 12 // pin 12 pour le bouton poussoir d'incrément des minutes #define BoutonHeures 13 // pin 13 pour le bouton poussoir d'incrément des heures #define BoutonAlarme1 6 // pin 6 pour le bouton poussoir Alarme1 #define BoutonAlarme2 2 // pin 2 pour le bouton poussoir Alarme2, alias « interruption 0 » #define BoutonHorloge 7 // pin 7 pour le bouton poussoir Horloge #define BoutonSupp 1 // pin TX1 pour le bouton supplémentaire #define relais A2 // pin analogique 2 pour le pilotage du relais ON/OFF AmpliAudio #define Radio A3 // pin analogique 3 pour le déclenchement de la radio (relié par la carte d'interface 5V -> 3V) à l'un des GPIO du Rpi /****** LED ******/ #define LedAlarm1 4 // pin 4 pour la led de l'alarme1 #define LedAlarm2 3 // pin 3 pour la led de l'alarme2 /****** Alimentation des 7 segments en PWM ******/ #define ledPin 9 // pin 9 pour le signal PWM de cadencement des afficheurs et leds #define photodiodepin A0 // pin A0 pour la photodiode /****** Variables d'état ******/ int EtatBoutonMinutes = 1; // pour stocker l'état du bouton aprés sa lecture int EtatBoutonHeures = 1; // idem int EtatBoutonAlarme1 = 1; // idem int EtatBoutonAlarme2 = 1; // idem int EtatBoutonHorloge = 1; // idem int EtatBoutonSupp = 1; // idem unsigned int ValeurPhotoDiode = 0; // pour stocker l'état de la photodiode aprés sa lecture volatile int change = 0; // pour mémoriser l'état de l'interruption 0 /****** Variables temporelles ******/ unsigned int heuresHorloge; // pour stocker les heures unsigned int heuresHorlogeINC; // pour stocker l'incrément des heures unsigned int minutesHorloge; // pour stocker les minutes unsigned int minutesHorlogeINC;// pour stocker l'incrément des minutes unsigned int secondes; // pour stocker les secondes unsigned int annee; // pour stocker l'annee unsigned int mois; // pour stocker le mois unsigned int jour; // pour stocker le jour unsigned int heuresAlarme; // pour stocker les heures unsigned int heuresAlarmeINC; // pour stocker l'incrément des heures unsigned int minutesAlarme; // pour stocker les minutes unsigned int minutesAlarmeINC;// pour stocker l'incrément des minutes /****** Variables d'affichage ******/ int dizH = 0; // pour stocker les dizaine des heures int unitH = 0; // pour stocker les unités des heures int dizM = 0; // pour stocker les dizaine des minutes int unitM = 0; // pour stocker les unités des minutes byte AfficheurUN; // données binaire pour l'afficheur UN, situé le plus à droite byte AfficheurDEUX; // données binaire pour l'afficheur DEUX byte AfficheurTROIS; // données binaire pour l'afficheur TROIS byte AfficheurQUATRE; // données binaire pour l'afficheur QUATRE, situé le plus à gauche byte dataArray[10]; // Tableau de données /****** Référenciel librairies ******/ Chronodot HORLOGE; // HORLOGE, nom choisi arbitrairement, référence à la librairie Chronodot ChronodotAlarm1 RADIO; ChronodotAlarm2 REVEIL; /**** Variable de construction des sonneries *****/ Tone tone1; #define OCTAVE_OFFSET 0 #define isdigit(n) (n >= '0' && n <= '9') int notes[] = { 0, NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4, NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5, NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6, NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7 }; char *songA = "A-Team:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#"; char *songB = "Hallowee:d=4,o=5,b=140:32p,8d6,8g,8g,8d6,8g,8g,8d6,8g,8d#6,8g,8d6,8g,8g,8d6,8g,8g,8d6,8g,8d#6,8g,8c#6,8f#,8f#,8c#6,8f#,8f#,8c#6,8f#,8d6,8f#,8c#6,8f#,8f#,8c#6,8f#,8f#,8c#6,8f#,8d6,8f#"; char *songC = "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c"; char *songD = "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5"; char *songE = "Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,8d#"; char *songF = "MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a#,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c.,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#."; int song = 1; // variable pour changer de sonnerie aprés chaque utilisation de la sonnerie /*******************/ /* Initialisations */ /*******************/ void setup () // Fonction d'initialisation obligatoire { // Serial.begin(9600); // uncomment to debug // Serial.println("Initializing Chronodot."); // uncomment to debug dataArray[0] = B00000011; // Case du tableau qui contient la valeur binaire pour afficher zero sur un afficheur 7 segments dataArray[1] = B10011111; // Case du tableau qui contient la valeur binaire pour afficher un sur un afficheur 7 segments dataArray[2] = B00100101; // Case du tableau qui contient la valeur binaire pour afficher deux sur un afficheur 7 segments dataArray[3] = B00001101; // Case du tableau qui contient la valeur binaire pour afficher trois sur un afficheur 7 segments dataArray[4] = B10011001; // Case du tableau qui contient la valeur binaire pour afficher quatre sur un afficheur 7 segments dataArray[5] = B01001001; // Case du tableau qui contient la valeur binaire pour afficher cinq sur un afficheur 7 segments dataArray[6] = B01000001; // Case du tableau qui contient la valeur binaire pour afficher six sur un afficheur 7 segments dataArray[7] = B00011111; // Case du tableau qui contient la valeur binaire pour afficher sept sur un afficheur 7 segments dataArray[8] = B00000001; // Case du tableau qui contient la valeur binaire pour afficher huit sur un afficheur 7 segments dataArray[9] = B00001001; // Case du tableau qui contient la valeur binaire pour afficher neuf sur un afficheur 7 segments pinMode(clockpin, OUTPUT); // pin correspondant à "clockpin" initialisée en sortie pinMode(datapin, OUTPUT); // pin correspondant à "datakpin" initialisée en sortie pinMode(latchpin, OUTPUT); // pin correspondant à "latchpin" initialisée en sortie pinMode(BoutonMinutes, INPUT); // pin correspondant à "BoutonMinutes" initialisée en entrée pinMode(BoutonHeures, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée pinMode(BoutonAlarme1, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée pinMode(BoutonAlarme2, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée pinMode(BoutonHorloge, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée pinMode(BoutonSupp, INPUT); // pin correspondant à "BoutonSupp" initialisée en entrée pinMode(LedAlarm1, OUTPUT); // pin correspondant à "LedAlarm1" initialisée en sortie pinMode(LedAlarm2, OUTPUT); // pin correspondant à "LedAlarm2" initialisée en sortie pinMode(relais, OUTPUT); // pin correspondant à "relais" initialisée en sortie pinMode(Radio, OUTPUT); // pin correspondant à "Radio" initialisée en sortie tone1.begin(A1); // pin A1 pour le jack sonnerie Wire.begin(); // initialisation du chronodot, référence à la librairie wire HORLOGE.begin(); // initialisation du chronodot, référence à la librairie Chronodot //************ MISE à L'heure manuelle du module RTC DS3231 ************ // HORLOGE.adjust(DateTime(2014,12,25,10,30,12)); // années, mois, jour, heures, minutes, secondes // RADIO.adjust(AlarmTime1(6,30,0)); // REVEIL.adjust(AlarmTime2(7,30)); attachInterrupt(0, stop2, FALLING); // attache l'interruption externe n°0 (pin2 soit bouton Alarm2) à la fonction stop2 digitalWrite(Radio, HIGH); // Coupe la radio au démarrage RADIO.Alarm1SetON(); // au démarrage, l'alarme Radio est forcée ON (en cas de coupure de courant) digitalWrite (LedAlarm1, HIGH); REVEIL.Alarm2SetON(); // au démarrage, l'alarme Réveil est forcée ON (en cas de coupure de courant) digitalWrite (LedAlarm2, HIGH); } /*************/ /* Programme */ /*************/ void loop () // boucle du programme ! { horloge (); // appelle la fct "horloge", récupération des données temporelles AfficheHorloge (); // appelle la fct "affiche", transfert des données temporelles sur les afficheurs 7 segments AjusteLuminosite(); // appelle la fct "AjusteLuminosite", plus il fait sombre, plus la lumière des afficheurs baisse SurveilleBouton_Horloge_Heures_Minutes (); // Pour permettre de mettre l'horloge à l'heure // SurveilleBouton_Supp (); RadioON(); // envoie d'ordre au rpi FaireSonnerSonnerie(); EtatBoutonAlarme1 = digitalRead(BoutonAlarme1); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme1" EtatBoutonAlarme2 = digitalRead(BoutonAlarme2); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme2" if (EtatBoutonAlarme1 == LOW) // sinon, si bouton alarme 1 appuyé { for (int i=0; i <= 800; i++) // faire durant 3 sec { alarme1(); AfficheAlarme(); // affiche l'alarme SurveilleBouton_Alarme1_Heures_Minutes (); // régler l'alarme SurveilleBouton_Alarme1_Horloge (); } } if (EtatBoutonAlarme2 == LOW) // sinon, si bouton alarme 2 appuyé { // Stopper(); for (int j=0; j <= 800; j++) // faire durant 3 sec { alarme2(); AfficheAlarme(); // affiche l'alarme SurveilleBouton_Alarme2_Heures_Minutes (); // régler l'alarme SurveilleBouton_Alarme2_Horloge (); } } if(change == 1) { // Si change = 1, stopper la sonnerie change = 0; // Serial.print(change); // RADIO.Alarm1Stop(); REVEIL.Alarm2Stop(); song = song + 1; // pour une sonnerie différente la prochaine fois if(song == 7) { song = 1; } // Serial.print(", song:"); // // Serial.print(song); // // Serial.println(); } } /****************************************/ /***** Les Fonctions du programme *******/ /****************************************/ /***** Fonction d'horloge *******/ void horloge () { DateTime now = HORLOGE.now(); // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot heuresHorloge = now.hour(), DEC; // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot minutesHorloge = now.minute(), DEC; // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot secondes = now.second(), DEC; // stocke les secondes en décimale dans la variable "secondes" grace à la fct "second" de la lib chronodot annee = now.year(), DEC; // stocke l'année en décimale dans la variable "annee" grace à la fct "year" de la lib chronodot mois = now.month(), DEC; // stocke le mois en décimale dans la variable "mois" grace à la fct "month" de la lib chronodot jour = now.day(), DEC; // stocke le jour en décimale dans la variable "jour" grace à la fct "day" de la lib chronodot // Serial.print(annee); // // Serial.print(':'); // // Serial.print(mois); // // Serial.print(':'); // // Serial.print(jour); // // Serial.print(':'); // // Serial.print(heures); //décommenter pour débug // Serial.print(':'); // // Serial.print(minutes); // // Serial.println(); // } /***** Fonction d'alarme 1 *******/ void alarme1 () { AlarmTime1 now = RADIO.now(); // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot heuresAlarme = now.hourA1(), DEC; // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot minutesAlarme = now.minuteA1(), DEC; // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot // Serial.print(heuresAlarme); //décommenter pour débug // Serial.print(':'); // // Serial.print(minutesAlarme); // // Serial.println(); // } /***** Fonction d'alarme 2 *******/ void alarme2 () { AlarmTime2 now = REVEIL.now(); // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot heuresAlarme = now.hourA2(), DEC; // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot minutesAlarme = now.minuteA2(), DEC; // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot // Serial.print(heuresAlarme); //décommenter pour débug // Serial.print(':'); // // Serial.print(minutesAlarme); // // Serial.println(); // } /***** Fonction d'affichage horloge sur les 7 segments *******/ void AfficheHorloge () { dizH = heuresHorloge / 10; // par calcul, extrait la dizaine de "heures" et stocke le résultat dans "dizH" unitH = heuresHorloge % 10; // par calcul, extrait l'unités de "heures" et stocke le résultat dans "unitH" dizM = minutesHorloge / 10; // par calcul, extrait la dizaine de "minutes" et stocke le résultat dans "dizM" unitM = minutesHorloge % 10; // par calcul, extrait l'unité de "minutes" et stocke le résultat dans "dizM" AfficheurUN = dataArray[unitM]; // stocke la valeur binaire 7 segments de l'unité de minutes dans "AfficheurUN" // AfficheurUN &= ~(1<<1); AfficheurDEUX = dataArray[dizM]; // stocke la valeur binaire 7 segments de la dizaine de minutes dans "AfficheurDEUX" AfficheurTROIS = dataArray[unitH]; // stocke la valeur binaire 7 segments de l'unité d'heures dans "AfficheurTROIS" AfficheurQUATRE = dataArray[dizH]; // stocke la valeur binaire 7 segments de la dizaine d'heures dans "AfficheurQUATRE" // AfficheurQUATRE &= ~(1<<1); digitalWrite(latchpin, 1); // latch à l'état HAUT pour autoriser le transfert des données série shiftOut(datapin, clockpin, LSBFIRST, AfficheurUN); // envoi l'unités minute au registre à décallage shiftOut(datapin, clockpin, LSBFIRST, AfficheurDEUX); // envoi la dizaine minute au registre à décallage shiftOut(datapin, clockpin, LSBFIRST, AfficheurTROIS); // envoi l'unités heure au registre à décallage shiftOut(datapin, clockpin, LSBFIRST, AfficheurQUATRE); // envoi la dizaine heure au registre à décallage digitalWrite(latchpin, 0); // latch à l'état BAS pour arreter le transfert des données série } /***** Fonction d'affichage alarmes sur les 7 segments *******/ void AfficheAlarme () { dizH = heuresAlarme / 10; // par calcul, extrait la dizaine de "heures" et stocke le résultat dans "dizH" unitH = heuresAlarme % 10; // par calcul, extrait l'unités de "heures" et stocke le résultat dans "unitH" dizM = minutesAlarme / 10; // par calcul, extrait la dizaine de "minutes" et stocke le résultat dans "dizM" unitM = minutesAlarme % 10; // par calcul, extrait l'unité de "minutes" et stocke le résultat dans "dizM" AfficheurUN = dataArray[unitM]; // stocke la valeur binaire 7 segments de l'unité de minutes dans "AfficheurUN" AfficheurDEUX = dataArray[dizM]; // stocke la valeur binaire 7 segments de la dizaine de minutes dans "AfficheurDEUX" AfficheurTROIS = dataArray[unitH]; // stocke la valeur binaire 7 segments de l'unité d'heures dans "AfficheurTROIS" AfficheurQUATRE = dataArray[dizH]; // stocke la valeur binaire 7 segments de la dizaine d'heures dans "AfficheurQUATRE" digitalWrite(latchpin, 1); // latch à l'état HAUT pour autoriser le transfert des données série shiftOut(datapin, clockpin, LSBFIRST, AfficheurUN); // envoi l'unités minute au registre à décallage shiftOut(datapin, clockpin, LSBFIRST, AfficheurDEUX); // envoi la dizaine minute au registre à décallage shiftOut(datapin, clockpin, LSBFIRST, AfficheurTROIS); // envoi l'unités heure au registre à décallage shiftOut(datapin, clockpin, LSBFIRST, AfficheurQUATRE); // envoi la dizaine heure au registre à décallage digitalWrite(latchpin, 0); // latch à l'état BAS pour arreter le transfert des données série } /***** Régler l'Horloge : Fonction Surveillance des BoutonHorloge, BoutonMinutes et BoutonHeures *******/ void SurveilleBouton_Horloge_Heures_Minutes () { EtatBoutonHorloge = digitalRead(BoutonHorloge); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge" EtatBoutonHeures = digitalRead(BoutonHeures); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures" EtatBoutonMinutes = digitalRead(BoutonMinutes); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes" if ((EtatBoutonHorloge == LOW) && (EtatBoutonHeures == LOW)) // si le bouton est appuyé { delay(170); // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut RegleHorlogeHeures (); // et appeller la fonction "RegleHeures" } if ((EtatBoutonHorloge == LOW) && (EtatBoutonMinutes == LOW)) // si le bouton est appuyé { delay(170); // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut RegleHorlogeMinutes (); // et appeller la fonction "RegleMinutes" } } /***** Fonction d'incrément Heures *******/ void RegleHorlogeHeures () { heuresHorlogeINC = heuresHorloge + 1; // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC" if (heuresHorlogeINC > 23) // si la valeur de "heuresHorlogeINC" dépasse 23 (23h) { heuresHorlogeINC = 0; // alors, et la variable "heuresHorlogeINC" à zero (minuit) } // Serial.print(heuresHorlogeINC); // Serial.println(); HORLOGE.adjust(DateTime(annee,mois,jour,heuresHorlogeINC,minutesHorloge,0)); // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero } /***** Fonction d'incrément minutes *******/ void RegleHorlogeMinutes () { minutesHorlogeINC = minutesHorloge + 1; // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC" if (minutesHorlogeINC > 59) // si la valeur de "minutesHorlogeINC" dépasse 59 (59min) { minutesHorlogeINC = 0; // alors, met la variable "minutesHorlogeINC" à zero } // Serial.print(minutesHorlogeINC); // Serial.println(); HORLOGE.adjust(DateTime(annee,mois,jour,heuresHorloge,minutesHorlogeINC,0)); // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero } /***** Régler l'Alarme 1 : Fonction Surveillance des BoutonAlarme1, BoutonMinutes et BoutonHeures *******/ void SurveilleBouton_Alarme1_Heures_Minutes () { EtatBoutonHeures = digitalRead(BoutonHeures); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures" EtatBoutonMinutes = digitalRead(BoutonMinutes); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes" EtatBoutonAlarme1 = digitalRead(BoutonAlarme1); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes" if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonHeures == LOW)) // si le bouton est appuyé { delay(170); // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut RegleAlarm1Heures (); // et appeller la fonction "RegleMinutes" } if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonMinutes == LOW)) // si le bouton est appuyé { delay(170); // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut RegleAlarm1Minutes (); // et appeller la fonction "RegleMinutes" } } /***** Fonction d'incrément Alarme 1, Heures *******/ void RegleAlarm1Heures () { heuresAlarmeINC = heuresAlarme + 1; // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC" if (heuresAlarmeINC > 23) // si la valeur de "heuresHorlogeINC" dépasse 23 (23h) { heuresAlarmeINC = 0; // alors, et la variable "heuresHorlogeINC" à zero (minuit) } // Serial.print(minutesHorlogeINC); // Serial.println(); RADIO.adjust(AlarmTime1(heuresAlarmeINC,minutesAlarme,0)); // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero } /***** Fonction d'incrément Alarme 1, Minutes *******/ void RegleAlarm1Minutes () { minutesAlarmeINC = minutesAlarme + 1; // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC" if (minutesAlarmeINC > 59) // si la valeur de "minutesHorlogeINC" dépasse 59 (59min) { minutesAlarmeINC = 0; // alors, met la variable "minutesHorlogeINC" à zero } // Serial.print(minutesHorlogeINC); // Serial.println(); RADIO.adjust(AlarmTime1(heuresAlarme,minutesAlarmeINC,0)); // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero } /***** Régler l'Alarme 2 : Fonction Surveillance des BoutonAlarme2, BoutonMinutes et BoutonHeures *******/ void SurveilleBouton_Alarme2_Heures_Minutes () { EtatBoutonHeures = digitalRead(BoutonHeures); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures" EtatBoutonMinutes = digitalRead(BoutonMinutes); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes" EtatBoutonAlarme2 = digitalRead(BoutonAlarme2); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes" if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonHeures == LOW)) // si le bouton est appuyé { delay(170); // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut RegleAlarm2Heures (); // et appeller la fonction "RegleMinutes" } if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonMinutes == LOW)) // si le bouton est appuyé { delay(170); // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut RegleAlarm2Minutes (); // et appeller la fonction "RegleMinutes" } } /***** Fonction d'incrément Alarme 2, Heures *******/ void RegleAlarm2Heures () { heuresAlarmeINC = heuresAlarme + 1; // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC" if (heuresAlarmeINC > 23) // si la valeur de "heuresHorlogeINC" dépasse 23 (23h) { heuresAlarmeINC = 0; // alors, et la variable "heuresHorlogeINC" à zero (minuit) } // Serial.print(minutesHorlogeINC); // Serial.println(); REVEIL.adjust(AlarmTime2(heuresAlarmeINC,minutesAlarme)); // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero } /***** Fonction d'incrément Alarme 2, Minutes *******/ void RegleAlarm2Minutes () { minutesAlarmeINC = minutesAlarme + 1; // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC" if (minutesAlarmeINC > 59) // si la valeur de "minutesHorlogeINC" dépasse 59 (59min) { minutesAlarmeINC = 0; // alors, met la variable "minutesHorlogeINC" à zero } // Serial.print(minutesHorlogeINC); // Serial.println(); REVEIL.adjust(AlarmTime2(heuresAlarme,minutesAlarmeINC)); // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero } /***** Fonction Surveillance des BoutonAlarme1 et Horloge *******/ void SurveilleBouton_Alarme1_Horloge () { EtatBoutonAlarme1 = digitalRead(BoutonAlarme1); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme1" EtatBoutonHorloge = digitalRead(BoutonHorloge); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge" if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonHorloge == LOW)) // si les boutons sont appuyé { delay(600); // alors, attendre 600 ms, permet un appuie bref pour activer ou désactiver l'alarme1 (radio) switch (RADIO.Alarm1Flag()) { case 0: // désactivée // 0AH = 0xxxxxxx RADIO.Alarm1SetON(); digitalWrite (LedAlarm1, HIGH); break; case 1: // alarme activée RADIO.Alarm1SetOFF(); digitalWrite (LedAlarm1, LOW); // 0AH = 1xxxxxxx break; } } } /***** Fonction Surveillance des BoutonAlarme2 et Horloge *******/ void SurveilleBouton_Alarme2_Horloge () { EtatBoutonAlarme2 = digitalRead(BoutonAlarme2); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme2" EtatBoutonHorloge = digitalRead(BoutonHorloge); // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge" if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonHorloge == LOW)) // si le bouton est appuyé { delay(600); // alors, attendre 600 ms, permet un appuie bref pour activer ou désactiver l'alarme2 (sonnerie) switch (REVEIL.Alarm2Flag()) { case 0: // alarme désactivée // 0AH = 0xxxxxxx REVEIL.Alarm2SetON(); digitalWrite (LedAlarm2, HIGH); break; case 1: // alarme activée REVEIL.Alarm2SetOFF(); digitalWrite (LedAlarm2, LOW); // 0AH = 1xxxxxxx break; } } } /***** Fonction d'envoie d'ordre au GPIO du Rpi *******/ void RadioON() { if (RADIO.Alarm1Status()==1) { // digitalWrite(relais, HIGH); # fait now par le RPI lui meme digitalWrite(Radio, LOW); delay(300); // appuie bref digitalWrite(Radio, HIGH); // delay(10000); change = 1; } } /***** Fonction d'activation de la sonnerie ChipTune *******/ void FaireSonnerSonnerie() { if (REVEIL.Alarm2Status()==1) { digitalWrite(relais, HIGH); // AmpliAudio alimenté delay(500); // attendre quelques millisec entre chaque bouctle de sonnerie switch (song) { case 1: // A-Team sonnerie(songA); // song = song + 1; break; case 2: // Hallowee sonnerie(songB); // song = song + 1; break; case 3: // Muppets sonnerie(songC); // song = song + 1; break; case 4: // TakeOnMe sonnerie(songD); // song = song + 1; break; case 5: // Gadget sonnerie(songE); // song = song + 1; break; case 6: // MahnaMahna sonnerie(songF); // song = 1; break; default: // cas par défaut sonnerie(songA); break; */ } } } /***** Fonction pour stopper la sonneie *******/ void stop2 () //appelée directement via l'interruption 0 lorsqu'on appuie sur le bouton alarm2 { change = 1; digitalWrite(relais, LOW); // coupe l'alimentation de l'AmpliAudio // Serial.print(change); // } /***** Fonction d'ajustement de la luminosité via la photodiode *******/ void AjusteLuminosite() { ValeurPhotoDiode = analogRead(photodiodepin); // Lit la valeur renvoyée par la photodiode, et stocke la valeur dans la variable "ValeurPhotoDiode" if (ValeurPhotoDiode > 495) // si la valeur est supérieure à 495 (beaucoup de lumière reçue, genre en plein jour) { analogWrite(ledPin, 255); // alors, illumination des afficheurs et leds à 100% (PWM de 0 à 255) } else if (ValeurPhotoDiode > 462) // sinon, si la valeur est supérieure à 462 { analogWrite(ledPin, 238); // alors, illumination des afficheurs et leds moins forte } else if (ValeurPhotoDiode > 429) { analogWrite(ledPin, 221); } else if (ValeurPhotoDiode > 396) { analogWrite(ledPin, 204); } else if (ValeurPhotoDiode > 363) { analogWrite(ledPin, 187); } else if (ValeurPhotoDiode > 330) { analogWrite(ledPin, 170); } else if (ValeurPhotoDiode > 297) { analogWrite(ledPin, 153); } else if (ValeurPhotoDiode > 264) { analogWrite(ledPin, 136); } else if (ValeurPhotoDiode > 231) { analogWrite(ledPin, 119); } else if (ValeurPhotoDiode > 198) { analogWrite(ledPin, 102); } else if (ValeurPhotoDiode > 165) { analogWrite(ledPin, 85); } else if (ValeurPhotoDiode > 132) { analogWrite(ledPin, 68); } else if (ValeurPhotoDiode > 99) { analogWrite(ledPin, 51); } else if (ValeurPhotoDiode > 66) { analogWrite(ledPin, 34); } else if (ValeurPhotoDiode > 33) { analogWrite(ledPin, 17); } else // sinon, (très peu voire pas du tout de lumière reçue, genre dans la nuit) { analogWrite(ledPin, 8); // alors, illumination des afficheurs et leds aux minimum 8 } } /***** Fonction Sonnerie *****/ void sonnerie(char *p) { // Absolutely no error checking in here byte default_dur = 4; byte default_oct = 6; int bpm = 63; int num; long wholenote; long duration; byte note; byte scale; // format: d=N,o=N,b=NNN: // find the start (skip name, etc) while(*p != ':') p++; // ignore name p++; // skip ':' // get default duration if(*p == 'd') { p++; p++; // skip "d=" num = 0; while(isdigit(*p)) { num = (num * 10) + (*p++ - '0'); } if(num > 0) default_dur = num; p++; // skip comma } // Serial.print("ddur: "); Serial.println(default_dur, 10); // get default octave if(*p == 'o') { p++; p++; // skip "o=" num = *p++ - '0'; if(num >= 3 && num <=7) default_oct = num; p++; // skip comma } // Serial.print("doct: "); Serial.println(default_oct, 10); // get BPM if(*p == 'b') { p++; p++; // skip "b=" num = 0; while(isdigit(*p)) { num = (num * 10) + (*p++ - '0'); } bpm = num; p++; // skip colon } // Serial.print("bpm: "); Serial.println(bpm, 10); // BPM usually expresses the number of quarter notes per minute wholenote = (60 * 1000L / bpm) * 4; // this is the time for whole note (in milliseconds) // Serial.print("wn: "); Serial.println(wholenote, 10); // now begin note loop while(*p) { // first, get note duration, if available num = 0; while(isdigit(*p)) { num = (num * 10) + (*p++ - '0'); } if(num) duration = wholenote / num; else duration = wholenote / default_dur; // we will need to check if we are a dotted note after // now get the note note = 0; switch(*p) { case 'c': note = 1; break; case 'd': note = 3; break; case 'e': note = 5; break; case 'f': note = 6; break; case 'g': note = 8; break; case 'a': note = 10; break; case 'b': note = 12; break; case 'p': default: note = 0; } p++; // now, get optional '#' sharp if(*p == '#') { note++; p++; } // now, get optional '.' dotted note if(*p == '.') { duration += duration/2; p++; } // now, get scale if(isdigit(*p)) { scale = *p - '0'; p++; } else { scale = default_oct; } scale += OCTAVE_OFFSET; if(*p == ',') p++; // skip comma for next note (or we may be at the end) // now play the note if(note) { // Serial.print("Playing: "); // Serial.print(scale, 10); Serial.print(' '); // Serial.print(note, 10); Serial.print(" ("); // Serial.print(notes[(scale - 4) * 12 + note], 10); // Serial.print(") "); // Serial.println(duration, 10); tone1.play(notes[(scale - 4) * 12 + note]); delay(duration); tone1.stop(); } else { // Serial.print("Pausing: "); // Serial.println(duration, 10); delay(duration); } } }
- Pour faire l'interface entre l'horloge et la radio, les signaux de commande de l'Arduino opérants en 5 Volts et ceux du Raspberry en 3 Volts, il manque ici une carte d'interface. Elle sera étudié au prochain billet sur le sujet.
Mode l'emploi de l'horloge :
De gauche à droite, les boutons : [Alarme 2] [Alarme 1] [Horloge] [Heures] [Minutes]
- Pour régler l'heure :
Appuyer (bref ou long) sur [Horloge] + [Heures] , et sur [Horloge] + [Minutes]
- Pour régler l'alarme 1 :
Appuyer (bref ou long) sur [Alarme 1] + [Heures] , et sur [Alarme 1] + [Minutes]
- Pour régler l'alarme 2 :
Appuyer (bref ou long) sur [Alarme 2] + [Heures] , et sur [Alarme 2] + [Minutes]
- Pour afficher l'alarme 1 :
Appuyer (bref) sur [Alarme 1]
- Pour afficher l'alarme 2 :
Appuyer (bref) sur [Alarme 2]
- Pour stopper la sonnerie :
Appuyer (bref) sur [Alarme 2]