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 matricielle à 7 segments

Composants et fournitures

SparkFun Arduino Pro Mini 328 - 5V/16MHz
× 1
Horloge en temps réel (RTC)
Achetez un "Module d'horloge temps réel DS1302 pour Arduino" et dessoudez la prise ic et le cristal.
× 1
Batterie CR1220 et support
Recherchez "5pcs, boîtier noir CR1220 CR1225 support de prise de pile bouton BS-1220-1"
× 1
Condensateur 0.1uf 1206 SMD
× 1
Condensateur 10uF 1206 SMD Céramique
× 1
Commutateur tactile, actionné par le haut
variante 12 mm avec dessus à boutons
× 4
Module de convertisseur abaisseur mini DC-DC 3A
× 1
Affichage à cathode commune à 4 chiffres et 7 segments de 0,28 in
× 36
MAX7219 DIP IC
× 18
Sonnerie
× 1
En-tête de machine
Vous avez besoin d'en-têtes masculins et féminins - généralement en bandes de 40, vous aurez donc 8 bandes d'hommes broches usinées et 8 bandes de douilles usinées femelles
× 1
Prise de courant CC
Recherchez "Prise d'alimentation 12V DC Connecteur femelle à montage sur panneau 5.5 x 2.ODZ2"
× 1

Outils et machines nécessaires

Fer à souder (générique)
Imprimante 3D (générique)

Applications et services en ligne

Arduino IDE

À propos de ce projet

En parcourant Hackaday.io, je suis tombé sur une belle horloge fabriquée avec une gamme d'affichages à 7 segments par Frugha. Je voulais vraiment le construire, mais la version de Frugha est assez grande car elle utilise des écrans à 7 segments de 0,56". Ma conception utilise des écrans à 7 segments de 0,28", ce qui en fait seulement un quart de la taille.

Le logiciel a été réécrit pour incorporer un réveil et un écran de configuration pour régler l'heure, la date et l'alarme.

Vidéo

Écran de configuration

L'horloge est contrôlée par quatre boutons. Le bouton SELECT (le plus haut) affichera l'écran de configuration. La sélection actuelle clignotera. Appuyez à nouveau sur le bouton SELECT pour faire défiler les différentes sections de configuration (c'est-à-dire l'heure, la date, l'alarme, la syntonisation, la luminosité, le format de la date et l'horloge).

Appuyer sur le bouton ENTER (le 2e en partant du haut) alors qu'un des éléments du menu est sélectionné vous permettra de modifier ses paramètres. Lorsqu'il y a plus d'un paramètre pour un élément de menu, le bouton ENTER passera de l'un à l'autre. Le réglage actif clignotera.

Lorsqu'un réglage clignote, les boutons HAUT et BAS (les deux boutons du bas) modifient le réglage.

Écran de date

Appuyez sur le bouton ENTER (le 2e en partant du haut) pendant que l'horloge est affichée pour afficher l'écran de date pendant cinq secondes.

La section Format de date de l'écran de configuration vous permet de définir le format de date (JJ-MM ou MM-JJ) et la police utilisée.

Considérations de conception

Pour simplifier la conception de la carte, ma version utilise des affichages à 4 chiffres plutôt que les affichages à un chiffre utilisés dans la version originale. Comme les écrans de 0,28" sont petits, j'ai dû mettre les puces MAX7219 sur une carte séparée. Pour un simple câblage, des en-têtes de broches mâles et femelles usinés sont utilisés pour connecter les cartes,

Les fichiers Eagle ont été inclus si vous souhaitez faire fabriquer les planches dans le commerce ou faire comme moi et les fabriquer vous-même. J'ai utilisé la méthode Toner pour faire le mien.

Les planches à colonnes

Six panneaux à colonnes qui contiennent tous les affichages doivent être fabriqués. Lorsque vous soudez les en-têtes mâles de la machine, commencez par l'ensemble central et travaillez jusqu'au bord extérieur. Utilisez une allumette ou quelque chose de similaire pour soulever suffisamment la douille afin de pouvoir souder les broches facilement. Utilisez un petit fer à souder avec une pointe fine et une soudure de 0,5 mm.

Après avoir créé les modules de colonnes, je vous recommande de peindre la bordure de l'écran avec de la peinture noire mate. Cela empêchera les bords blancs de s'afficher si un affichage n'est pas parfaitement aligné avec son voisin. Également à l'aide d'un marqueur, numérotez chaque module de colonne. Cela aide lorsqu'ils sont insérés dans la carte mère MAX7219.

La carte mère MAX7219

Lors de la conception de la carte mère et des panneaux de colonnes, je n'ai pas mappé les segments ou chiffres corrects du MAX7219 sur leurs broches d'affichage correspondantes. Je voulais garder la disposition du PCB aussi simple que possible et m'adapter à toute différence de logiciel.

Je recommande, en ce qui concerne les douilles usinées femelles, de les placer d'abord sur les broches mâles des cartes de colonne, puis de souder l'ensemble en place pendant qu'elles sont connectées. Cela signifie que les broches de la colonne s'aligneront exactement avec leurs prises correspondantes. Si vous devez les supprimer, le fait de numéroter les modules de colonnes garantira qu'ils reviennent dans la même position.

La carte MPU

La carte microprocesseur contient tous les autres composants. Les quatre boutons et les deux condensateurs SMD sont montés à l'arrière de la carte et tous les autres composants sont montés à l'avant de la carte. Pour garder un profil bas, l'en-tête de broche FTDI qui est généralement soudé à l'Arduino Pro Mini est maintenant soudé directement au PCB. Deux fils vont des broches DTR et VCC directement au PCB.

Faire le cas

Les fichiers STL pour le recto et le verso ont été inclus. Les deux ont été imprimés en utilisant une hauteur de couche de 0,2 et un bord. L'avant a également des supports activés qui n'ont touché que la plaque de construction.

La carte mère MAX7219 avec ses modules colonnes se glisse par l'avant. Si vous le trouvez un peu lâche, utilisez une couche ou deux de ruban de masquage comme emballage.

La carte MPU est collée à chaud à l'arrière.

Logiciel

Le logiciel nécessite que la bibliothèque MD_MAX72XX soit installée dans votre IDE Arduino. J'ai fourni mon croquis Hardware_Test_V1 pour les tests. Il éclairera chaque segment afin que vous puissiez vérifier les courts-circuits ou le câblage cassé. Une fois que l'affichage fonctionne, téléchargez le croquis Clock_V4.

Code

  • Clock_V4.ino
  • Chiffres.h
  • Tunes.h
  • Bouton.h
  • Bouton.cpp
  • Hardware_Test_V1.zip
Clock_V4.inoC/C++
/*--------------------------------------------- ------ * Horloge de tableau à 7 segments * * Basé sur l'horloge de Frugha (https://hackaday.io/project/169632-7-segment-display-array-clock) * * Modifications par John Bradnam (jbrad2089@ gmail.com) * - Matériel modifié pour utiliser des écrans de 0,28 "7 segments. * - L'ordre des périphériques, des chiffres et des segments MAX7219 a été modifié pour simplement un routage de carte PCB autrement * complexe. * - Le matériel utilise Arduino Mini Pro, DS1302 RTC et 4 boutons poussoirs * - Fonction d'alarme ajoutée avec alarme sélectionnable * - Réglage de la luminosité ajouté * - Écran de configuration ajouté pour régler l'heure, la date, l'alarme, la musique et la luminosité * - Écran de date ajouté (s'affiche pendant deux secondes lorsque le bouton ENTER est enfoncé * Mise à jour 2020 -06-16 * - Ajout d'une option de format de date sur l'écran de configuration * - Augmentation du délai d'expiration de l'écran de date de 2 à 5 secondes * - Ajout d'un choix de police configurable pour l'affichage de la date *-------------- ------------------------------------*/ #include #include #include # include #include #include "button.h"#include "Tunes.h"#include "Digits.h"#define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW#define MAX_DEVICES 18#define LED_CLK 13 / / ou SCK (WHI)#define LED_DATA 11 // ou MOSI (BRN)#define LED_CS 10 // ou SS (YEL)#define SPEAKER 2#define SW_UP 3#define SW_DOWN 4#define RTC_CLK 5#define RTC_IO 6#define SW_ENTER 7#define RTC_CE 8#define SW_SELECT 9DS1302RTC rtc(RTC_CE, RTC_IO, RTC_CLK);// Interface matérielle SPIMD_MAX72XX mx =MD_MAX72XX(HARDWARE_TYPE, LED_CS, MAX_DEVICES);// Broches arbitraires, LED_MAXTYXX//MD_MAX LED_CLK, LED_CS, MAX_DEVICES);//gestion de l'EEPROM#define EEPROM_ADDRESS 0#define EEPROM_MAGIC 0x0BAD0DADtypedef struct { uint32_t magic; alarme booléenne; uint8_t minutes ; uint8_t heures ; format booléen12hr; uint8_t luminosité ; uint8_t syntoniser ; bool formatDmy; bool squareFont;} EEPROM_DATA;EEPROM_DATA EepromData; //Paramètres EEPROM actuelsvoid clockButtonPressed(void);void enterButtonPressed(void);void downButtonPressed(void);void upButtonPressed(void);Button* clockButton;Button* enterButton;Button* downButton;Button* upButton;//Modes de fonctionnementbool inSubMenu =false;#define SETUP_FLASH_RATE 200;setupTimeout long non signé;bool setupDisplayState =false;enum ClockButtonModesEnum { CLOCK, TIME_SET, DATE_SET, ALARM_SET, TUNE_SET, BRIGHT_SET, FORMAT_SET };ClockButtonModesEnum clockMode =MenuMINEnumTIMESet;enum TimeSet_MenuMINEOUR}TimeSet timeSetMode =TIME_HOUR;enum DateSetMenuEnum { DATE_YEAR, DATE_MONTH, DATE_DAY };DateSetMenuEnum dateSetMode =DATE_YEAR;enum AlarmSetMenuEnum { ALARM_HOUR, ALARM_MIN, ALARM_STATE };AlarmSetMenuEnum alarmSetMode =ALARMONTMenuEnum; -1;bool alarmRinging =false; //true quand l'alarme est activée alarmCancelled =false; //alarme annulée par userbool musicPlaying =false; //true si vous jouez un songbool clockColon =false; //afficher/masquer colonint8_t dom[] ={31,28,31,30,31,30,31,31,30,31,30,31};tmElements_t newTime; // Utilisé pour stocker la nouvelle configuration timevoid () { Serial.begin (115200); //Eprom readEepromData(); //Initialiser les boutons clockButton =new Button(SW_SELECT); enterButton =new Button(SW_ENTER); downButton =nouveau Button(SW_DOWN); downButton->Repeat(downButtonPressed); upButton =nouveau Button(SW_UP); upButton->Repeat(upButtonPressed); //Initialiser le son pinMode(HAUT-PARLEUR,SORTIE); mx.begin(); mx.control(MD_MAX72XX::INTENSITY, EepromData.brightness); //0..MAX_INTENSITY mx.update(MD_MAX72XX::OFF); //Pas de mise à jour automatique setSyncProvider(rtc.get); // la fonction pour obtenir l'heure du RTC if(timeStatus() !=timeSet) { Serial.println("RTC Sync Bad"); newTime.Year =CalendarYrToTm(2020); nouvelleHeure.Mois =5 ; nouvelleHeure.Jour =30 ; nouvelleHeure.Heure =14 ; nouvelleHeure.Minute =53 ; nouvelleHeure.Seconde =0 ; time_t t =makeTime(newTime); setTime(t); rtc.set(t); if (rtc.set(t) !=0) { Serial.println("Échec de la définition de l'heure"); } } newTime.Year =CalendarYrToTm(year()); nouvelleHeure.Mois =mois(); nouvelleHeure.Jour =jour(); nouvelleHeure.Heure =heure(); nouvelleHeure.Minute =minute(); nouvelleHeure.Seconde =seconde(); Serial.println("Time:" + String(newTime.Hour) + ":" + String(newTime.Minute) + ":" + String(newTime.Second)); Serial.println("Date :" + String(newTime.Day) + "/" + String(newTime.Month) + "/" + String(tmYearToCalendar(newTime.Year))); modehorloge =HORLOGE ; showTime(true);}void loop(){ testButtons(); if (clockMode ==CLOCK) { showTime(false); if (EepromData.alarm &&EepromData.hours ==heure() &&EepromData.minutes ==minute()) { if (!alarmCancelled) { alarmRinging =true; playSong(melodies[EepromData.tune]); } } else { alarmCancelled =false; sonnerie d'alarme =faux ; } } else { showSetup(false); } délai(100);}//------------------------------------------ ----------------------//Test si des boutons ont été pressésvoid testButtons(){ //Appuyez une fois sur les boutons if (clockButton->Pressed()) { clockButtonPressed(); } if (enterButton->Pressed()) { enterButtonPressed(); } //Pas besoin de vérifier le résultat de pressé puisque le gestionnaire de bouton invoquera sa fonction de répétition upButton->Pressed(); downButton->Appuyé ();}//--------------------------- -----------------------//Handle CLOCK bttonvoid clockButtonPressed(){ if (cancelAlarm()) return ; inSubMenu =false; clockMode =(clockMode ==FORMAT_SET) ? HORLOGE :(ClockButtonModesEnum)((int)clockMode + 1); if (clockMode ==CLOCK) { Serial.println("Saving Time:" + String(newTime.Hour) + ":" + String(newTime.Minute)); Serial.println(" From:" + String(hour()) + ":" + String(minute())); if (newTime.Year !=CalendarYrToTm(year()) || newTime.Month !=month() || newTime.Day !=day() || newTime.Hour !=hour() || newTime.Minute !=minute()) { //Heure de mise à jour Serial.println("Mise à jour RTC"); nouvelleHeure.Seconde =seconde(); time_t t =makeTime(newTime); setTime(t); rtc.set(t); if (rtc.set(t) !=0) { Serial.println("Échec de la définition de l'heure"); } } writeEepromData(); showTime(true); } else { if (clockMode ==TIME_SET) { newTime.Year =CalendarYrToTm(year()); nouvelleHeure.Mois =mois(); nouvelleHeure.Jour =jour(); nouvelleHeure.Heure =heure(); nouvelleHeure.Minute =minute(); nouvelleHeure.Seconde =seconde(); Serial.println("Heure de chargement :" + String(hour()) + ":" + String(minute())); } showSetup(true); }}//---------------------------------------------- -----------------//Handle ENTER bttonvoid enterButtonPressed(){ if (cancelAlarm()) return ; if (clockMode !=CLOCK) { if (!inSubMenu) { timeSetMode =TIME_HOUR; dateSetMode =DATE_YEAR; alarmSetMode =ALARM_HOUR; formatSetMode =JOUR_MOIS; inSubMenu =vrai; } else { switch (clockMode) { case TIME_SET :timeSetMode =(timeSetMode ==TIME_FORMAT) ? TIME_HOUR :(TimeSetMenuEnum)((int)timeSetMode + 1); Pause; cas DATE_SET :dateSetMode =(dateSetMode ==DATE_DAY) ? DATE_YEAR :(DateSetMenuEnum)((int)dateSetMode + 1); Pause; cas ALARM_SET :alarmSetMode =(alarmSetMode ==ALARM_STATE) ? ALARM_HOUR :(AlarmSetMenuEnum)((int)alarmSetMode + 1); Pause; cas FORMAT_SET :formatSetMode =(formatSetMode ==FONT_STYLE) ? DAY_MONTH :(FormatSetMenuEnum)((int)formatSetMode + 1); Pause; } } showSetup(true); } else { showDate(day(), month(), year()); retard (5000); }}//---------------------------------------------- -----------------//Handle DOWN bttonvoid downButtonPressed(){ if (cancelAlarm()) return ; switch (clockMode) { case TIME_SET:if (inSubMenu) { switch(timeSetMode) { case TIME_HOUR:newTime.Hour =(newTime.Hour + 24 - 1) % 24; Pause; cas TIME_MIN :newTime.Minute =(newTime.Minute + 60 - 1) % 60; Pause; cas TIME_FORMAT :EepromData.format12hr =!EepromData.format12hr; Pause; } showSetup(true); } Pause; case DATE_SET:if (inSubMenu) { switch(dateSetMode) { case DATE_YEAR:newTime.Year =((newTime.Year - 30 + 100) - 1) % 100 + 30; Pause; cas DATE_MONTH :nouvelleHeure.Mois =((nouvelleHeure.Mois - 1 + 12) - 1) % 12 + 1 ; Pause; case DATE_DAY :uint8_t md =daysInMonth(newTime.Year, newTime.Month); newTime.Day =((newTime.Day - 1 + md) - 1) % md + 1; Pause; } showSetup(true); } Pause; case ALARM_SET:if (inSubMenu) { switch(alarmSetMode) { case ALARM_HOUR:EepromData.hours =(EepromData.hours + 24 - 1) % 24 ; Pause; cas ALARM_MIN :EepromData.minutes =(EepromData.minutes + 60 - 1) % 60 ; Pause; cas ALARM_STATE :EepromData.alarm =!EepromData.alarm; Pause; } showSetup(true); } Pause; cas TUNE_SET :EepromData.tune =(EepromData.tune + NUM_OF_MELODIES - 1) % NUM_OF_MELODIES ; showSetup(true); Pause; cas BRIGHT_SET :EepromData.brightness =(EepromData.brightness + MAX_INTENSITY - 1) % MAX_INTENSITY ; mx.control(MD_MAX72XX::INTENSITY, EepromData.brightness); //0..MAX_INTENSITY showSetup(true); Pause; case FORMAT_SET :if (inSubMenu) { switch (formatSetMode) { case DAY_MONTH :EepromData.formatDmy =!EepromData.formatDmy ; Pause; case FONT_STYLE :EepromData.squareFont =!EepromData.squareFont; Pause; } } showSetup(true); Pause; }}//---------------------------------------------- -----------------//Handle UP bttonvoid upButtonPressed(){ if (cancelAlarm()) return ; switch (clockMode) { case TIME_SET:if (inSubMenu) { switch(timeSetMode) { case TIME_HOUR:newTime.Hour =(newTime.Hour + 1) % 24; Pause; cas TIME_MIN :newTime.Minute =(newTime.Minute + 1) % 60; Pause; cas TIME_FORMAT :EepromData.format12hr =!EepromData.format12hr; Pause; } showSetup(true); } Pause; case DATE_SET:if (inSubMenu) { switch(dateSetMode) { case DATE_YEAR:newTime.Year =((newTime.Year - 30) + 1) % 100 + 30; Pause; cas DATE_MONTH :nouvelleHeure.Mois =((nouvelleHeure.Mois - 1) + 1) % 12 + 1 ; Pause; case DATE_DAY :uint8_t md =daysInMonth(newTime.Year, newTime.Month); nouvelleHeure.Jour =(nouvelleHeure.Jour % md) + 1 ; Pause; } showSetup(true); } Pause; case ALARM_SET :if (inSubMenu) { switch(alarmSetMode) { case ALARM_HOUR :EepromData.hours =(EepromData.hours + 1) % 24 ; Pause; cas ALARM_MIN :EepromData.minutes =(EepromData.minutes + 1) % 60 ; Pause; cas ALARM_STATE :EepromData.alarm =!EepromData.alarm; Pause; } showSetup(true); } Pause; cas TUNE_SET :EepromData.tune =(EepromData.tune + 1) % NUM_OF_MELODIES ; showSetup(true); Pause; cas BRIGHT_SET :EepromData.brightness =(EepromData.brightness + 1) % MAX_INTENSITY ; mx.control(MD_MAX72XX::INTENSITY, EepromData.brightness); //0..MAX_INTENSITY showSetup(true); Pause; case FORMAT_SET :if (inSubMenu) { switch (formatSetMode) { case DAY_MONTH :EepromData.formatDmy =!EepromData.formatDmy ; Pause; case FONT_STYLE :EepromData.squareFont =!EepromData.squareFont; Pause; } } showSetup(true); Pause; }}//---------------------------------------------- -----------------//Désactiver l'alarme si elle joue un tunebool cancelAlarm(){ if (musicPlaying) { musicPlaying =false; alarmCancelled =alarmRinging ; renvoie vrai ; } rendement(); return false;}//--------------------------------------------- -------------------//Afficher le menu de configuration et faire clignoter l'élément actuel sélectionnévoid showSetup(bool force){ setupDisplayState =setupDisplayState | Obliger; force =force || (millis()> setupTimeout); if (force) { setupTimeout =millis() + SETUP_FLASH_RATE ; bool on =setupDisplayState; setupDisplayState =!setupDisplayState; mx.clear(); if (on || !(clockMode ==TIME_SET &&!inSubMenu)) displayString(0,7,"TINE"); if (on || !(clockMode ==TIME_SET &&inSubMenu &&timeSetMode ==TIME_HOUR)) displayNumber(0,13,newTime.Hour,2,true); if (on || !(clockMode ==TIME_SET &&inSubMenu &&timeSetMode ==TIME_MIN)) displayNumber(0,16,newTime.Minute,2,true); if (on || !(clockMode ==TIME_SET &&inSubMenu &&timeSetMode ==TIME_FORMAT)) displayString(0,19,(EepromData.format12hr) ? "12HR" :"24HR"); if (on || !(clockMode ==DATE_SET &&!inSubMenu)) displayString(1,7,"DATE"); if (on || !(clockMode ==DATE_SET &&inSubMenu &&dateSetMode ==DATE_YEAR)) displayNumber(1,13,tmYearToCalendar(newTime.Year),4,true); if (on || !(clockMode ==DATE_SET &&inSubMenu &&dateSetMode ==DATE_MONTH)) displayNumber(1,18,newTime.Month,2,true); if (on || !(clockMode ==DATE_SET &&inSubMenu &&dateSetMode ==DATE_DAY)) displayNumber(1,21,newTime.Day,2,true); if (on || !(clockMode ==ALARM_SET &&!inSubMenu)) displayString(2,6,"ALARN"); if (on || !(clockMode ==ALARM_SET &&inSubMenu &&alarmSetMode ==ALARM_HOUR)) displayNumber(2,13,EepromData.hours,2,true); if (on || !(clockMode ==ALARM_SET &&inSubMenu &&alarmSetMode ==ALARM_MIN)) displayNumber(2,16,EepromData.minutes,2,true); if (on || !(clockMode ==ALARM_SET &&inSubMenu &&alarmSetMode ==ALARM_STATE)) displayString(2,19,(EepromData.alarm) ? "ON" :"OFF"); if (on || !(clockMode ==TUNE_SET &&!inSubMenu)) displayString(3,7,"TUNE"); if (on || !(clockMode ==TUNE_SET &&inSubMenu)) { switch(EepromData.tune) { case 0:displayString(3,13,"ELISE"); Pause; cas 1 :displayString(3,13,"RANGE"); Pause; cas 2:displayString(3,13,"SUNSHINE"); Pause; } } if (sur || !(clockMode ==BRIGHT_SET &&!inSubMenu)) displayString(4,1,"BRIGHTNESS"); if (on || !(clockMode ==BRIGHT_SET &&inSubMenu)) displayNumber(4,13,EepromData.brightness,0,false); if (on || !(clockMode ==FORMAT_SET &&!inSubMenu)) displayString(5,0,"DATE ​​FORNAT"); if (on || !(clockMode ==FORMAT_SET &&inSubMenu &&formatSetMode ==DAY_MONTH)) displayString(5,13,(EepromData.formatDmy) ? "DD-NN" :"NN-DD"); if (on || !(clockMode ==FORMAT_SET &&inSubMenu &&formatSetMode ==FONT_STYLE)) displayString(5,19,(EepromData.squareFont) ? "FONT1" :"FONT2"); mx.update(); }}//---------------------------------------------- -----------------//Afficher l'heure actuelle à l'écran si elle est modifiée// force - affiche toujours l'heure même si elle n'est pas modifiéevoid showTime(bool force){ force =force || (dernières secondes !=seconde()); if (force) { lastSeconds =second(); showTime(hour(), minute(), true, true, (second() &0x01), (clockMode !=CLOCK || !EepromData.format12hr)); }}//---------------------------------------------- -----------------//Afficher l'heure sur l'affichage// h - heure// m - minute// he - heure activer // me - minute activer // ce - deux-points activer void showTime(int h, int m, bool he, bool me, bool ce, bool f24){ mx.clear(); if (il) { if (!f24 &&h> 12) { h =h - 12; } if (h> 9 || f24) { displayLargeDigit(0, h / 10); } displayLargeDigit(5, h % 10); } if (moi) { displayLargeDigit(13, m/10); afficherLargeDigit(18, m % 10); } if (ce) { displayLargeDigit (11, 10); } mx.update();}//----------------------------------------- ----------------------- void showDate(int d, int m, int y){ #define XOFS 3 mx.clear(); if (EepromData.formatDmy) { displayDateDigit(XOFS+0, d/10); displayDateDigit(XOFS+4, d % 10); displayDateDigit(XOFS+8, 10); //deux-points displayDateDigit(XOFS+12, m/10); displayDateDigit(XOFS+16, m % 10); } else { displayDateDigit(XOFS+0, m/10); displayDateDigit(XOFS+4, m % 10); displayDateDigit(XOFS+8, 10); //deux-points displayDateDigit(XOFS+12, d/10); displayDateDigit(XOFS+16, d % 10); } displayNumber(5, 10, y, 0, false); mx.update();}//------------------------------------------ ----------------------// Écrivez un chiffre carré ou petit en fonction du paramètre de configuration// x =0 à 23// v =chiffre grand ou carré à display (0..10)void displayDateDigit(uint8_t x, uint8_t v){ if (EepromData.squareFont) { displaySquareDigit(x, v); } else { displaySmallDigit (x, v); }}//---------------------------------------------- -----------------// Écrire un masque de bits de segment// x =0 à 23// v =gros chiffre à afficher (0..10) void displayLargeDigit(uint8_t x , uint8_t v){ if (x <24 &&v <11) { for (uint8_t row =0; row <6; row++) { for (uint8_t col =0; col <6; col++) { writePhysicalDigit(row, col + x, pgm_read_byte(&largeDigits[v][row][col]), false); } } }}//--------------------------------------------- -------------------// Écrire un masque de bits de segment// x =0 à 23// v =grand chiffre à afficher (0..10) void displaySmallDigit( uint8_t x, uint8_t v){ if (x <24 &&v <11) { for (uint8_t row =0; row <5; row++) { for (uint8_t col =0; col <3; col++) { writePhysicalDigit(row, col + x, pgm_read_byte(&smallDigits[v][row][col]), false); } } }}//--------------------------------------------- -------------------// Écrire un masque de bits de segment// x =0 à 23// v =gros chiffre à afficher (0..10) void displaySquareDigit( uint8_t col, uint8_t v){ //Ordre des segments defbca _ g uint8_t mask =ascii[v]; if (mask ==B00000000) { //Masque de trait d'union =B00000001; } if (mask &B00000010) { //seg A writePhysicalDigit (0, col + 0, 0xff, false); writePhysicalDigit (0, col + 1, 0xff, false); writePhysicalDigit (0, col + 2, 0xff, false); } if (mask &B00010000) { //seg B writePhysicalDigit (0, col + 2, 0xff, false); writePhysicalDigit(1, col + 2, 0xff, false); writePhysicalDigit(2, col + 2, 0xff, false); } if (mask &B00001000) { //seg C writePhysicalDigit(2, col + 2, 0xff, false); writePhysicalDigit(3, col + 2, 0xff, false); writePhysicalDigit(4, col + 2, 0xff, false); } if (mask &B10000000) { //seg D writePhysicalDigit (4, col + 0, 0xff, false); writePhysicalDigit(4, col + 1, 0xff, false); writePhysicalDigit(4, col + 2, 0xff, false); } if (mask &B01000000) { //seg C writePhysicalDigit(2, col, 0xff, false); writePhysicalDigit(3, col, 0xff, false); writePhysicalDigit(4, col, 0xff, false); } if (mask &B001000000) { //seg E writePhysicalDigit (0, col, 0xff, false); writePhysicalDigit(1, col, 0xff, false); writePhysicalDigit(2, col, 0xff, false); } if (mask &B00000001) { //seg D writePhysicalDigit(2, col + 0, 0xff, false); writePhysicalDigit(2, col + 1, 0xff, false); writePhysicalDigit(2, col + 2, 0xff, false); }}//---------------------------------------------- -----------------// Écrire la chaîne de caractèresuint8_t displayString(uint8_t row, uint8_t col, String s){ for (int i =0; i 0x5F) { c =0x3F; //Utilisé comme caractère espace } c =c - 0x30; writePhysicalDigit(ligne, col, ascii[c], true); col =col + 1; }}//---------------------------------------------- -----------------// Écrire un nombreuint8_t displayNumber(uint8_t row, uint8_t col, int number, int padding, bool leadZeros){ if (padding ==0) { padding =(nombre> 0) ? étage(log10(nombre)) + 1 :1 ; } col =col + remplissage ; bool d'abord =vrai ; for (int i =0; i > 2) * 3 + (ligne>> 1); uint16_t c =((uint16_t)dev <<3) | digitMap[creuser]; if (!effacer) { v =v | mx.getColumn(c); } mx.setColumn(c, v); }}//---------------------------------------------- -----------------//Renvoie les jours d'une année et d'un mois donnés//Feb a 28 sauf année bissextile ou au tournant d'un siècleuint8_t daysInMonth(int y, int m) { return dom[m - 1] + ((m ==2 &&(y % 4) ==0 &&(y % 100) !=0) ? 1 :0);}//------- -------------------------------------------------- ------//Écrire la structure EepromData dans EEPROMvoid writeEepromData(){ //Cette fonction utilise EEPROM.update() pour effectuer l'écriture, donc ne réécrit pas la valeur si elle n'a pas changé. EEPROM.put(EEPROM_ADDRESS,EepromData);}//-------------------------------------- -------------------------//Lire la structure EepromData de l'EEPROM, initialiser si nécessaire void readEepromData(){ //Eprom EEPROM.get(EEPROM_ADDRESS, EepromData); //Serial.println("magic:" + String(EepromData.magic, 16) + ", alarm:" + String(EepromData.alarm) + ", time:" + String(EepromData.hours) + ":" + String(EepromData.minutes) + ", 12hr:" + String(EepromData.format12hr) + ", luminosité:" + String(EepromData.brightness)); if (EepromData.magic !=EEPROM_MAGIC) { Serial.println("Initialisation de l'EEPROM ..."); EepromData.magic =EEPROM_MAGIC; EepromData.alarm =false; EepromData.minutes =30 ; EepromData.heures =5 ; EepromData.format12hr =faux ; EepromData.luminosité =8 ; EepromData.tune =0 ; EepromData.formatDmy =false; writeEepromData(); } Serial.println("alarm:" + String(EepromData.alarm) + ", time:" + String(EepromData.hours) + ":" + String(EepromData.minutes) + ", 12hr:" + String(EepromData .format12hr) + ", luminosité:" + String(EepromData.brightness));}//----------------------------- ----------------------------------//Jouer une mélodie playSong(const uint16_t* melody){ //Jouer chaque note de la mélodie jusqu'à ce que la note END_OF_TUNE soit rencontrée musicPlaying =true; int thisNote =0; uint16_t noteRaw =pgm_read_word(&melody[thisNote++]); while (musicPlaying &¬eRaw !=END_OF_TUNE) { testButtons(); rendement(); playNote(noteRaw); noteRaw =pgm_read_word(&melody[thisNote++]); } //pendant le délai (50);}//--------------------------------------- -------------------------//Jouer une seule notevoid playNote(uint16_t noteRaw){ // pour calculer la durée de la note, prenez une seconde divisée par le type de note. // par exemple. noire =1000 / 4, croche =1000/8, etc. fréquence uint16_t =noteRaw &0x1FFF; uint16_t duration =(noteRaw &0xE000)>> 13; if (duration ==7) duration =8; uint16_t noteDuration =1800 / duration; if (frequency !=REST) { tone(SPEAKER, frequency, noteDuration); } // to distinguish the notes, set a minimum time between them. // the note's duration + 30% seems to work well:uint16_t pauseBetweenNotes =(noteDuration * 13) / 10; delay(pauseBetweenNotes); if (frequency !=REST) { // stop the tone playing:noTone(SPEAKER); }}
Digits.hC/C++
/*--------------------------------------------------- * 7 Segment array clock * define each digit in a 6x6 byte array *--------------------------------------------------*/ #pragma once//---------------------------------------------------// Standard MAX7219 wiring// Digit order 0,1,2,3,4,5/*// Segment order _ a b c d e f g#define _______ B00000000#define __cd___ B00011000#define _bcde_g B00111101#define abcdefg B01111111#define __cdefg B00011111#define __c____ B00010000#define ab__efg B01100111#define abcd_fg B01111011#define abcde_g B01111101#define ab_defg B01101111#define _bc____ B00110000#define a__defg B01001111#define ____ef_ B00000110#define ___defg B00001111#define abc__fg B01110011#define a___ef_ B01000110#define _b_____ B00100000#define ab___f_ B01100010#define _bcd___ B00111000#define a___ef_ B01000110#define ab_____ B01100000#define ____e__ B00000100#define __cde_g B00011101#define a____f_ B01000010#define a_cdefg B01011111#define ___de__ B00001100#define _____f_ B00000010#define ab___fg B01100011#define a__def_ B01001110#define __cde__ B00011100#define a___efg B01000111#define a__d___ B01001000#define abc____ B01110000#define _bc_ef_ B00110110#define ___def_ B00001110#define abc_ef_ B01110110#define _bcdef_ B00111110#define a__def_ B01001110#define abcd___ B01111000*///Segment order d e f b c a _ g#define _______ B00000000#define __cd___ B10001000#define _bcde_g B11011001#define abcdefg B11111101#define __cdefg B11101001#define __c____ B00001000#define ab__efg B01110101#define abcd_fg B10111101#define abcde_g B11011101#define ab_defg B11110101#define _bc____ B00011000#define a__defg B11100101#define ____ef_ B01100000#define ___defg B11100001#define abc__fg B00111101#define a___ef_ B01100100#define _b_____ B00010000#define ab___f_ B00110100#define _bcd___ B10011000#define a___ef_ B01100100#define ab_____ B00010100#define ____e__ B01000000#define __cde_g B11001001#define a____f_ B00100100#define a_cdefg B11101101#define ___de__ B11000000#define _____f_ B00100000#define ab___fg B00110101#define a__def_ B11100100#define __cde__ B11001000#define a___efg B01100101#define a__d___ B10000100#define abc____ B00011100#define _bc_ef_ B01111000#define ___def_ B11100000#define abc_ef_ B01111100#define _bcdef_ B11111000#define a__def_ B11100100#define abcd___ B10011100//Square Numbers//ASCII Character Set//Numbers 0 - 9//Letters A - Z//Segment order d e f b c a _ guint8_t ascii[] ={ B11111100, B00011000, B11010101, B10011101, B00111001, B10101101, B11101101, B00011100, B11111101, B10111101, B00000000, B00000000, B00000000, B00000001, B00000000, B00000000, B00000000, B01111101, B11101001, B11100100, B11011001, B11100101, B01100101, B10111101, B01111001, B00011000, B11011000, B00000000, B11100000, B00000000, B01001001, B11001001, B01110101, B00000000, B01000001, B10101101, B11100001, B11001000, B00000000, B00000000, B00000000, B10111001, B00000000, B11001100, B01010001, B10011100, B00000000, B10000000};//Digit sequence for each device (MAX7219)uint8_t digitMap[] ={5, 2, 6, 4, 1, 7, 3, 0};//------------------------------------------------------------// Digits using logical coordinates//------------------------------------------------------------const int8_t largeDigits[11][6][6] PROGMEM ={ { //0 { _______, _______, __cd___, _bcde_g, abcdefg, __cdefg }, { _______, __c____, abcdefg, ab__efg, abcd_fg, abcdefg }, { _______, abcde_g, ab_defg, _______, _bc____, a__defg }, { _______, abcdefg, ____ef_, __c____, abcdefg, ____ef_ }, { _______, abcdefg, __cdefg, abcdefg, a___efg, _______ }, { _______, abc__fg, abcdefg, ab__efg, _______, _______ } }, { //1 { _______, _______, _______, __c____, abcdefg, __cdefg }, { _______, _______, _______, abcdefg, abcdefg, ____ef_ }, { _______, _______, _bcde_g, abcdefg, a__defg, _______ }, { _______, _bc____, abcdefg, abcdefg, ____ef_, _______ }, { _______, abcdefg, abcdefg, a___ef_, _______, _______ }, { _b_____, abcdefg, abcdefg, _______, _______, _______ } }, { //2 { _______, _______, __cd___, _bcde_g, abcdefg, __cdefg }, { _______, _bc____, abcdefg, ab___f_, abcd_fg, abcdefg }, { _______, _______, _______, _bcd___, abcdefg, a___ef_ }, { _______, _______, _bcde_g, abcdefg, a___ef_, _______ }, { __c____, abcdefg, abcdefg, a___ef_, _______, _______ }, { _b_____, abc__fg, abcdefg, abcdefg, ab__efg, _______ } }, { //3 { _______, _______, __cd___, abcdefg, abcdefg, __cdefg }, { _______, _b_____, abcdefg, ab___f_, abcd_fg, abcdefg }, { _______, _______, __cd___, _bcde_g, abcdefg, a___ef_ }, { _______, _______, ab_____, abc__fg, abcdefg, ____e__ }, { _______, __cd___, __cde_g, _bcde_g, abcdefg, ____ef_ }, { _b_____, abc__fg, abcdefg, abcdefg, a____f_, _______ } }, { //4 { _______, _______, _bcd___, abcdefg, __c____, abcdefg }, { _______, __c____, abcdefg, a___ef_, abcde_g, a__defg }, { _______, abcde_g, abcdefg, _bcd___, abcdefg, ____ef_ }, { __c____, abcdefg, abcdefg, abcdefg, abcdefg, _______ }, { _______, _______, __c____, abcdefg, ____ef_, _______ }, { _______, _______, abcdefg, ab__efg, _______, _______ } }, { //5 { _______, _______, _bcde_g, abcdefg, abcdefg, abcdefg }, { _______, _bc____, abcdefg, a_cdefg, ___de__, _______ }, { _______, _______, abc__fg, abcdefg, abcdefg, ____ef_ }, { _______, _______, _______, _bc____, abcdefg, ____ef_ }, { _______, __cde_g, __cde_g, _bcde_g, abcdefg, _____f_ }, { _b_____, abcdefg, abcdefg, ab__efg, a____f_, _______ } }, { //6 { _______, _______, _______, __cd___, abcdefg, ____ef_ }, { _______, _______, _bcde_g, abcdefg, a____f_, _______ }, { _______, _bcd___, abcdefg, abcdefg, abcdefg, ____e__ }, { __c____, abcdefg, a___ef_, ab_____, abcdefg, ____ef_ }, { _bc____, abcdefg, __cdefg, _bcde_g, abcdefg, _______ }, { _______, abc__fg, abcdefg, ab__efg, _______, _______ } }, { //7 { _______, _bc____, abcdefg, abcdefg, abcdefg, __cdefg }, { _______, _b_____, ab___fg, ab___fg, abcdefg, abcdefg }, { _______, _______, _______, _bcde_g, abcdefg, a___ef_ }, { _______, _______, _bcde_g, abcdefg, ab__efg, _______ }, { _______, _bcde_g, abcdefg, a___ef_, _______, _______ }, { _b_____, abcdefg, abcdefg, _______, _______, _______ } }, { //8 { _______, _______, __cd___, abcdefg, abcdefg, __cdefg }, { _______, _bc____, abcdefg, ab___f_, abcd_fg, abcdefg }, { _______, _b_____, abcdefg, _bcde_g, abcdefg, a___ef_ }, { _______, _bcde_g, ab__efg, abc__fg, abcdefg, ____e__ }, { _bc____, abcdefg, __cde_g, _bcde_g, abcdefg, ____ef_ }, { _______, abc__fg, abcdefg, abcdefg, a____f_, _______ } }, { //9 { _______, _______, __cde_g, abcdefg, __cdefg, ___de__ }, { _______, _bcd___, abcdefg, ab___fg, abcd_fg, abcdefg }, { _______, abcdefg, a_cdefg, __cde__, abcdefg, a__defg }, { _______, ab_____, abcd_fg, abcdefg, abcdefg, _____f_ }, { _______, __cd___, abcdefg, ab__efg, _______, _______ }, { _b_____, abcdefg, a___ef_, _______, _______, _______ } }, { //Colon { _______, _______, _______, _______, _______, _______ }, { _______, __cde_g, _______, _______, _______, _______ }, { _______, _______, _______, _______, _______, _______ }, { _______, _______, _______, _______, _______, _______ }, { __cde_g, _______, _______, _______, _______, _______ }, { _______, _______, _______, _______, _______, _______ } }};const int8_t smallDigits[11][5][3] PROGMEM ={ { //0 { a___ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { _bc_ef_, _______, _bc_ef_ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bcd___ } }, { //1 { _______, abc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bcdef_, _______ } }, { //2 { a__def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { a___ef_, a__d___, _bcd___ }, { _bc_ef_, _______, _______ }, { ___def_, a__d___, abcd___ } }, { //3 { a__def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { _______, a__def_, _bc____ }, { _______, _______, _bc_ef_ }, { a__def_, a__d___, _bcd___ } }, { //4 { abc_ef_, _______, abc_ef_ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bc____ }, { _______, _______, _bc_ef_ }, { _______, _______, _bcdef_ } }, { //5 { a___ef_, a__d___, abcd___ }, { _bc_ef_, _______, _______ }, { ___def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { a__def_, a__d___, _bcd___ } }, { //6 { a___ef_, a__d___, abcd___ }, { _bc_ef_, _______, _______ }, { ____ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bcd___ } }, { //7 { a__def_, a__d___, abc____ }, { _______, _______, _bc_ef_ }, { _______, _bc_ef_, _______ }, { _______, _bc_ef_, _______ }, { _______, _bcdef_, _______ }, }, { //8 { a___ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { ____ef_, a__d___, _bc____ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bcd___ } }, { //9 { a___ef_, a__d___, abc____ }, { _bc_ef_, _______, _bc_ef_ }, { ___def_, a__d___, _bc____ }, { _______, _______, _bc_ef_ }, { a__def_, a__d___, _bcd___ } }, { //Hyphen { _______, _______, _______ }, { _______, _______, _______ }, { a__def_, a__d___, abcd___ }, { _______, _______, _______ }, { _______, _______, _______ } }};
Tunes.hC/C++
No preview (download only).
Button.hC/C++
/*Class:ButtonAuthor:John Bradnam ([email protected])Purpose:Arduino library to handle buttons*/#pragma once#include "Arduino.h"#define DEBOUNCE_DELAY 10//Repeat speed#define REPEAT_START_SPEED 500#define REPEAT_INCREASE_SPEED 50#define REPEAT_MAX_SPEED 50class Button{ public://Simple constructor Button(int pin); Button(int name, int pin); Button(int name, int pin, int analogLow, int analogHigh, bool activeLow =true); //Background function called when in a wait or repeat loop void Background(void (*pBackgroundFunction)()); //Repeat function called when button is pressed void Repeat(void (*pRepeatFunction)()); //Test if button is pressed bool IsDown(void); //Test whether button is pressed and released //Will call repeat function if one is provided bool Pressed(); //Return button state (HIGH or LOW) - LOW =Pressed int State(); //Return button name int Name(); private:int _name; int _pin; bool _range; int _low; int _high; bool _activeLow; void (*_repeatCallback)(void); void (*_backgroundCallback)(void);};
Button.cppC/C++
/*Class:ButtonAuthor:John Bradnam ([email protected])Purpose:Arduino library to handle buttons*/#include "Button.h"Button::Button(int pin){ _name =pin; _pin =pin; _range =false; _low =0; _high =0; _backgroundCallback =NULL; _repeatCallback =NULL; pinMode(_pin, INPUT_PULLUP);}Button::Button(int name, int pin){ _name =name; _pin =pin; _range =false; _low =0; _high =0; _backgroundCallback =NULL; _repeatCallback =NULL; pinMode(_pin, INPUT_PULLUP);}Button::Button(int name, int pin, int analogLow, int analogHigh, bool activeLow){ _name =name; _pin =pin; _range =true; _low =analogLow; _high =analogHigh; _activeLow =activeLow; _backgroundCallback =NULL; _repeatCallback =NULL; pinMode(_pin, INPUT);}//Set function to invoke in a delay or repeat loopvoid Button::Background(void (*pBackgroundFunction)()){ _backgroundCallback =pBackgroundFunction;}//Set function to invoke if repeat system requiredvoid Button::Repeat(void (*pRepeatFunction)()){ _repeatCallback =pRepeatFunction;} bool Button::IsDown(){ if (_range) { int value =analogRead(_pin); return (value>=_low &&value <_high); } else { return (digitalRead(_pin) ==LOW); }}//Tests if a button is pressed and released// returns true if the button was pressed and released// if repeat callback supplied, the callback is called while the key is pressedbool Button::Pressed(){ bool pressed =false; if (IsDown()) { unsigned long wait =millis() + DEBOUNCE_DELAY; while (millis() =time) { _repeatCallback(); unsigned long faster =speed - REPEAT_INCREASE_SPEED; if (faster>=REPEAT_MAX_SPEED) { speed =faster; } time =millis() + speed; } } pressed =true; } } return pressed;}//Return current button stateint Button::State(){ if (_range) { int value =analogRead(_pin); if (_activeLow) { return (value>=_low &&value <_high) ? LOW :HIGH; } else { return (value>=_low &&value <_high) ? HIGH :LOW; } } else { return digitalRead(_pin); }}//Return current button nameint Button::Name(){ return _name;}
Hardware_Test_V1.zipC/C++
Hardware test sketch - Turns on all segments and tests speaker
No preview (download only).

Pièces et boîtiers personnalisés

Schémas

Schematic for each MAX7219 (repeated 18 times) Holds six 7 segment 4 digit displays (6 boards required) PCB files in Eagle format eagle_files_KPhUOj6Ezv.zip

Processus de fabrication

  1. horloge de vision Arduino pov
  2. Horloge de mots simple (Arduino)
  3. Horloge Arduino avec heures de prière islamique
  4. horloge maîtresse
  5. Horloge à bascule Arduino à matrice LED unique
  6. Contrôler une matrice LED avec Arduino Uno
  7. eDOT - Horloge de précision et station météo basée sur Arduino
  8. Mini radar avec Arduino
  9. Réveil simple avec DS1302 RTC