Horloge à bascule Arduino à matrice LED unique
Composants et fournitures
| | × | 1 | |
| Maxim Integrated DS3231M - ±5 ppm, horloge temps réel I2C | | × | 1 | |
| Matrice Led 8x8 avec pilote MAX7219 | | × | 1 | |
| Cathode commune diffuse RVB | | × | 1 | |
| | × | 2 | |
| Encodeur rotatif avec bouton-poussoir | | × | 1 | |
Applications et services en ligne
À propos de ce projet
Je construis ce module de matrice de LED 8x8 HORLOGE développé par Adrian Jones. Le temps est affiché en faisant défiler de gauche à droite, ou, sous contrôle logiciel, de haut en bas. Chaque chiffre de l'heure glisse successivement du côté droit et lorsqu'il est centré, s'arrête momentanément et s'éclaircit légèrement. Il défile ensuite vers la gauche tandis que le chiffre suivant de l'affichage défile. Le cycle se répète avec un court délai entre les affichages successifs. Pour le retournement vertical "de haut en bas", vous devez changer :
booléen statique top2bottom =false ;
à :
statique booléen top2bottom =true;
Comme vous pouvez le voir dans les commentaires du code, de nombreux paramètres peuvent être modifiés, par exemple la vitesse de défilement, le nombre de lignes vides entre les caractères, l'affichage 12/24 heures, les ms entre les caractères, la luminosité etc.
L'heure peut être facilement réglée à l'aide d'un encodeur rotatif. Une diode bicolore affiche le mode de réglage (minutes, heures ou normal). très pratique et pratique.
Code
codeArduino
//************************************************ ******************************************** //// HORLOGE MATRICE // Adrian Jones, mars 2014 //// - permet le défilement de gauche à droite et de haut en bas ////************************ ******************************************************** ******************//#include // Bibliothèque I2C-WIRE#include // RTC-Library// définit max7219 registres et les broches de commande # définissent max7219_reg_noop 0x00 #define max7219_reg_digit0 0x01 #define max7219_reg_digit1 0x02 #define max7219_reg_digit2 0x03 #define max7219_reg_digit3 0x04 #define max7219_reg_digit4 0x05 #define max7219_reg_digit5 0x06 #define max7219_reg_digit6 0x07 #define max7219_reg_digit7 0x08 #define max7219_reg_decodeMode 0x09 #define max7219_reg_intensity 0x0A #define max7219_reg_scanLimit 0x0b#define max7219_reg_shutdown 0x0c#define max7219_reg_displayTest 0x0f#define dataIn 12 // DIN#define load 10 // CS #define clock 11 // CLKchar alphanum[][8] ={{0x00,0x00,0x00,0x00,0x00,0x00 ,0x00,0x00}, // Hex vide 20 déc. 32 {0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10}, // ! 33 {0x00,0x28,0x28,0x28,0x00,0x00,0x00,0x00}, // " 34 {0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00}, // # 35 {0x10,0x38, 0x50,0x38,0x14,0x54,0x38,0x10}, // $ {0x41,0xA2,0x44,0x08,0x10,0x22,0x45,0x82}, // % {0x38,0x44,0x44,0x38,0x50,0x4A, 0x44,0x3A}, // &{0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00}, // ' {0x30,0x40,0x80,0x80,0x80,0x80,0x40,0x30}, // ( 40 {0xC0,0x20,0x10,0x10,0x10,0x10,0x20,0xC0}, // ) {0x28,0x10,0xAA,0x54,0xAA,0x10,0x28,0x00}, // * {0x00,0x10,0x10, 0x10,0xFE,0x10,0x10,0x10}, // + {0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10}, // , {0x00,0x00,0x00,0x00,0x7E,0x00,0x00, 0x00}, // - {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18}, // .{0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}, // / {0x7E ,0xC1,0xA1,0x91,0x89,0x85,0x83,0x7E}, // 0 {0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x7C}, // 1 {0x38,0x44,0x82,0x04,0x18 ,0x20,0x40,0xFE}, // 2 50 {0x7C,0x82,0x02,0x3C,0x02,0x02,0x82,0x7C}, // 3 {0x08,0x18,0x28,0x48,0xFE,0x08,0x08,0x08} , // 4 {0xFE,0x80,0xF8,0x04,0x02,0x82,0x44,0x38}, // 5 {0x38,0x44,0x80,0xB8,0xC4 ,0x82,0x44,0x38}, // 6 {0xFE,0x02,0x04,0x08,0x10,0x20,0x20,0x20}, // 7 {0x7C,0x82,0x82,0x7C,0x82,0x82,0x82,0x7C}, // 8 {0x7C,0x82,0x82,0x7E,0x02,0x82,0x44,0x38}, // 9 {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x00}, // :{0x00,0x00, 0x18,0x18,0x00,0x18,0x18,0x30}, //; {0x00,0x10,0x20,0x40,0x80,0x40,0x20,0x10}, // <60 {0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00}, // ={0x00,0x80,0x40, 0x20,0x10,0x20,0x40,0x80}, //> {0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20}, // ? {0x7E,0x81,0x99,0xA1,0xA1,0x9E,0x80,0x7E}, // @ {0x3C,0x42,0x81,0x81,0xFF,0x81,0x81,0x81}, // A {0xFC,0x82,0x81,0xFE ,0x81,0x81,0x82,0xFC}, // B {0x3C,0x42,0x81,0x80,0x80,0x81,0x42,0x3C}, // C {0xFC,0x82,0x81,0x81,0x81,0x81,0x82,0xFC }, // D {0xFE,0x80,0x80,0xFC,0x80,0x80,0x80,0xFE}, // E {0xFE,0x80,0x80,0xFC,0x80,0x80,0x80,0x80}, // F 70 {0x3C ,0x42,0x81,0x80,0x87,0x81,0x42,0x3C}, // G {0x81,0x81,0x81,0xFF,0x81,0x81,0x81,0x81}, // H {0xFE,0x10,0x10,0x10,0x10 ,0x10,0x10,0xFE}, // je {0xFF,0x08,0x08,0x08,0x08,0x88,0x88,0x70}, // J {0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x84}, // K {0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFE}, // L {0x81,0xC3,0xA5,0x99,0x81,0x81,0x81,0x81}, // M {0x81,0xC1, 0xA1,0x91,0x89,0x85,0x83,0x81}, // N {0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C}, // O {0xFC,0x82,0x81,0x82,0xFC,0x80, 0x80,0x80}, // P 80 {0x3C,0x42,0x81,0x81,0x81,0x85,0x42,0x3D}, // Q {0xFC,0x82,0x81,0x82,0xFC,0x84,0x82,0x81}, // R {0x3C,0x42,0x81,0x40,0x3E,0x81,0x42,0x3C}, // S {0xFE,0x10,0x10,0x10,0x10,0x10,0x1 0,0x10}, // T {0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38}, // U {0x82,0x82,0x82,0x82,0x82,0x44,0x28,0x10}, // V {0x81,0x81,0x81,0x81,0x99,0xA5,0xC3,0x81}, // W {0x81,0x42,0x24,0x18,0x18,0x24,0x42,0x81}, // X {0x82,0x44,0x28,0x10 ,0x10,0x10,0x10,0x10}, // Y {0xFF,0x02,0x04,0x08,0x10,0x20,0x40,0xFF}, // Z 90 {0xE0,0x80,0x80,0x80,0x80,0x80,0x80, 0xE0}, // [ {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}, // {0x07,0x01,0x01,0x01,0x01,0x01,0x01,0x07}, // ] {0xE0, 0xA0,0xE0,0xA0,0xAA,0x15,0x15,0x11}, // am (codé comme '^' {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E}, // _ {0x10,0x08, 0x00,0x00,0x00,0x00,0x00,0x00}, // ' {0x00,0x00,0x38,0x04,0x3C,0x44,0x48,0x34}, // un {0x00,0x40,0x40,0x40,0x78,0x44, 0x44,0x38}, // b {0x00,0x00,0x18,0x24,0x40,0x40,0x24,0x18}, // c {0x00,0x04,0x04,0x04,0x3C,0x44,0x44,0x38}, // d 100 {0x00,0x00,0x38,0x44,0x7C,0x40,0x44,0x38}, // e {0x00,0x18,0x20,0x20,0x78,0x20,0x20,0x20}, // f {0x00,0x38,0x44, 0x44,0x38,0x04,0x44,0x38}, // g {0x00,0x40,0x40,0x40,0x78,0x44,0x44,0x44}, // h {0x0 0,0x00,0x40,0x00,0x40,0x40,0x40,0x40}, // je {0x00,0x08,0x00,0x08,0x08,0x08,0x48,0x30}, // j {0x00,0x40,0x40,0x48, 0x50,0x60,0x50,0x48}, // k {0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x20}, // l {0x00,0x00,0x00,0x28,0x54,0x44,0x44,0x44} , // m {0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x44}, // n 110 {0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x38}, // o {0x00, 0x00,0x70,0x48,0x48,0x70,0x40,0x40}, // p {0x00,0x00,0x30,0x48,0x48,0x38,0x08,0x08}, // q {0x00,0x00,0x00,0x30,0x48, 0x40,0x40,0x40}, // r {0x00,0x30,0x48,0x40,0x30,0x08,0x48,0x30}, // s {0x00,0x20,0x70,0x20,0x20,0x20,0x28,0x10}, / / t {0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x38}, // tu {0x00,0x00,0x44,0x44,0x44,0x44,0x28,0x10}, // v {0x00,0x00,0x82 ,0x82,0x82,0x92,0x54,0x28}, // w {0x00,0x00,0x84,0x48,0x30,0x30,0x48,0x84}, // x 120 {0x00,0x48,0x48,0x48,0x38,0x08, 0x48,0x30}, // y {0x00,0x00,0x00,0x7C,0x08,0x10,0x20,0x7C}, // z {0x00,0x30,0x40,0x40,0x80,0x40,0x40,0x30}, // { {0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20}, // | {0x00,0x60,0x10,0x10,0x08,0x10,0x10,0x60}, // } {0xE0,0xA0,0xE0,0x80,0x8A,0x15,0x15,0x11} // code pm comme '~' Hex 7E, déc 126 } ;// définir l'opération RTCRTC_DS1307 RTC ; // Module Tiny RTC (DS1307) (SDA - A4, SCL - A5)// encodeur rotatif, interrupteur et contrôle LED#define enc_PinA 2 // encodeur A vers pin 2 (interruption 0)#define enc_PinB 4 // encodeur B vers broche 4#define enc_Switch 3 // l'encodeur passe à la broche 3 (interruption 1)#define mode_Pin 8 // mode LED pin#define min_Pin 9 // minute LED pinunsigned char enc_A, enc_B, enc_A_prev=0;static boolean rotation =false; booléen statique dans le sens des aiguilles d'une montre =false; booléen statique updateFlag =false; mode int statique =0; // 0 - rien, 1 - heure définie, 2 - min définie// définir les chaînes d'affichage#define max_array_size 100char ac[max_array_size] ={};byte rc[8] ={};String display_message ="";int arraylen; // paramètres opérationnels#define delay_line 75 // ms entre les décalages de ligne#define delay_char 400 // ms entre les caractères#define delay_mess 500 // ms entre les messages#define cblanks 1 // nombre de lignes vides entre les caractères#define eblanks 0 // nombre de lignes vides supplémentaires (au-dessus de 8) à la fin du message// display featuresstatic boolean top2bottom =false; // sens d'affichage (de haut en bas ou de droite à gauchestatic boolean hour24 =false ; // 24 hour display?static boolean charHI =true ; // met en évidence tout le caractèrestatic boolean doSerial =true ; // sortie série ?//*** ******************************************************** ************************************//// La configuration initiale//****** ******************************************************** ********************************* // configuration void () { Wire.begin (); Serial.begin ( 57600); if (doSerial) Serial.print (" MATRIX Clock - Adrian Jones, mars 2014 "); // 8 x 8 broches de contrôle de la matrice LED pinMode (dataIn, OUTPUT); pinMode (clock, OUTPUT); pinMode (load, OUTPUT) ); initMatrix (); // initialise la matrice LED // broches LED pinMode (mode_Pin, OUTPUT); // mode broche digitalWrite (mode_Pin, 1); pinMode (min_Pin, OUTPUT); // minute pin digitalWrite (min_Pin, 1); // contrôle du codeur pinMode (enc_PinA, INPUT_PULLUP); digitalWrite (enc_PinA, HIGH); // codeur rotatif broche A pinMode (enc_PinB, INPUT_PULLUP); digitalWrite (enc_PinB, HIGH); // rotatif codeur broche B pinMode(enc_Switch, INPUT_PULLUP);digitalWrite(enc_Switch, HIGH); // commutateur d'encodeur attachInterrupt(0, rotEncoder, CHANGE); // réglage de l'heure attachInterrupt(1, swEncoder, CHANGE); // minutes / heures // RTC RTC.begin(); if (! RTC.isrunning()) { RTC.adjust(DateTime(__DATE__, __TIME__)); if(doSerial) Serial.println(" (RTC reset)"); } else { if(doSerial) Serial.println(" (RTC en cours d'exécution)"); } } //************************************************ *******************************************//// Boucle principale/ /****************************************************** ******************************************** // boucle vide () { DateTime now =RTC.maintenant(); // show_time_and_date (maintenant); // afficher l'heure display_message =createMessage(now); arraylen =initDisplayString(display_message); if(updateFlag) { show_time_and_date(now); updateFlag =false; } while(rotating) { delay(1); // anti-rebond adjTime (maintenant, dans le sens des aiguilles d'une montre); show_time_and_date( RTC.now() ); display_message =createMessage (maintenant); arraylen =initDisplayString(display_message); retard(1) ; rotation =faux ; // Réinitialise le drapeau d'interruption à false } delay(5); for (int i =0; i <(arraylen-7); i++) { // parcourt le tableau de messages en avançant d'un octet à la fois for (int j =1; j <9; j++) { maxSingle(j,ac [i+8-j]); } // la ligne 1 obtient ac[i+8], la ligne 2 obtient ac[i+7] etc... la ligne 8 obtient ac[i+0] if(i%(8+cblanks) ==0) { / / quand il y a un caractère complet sur l'affichage... if(charHI) maxSingle(max7219_reg_intensity, 0x01); // ... augmente la luminosité et arrête temporairement newDelay(delay_char); } else { // luminosité normale maxSingle(max7219_reg_intensity, 0x00); newDelay(delay_line); } } if(mode ==0) newDelay(delay_mess);}// ********************************* ************************************************* / /// ROUTINES D'INTERRUPTION// ******************************************* *************************************** //// fonction rotEncoder() :ISR appelé quand l'encodeur a tournévoid rotEncoder(){ delay(1); enc_A =digitalRead(enc_PinA); enc_B =digitalRead(enc_PinB); if(!enc_A &&enc_A_prev){ // changement d'état dans le sens horaire =(!enc_A &&enc_B) ? vrai faux; if(mode !=0) rotation =vrai; } enc_A_prev =enc_A; // Stocke la valeur de A pour la prochaine fois }// function swEncoder() :ISR appelé lorsque le bouton de l'encodeur est poussévoid swEncoder(){ delay(1) ; if(digitalRead (enc_Switch) !=LOW) return ; // si le commutateur est enfoncé delay(1) ; // anti-rebond if(digitalRead (enc_Switch) !=LOW) return ; // si le commutateur est toujours enfoncé mode++ ; mode =mode % 3; // incrémente le mode digitalWrite(mode_Pin, !(mode ==1)); // ajustement de l'heure LED digitalWrite(min_Pin, !(mode ==2)); // minute ajuste la LED updateFlag =true;} // ************************************** ******************************************** //// ROUTINES D'OPÉRATION // ************************************************ ******************************** //// function newDelayvoid newDelay (int dly) { for (int z =1 ; z=25) adj_hrs =1; } else { // décrémenter if(adj_hrs ==0) adj_hrs =24; if(--adj_hrs <=0) adj_hrs =24 ; } RTC.adjust(DateTime(now.year(), now.month(), now.day(), adj_hrs, now.minute(), now.second() )); } if(mode ==2) { // ajuste les minutes int adj_mins =now.minute(); if(dir) { if(++adj_mins>=60) adj_mins =0; } else { if(--adj_mins <0) adj_mins =59; } RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), adj_mins, now.second() )); }}// fonction rotChar(char) :pour le caractère char, transpose les bits à 90 degrés. (haut - bas ==> gauche - droite) // et stocke les résultats dans rc[0] - rc[7].byte rotChar(char inLetter) { int ind =int(inLetter) - 0x20; for (int col =0; col <8; col++) { byte mask =0x01 <<(7-col); for (int row =0; row <8; row++) { bitWrite(rc[col], 7-row,(alphanum[ind][row] &mask)); } }} // fonction show_time_and_date :affiche la chaîne d'heure &bytesvoid show_time_and_date(DateTime datetime){ if(doSerial) { int minutes =datetime.minute(); int heures =dateheure.heure(); si(heures==0) heures=24 ; int secondes =datetime.second(); char delim ='/'; char dend =' '; String te ="Date/heure actuelle : " ; te =te + datetime.year() + delim + datetime.month() + delim + datetime.day() + dend; Serial.print(te); if(heures<10) Serial.print(0); Serial.print(heures,DEC); Serial.print(":"); if(minutes<10) Serial.print(0); Serial.print(minutes,DEC); Serial.print(":"); if(secondes <10) Serial.print(0); Serial.print(secondes,DEC); Serial.println(""); } }String createMessage(DateTime datetime) { String new_mess =" "; int hr =datetime.hour()%24; si (heure ==0) heure =24 ; int mn =dateheure.minute(); if(mode ==0) { // Mode normal if(hour24) { new_mess +=hr; } else { new_mess +=(h> 12) ? h - 12 :h ; } nouveau_mess +=':'; if(mn <10) new_mess +='0'; new_mess +=mn; if(!hour24) new_mess +=(hr> 12) ? "~" :"^"; } if(mode ==1) { // Ajustement des heures new_mess +=hr; } if(mode ==2) { // Ajustement des minutes if(mn <10) new_mess +='0'; new_mess +=mn; } return new_mess;}// function initDisplayString() :crée un tableau de chaîne de message avec des blancs entre les caractères et à la fin initDisplayString(String message) { int x =0; for (int y =0; y > 1); // mettre les données digitalWrite(load,HIGH);}// function putByte() :charge les données dans la matrice, MSB en LSB void putByte(byte data) { byte i =8; masque d'octet; while(i> 0) { // MSB vers LSB mask =0x01 <<(i - 1); // crée un masque de bits digitalWrite(clock, LOW); // cocher if (data &mask){ // choisir bit digitalWrite(dataIn, HIGH); // envoyer 1 } else { digitalWrite(dataIn, LOW); // envoie 0 } digitalWrite(clock, HIGH); // tac --i; // passer au bit inférieur }} Schémas