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 à bascule Arduino avec matrice LED 8×8 – Projet DIY d'horloge temps réel

Composants et fournitures

Composant Quantité
Arduino Nano R3 1
Maxim Integrated DS3231M - ±5ppm, Horloge temps réel I2C 1
Matrice LED 8x8 avec pilote MAX7219 1
LED RGB à cathode commune diffuse 1
Résistance 220 ohms 2
Encodeur rotatif avec bouton poussoir 1

Outils et machines nécessaires

Applications et services en ligne

À propos de ce projet

J'ai construit cette horloge à matrice LED 8x8 développée par Adrian Jones. L'heure est affichée par défilement de gauche à droite, ou, sous contrôle logiciel, de haut en bas. Chaque chiffre de l'heure glisse successivement depuis le côté droit et, une fois centré, s'arrête momentanément en s'éclaircissant légèrement. Il défile ensuite vers la gauche pendant que le chiffre suivant apparaît. Le cycle se répète avec un court délai entre chaque affichage.

Pour le défilement vertical « de haut en bas », vous devez modifier :

static boolean top2bottom = false;

en :

static boolean top2bottom = true;

Comme vous pouvez le voir dans les commentaires du code, de nombreux paramètres peuvent être modifiés : vitesse de défilement, nombre de lignes vides entre les caractères, affichage 12/24 heures, millisecondes entre caractères, luminosité, etc.

L'heure peut être facilement réglée à l'aide d'un encodeur rotatif. Une LED bicolore indique le mode de réglage (minutes, heures ou normal). J'ai placé l'horloge dans une boîte composée de deux pièces de base, ce qui rend l'accès à l'intérieur très pratique.

Horloge à bascule Arduino avec matrice LED 8×8 – Projet DIY d horloge temps réel

Code

code (Arduino)

//*****************************************************************************************// // HORLOGE MATRICE // Adrian Jones, Mars 2014 // // - permet le défilement gauche-droite et haut-bas // //*****************************************************************************************// #include  // bibliothèque I2C-WIRE #include  // bibliothèque RTC // définition des registres et broches de contrôle max7219 #define 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 // CLK char alphanum[][8] ={{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // espace Hex 20 Dec 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}, // I {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,0x10,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}, // a {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 {0x00,0x00,0x40,0x00,0x40,0x40,0x40,0x40}, // i {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}, // u {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} // pm codé comme '~' Hex 7E, Dec 126 }; // définition de l'opération RTC RTC_DS1307 RTC; // Module Tiny RTC (DS1307) (SDA - A4, SCL - A5) // encodeur rotatif, interrupteur et contrôle LED #define enc_PinA 2 // encodeur A sur broche 2 (interruption 0) #define enc_PinB 4 // encodeur B sur broche 4 #define enc_Switch 3 // interrupteur encodeur sur broche 3 (interruption 1) #define mode_Pin 8 // broche LED mode #define min_Pin 9 // broche LED minute unsigned char enc_A, enc_B, enc_A_prev=0; static boolean rotating = false; static boolean clockwise = false; static boolean updateFlag= false; static int mode = 0; // 0 - rien, 1 - réglage heure, 2 - réglage minute // définition des chaînes d'affichage #define max_array_size 100 char ac[max_array_size] = {}; byte rc[8] = {}; String display_message = ""; int arraylen; // paramètres opérationnels #define delay_line 75 // ms entre décalages de ligne #define delay_char 400 // ms entre caractères #define delay_mess 500 // ms entre messages #define cblanks 1 // nombre de lignes vides entre caractères #define eblanks 0 // nombre de lignes vides supplémentaires (au-dessus de 8) à la fin du message // fonctionnalités d'affichage static boolean top2bottom = false; // direction d'affichage (haut-bas ou droite-gauche) static boolean hour24 = false; // affichage 24h ? static boolean charHI = true; // surbrillance caractère entier static boolean doSerial = true; // sortie série ? //*****************************************************************************************// // Configuration initiale //*****************************************************************************************// void setup () { Wire.begin(); Serial.begin(57600); if(doSerial) Serial.print("HORLOGE MATRICE - Adrian Jones, Mar. 2014"); // broches de contrôle matrice LED 8x8 pinMode(dataIn, OUTPUT); pinMode(clock, OUTPUT); pinMode(load, OUTPUT); initMatrix(); // initialiser matrice LED // broches LED pinMode(mode_Pin, OUTPUT); // broche mode digitalWrite(mode_Pin, 1); pinMode(min_Pin, OUTPUT); // broche minute digitalWrite(min_Pin, 1); // contrôle encodeur pinMode(enc_PinA, INPUT_PULLUP); digitalWrite(enc_PinA, HIGH); // broche A encodeur rotatif pinMode(enc_PinB, INPUT_PULLUP); digitalWrite(enc_PinB, HIGH); // broche B encodeur rotatif pinMode(enc_Switch, INPUT_PULLUP);digitalWrite(enc_Switch, HIGH); // interrupteur encodeur attachInterrupt(0, rotEncoder, CHANGE); // réglage heure attachInterrupt(1, swEncoder, CHANGE); // minutes / heures // RTC RTC.begin(); if (! RTC.isrunning()) { RTC.adjust(DateTime(__DATE__, __TIME__)); if(doSerial) Serial.println(" (RTC réinitialisé)"); } else { if(doSerial) Serial.println(" (RTC en marche)"); } } //*****************************************************************************************// // Boucle principale //*****************************************************************************************// void loop () { DateTime now = RTC.now(); // show_time_and_date(now); // 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(now, clockwise); show_time_and_date( RTC.now() ); display_message = createMessage(now); arraylen = initDisplayString(display_message); delay(1); rotating = false; // Réinitialiser le drapeau d'interruption à false } delay(5); for (int i = 0; i < (arraylen-7); i++) { // parcourir le tableau du message, avancer d'un octet à la fois for (int j = 1; j < 9; j++) { maxSingle(j,ac[i+8-j]); } // ligne 1 reçoit ac[i+8], ligne 2 reçoit ac[i+7] etc... ligne 8 reçoit ac[i+0] if(i%(8+cblanks) == 0) { // quand un caractère complet est sur l'affichage... if(charHI) maxSingle(max7219_reg_intensity, 0x01); // ... augmenter la luminosité et arrêter 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ée lors de la rotation de l'encodeur void rotEncoder(){ delay(1); enc_A = digitalRead(enc_PinA); enc_B = digitalRead(enc_PinB); if(!enc_A && enc_A_prev){ // changement d'état clockwise = (!enc_A && enc_B)? true : false; if(mode != 0) rotating = true; } enc_A_prev = enc_A; // Stocker la valeur de A pour la prochaine fois } // fonction swEncoder() : ISR appelée quand le bouton de l'encodeur est pressé void swEncoder(){ delay(1); if(digitalRead (enc_Switch) != LOW) return; // si interrupteur enfoncé delay(1); // anti-rebond if(digitalRead (enc_Switch) != LOW) return; // si interrupteur toujours enfoncé mode++; mode = mode % 3; // incrémenter le mode digitalWrite(mode_Pin, !(mode == 1)); // LED réglage heure digitalWrite(min_Pin, !(mode == 2)); // LED réglage minute updateFlag = true; } // ********************************************************************************** // // ROUTINES OPÉRATIONNELLES // ********************************************************************************** // // fonction newDelay void newDelay (int dly) { for (int z=1; z< dly; z++) { delay(1); if(rotating || updateFlag) break; } } // fonction initMatrix() : initialisation des registres MAX7219 void initMatrix() { maxSingle(max7219_reg_scanLimit, 0x07); // toutes les 8 colonnes utilisées maxSingle(max7219_reg_decodeMode, 0x00); // mode matrice LED (pas 7 seg.) maxSingle(max7219_reg_shutdown, 0x01); // pas en mode arrêt maxSingle(max7219_reg_displayTest, 0x00); // pas en mode test affichage for (int e=1; e<=8; e++) {maxSingle(e,0); } // effacer registres LED (éteindre toutes les LED) maxSingle(max7219_reg_intensity, 0x00); // régler intensité. Plage : 0x00 à 0x0f } // fonction adjTime() : incrémente/décrémente (selon direction encodeur) heures/minutes (selon mode) void adjTime(DateTime now, boolean dir) { if(mode == 1) { // régler heures int adj_hrs = now.hour(); if(dir) { // incrémenter if(++adj_hrs >= 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) { // régler 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° (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: afficher la chaîne de temps et les octets void show_time_and_date(DateTime datetime){ if(doSerial) { int minutes = datetime.minute(); int hours = datetime.hour(); if(hours==0) hours=24; int seconds = 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(hours<10) Serial.print(0); Serial.print(hours,DEC); Serial.print(":"); if(minutes<10) Serial.print(0); Serial.print(minutes,DEC); Serial.print(":"); if(seconds < 10) Serial.print(0); Serial.print(seconds,DEC); Serial.println(""); } } String createMessage(DateTime datetime) { String new_mess = " "; int hr = datetime.hour()%24; if(hr == 0) hr = 24; int mn = datetime.minute(); if(mode == 0) { // Mode normal if(hour24) { new_mess += hr; } else { new_mess += (hr > 12)? hr - 12 : hr; } new_mess += ':'; if(mn < 10) new_mess += '0'; new_mess += mn; if(!hour24) new_mess += (hr > 12)? "~" : "^"; } if(mode == 1) { // Réglage heures new_mess += hr; } if(mode == 2) { // Réglage minutes if(mn < 10) new_mess += '0'; new_mess += mn; } return new_mess; } // fonction initDisplayString() : crée tableau de la chaîne du message avec espaces entre caractères et à la fin int initDisplayString(String message) { int x = 0; for (int y = 0; y < message.length(); y++ ){ char thisCh = message.charAt(y); int ind = int(thisCh) - 0x20; if(!top2bottom) rotChar(thisCh); for (int row = 0; row < 8 + cblanks; row++) { if (row <= 7) { ac[x] = (top2bottom)? alphanum[ind][7-row] : rc[row]; } else { ac[x] = 0; } x++; } } for(int y = 0; y < 7+eblanks; y++) {ac[x] = 0; x++; } // espaces de fin return x; } // fonction maxSingle() : charge données dans registre void maxSingle(byte reg, byte col) { digitalWrite(load, LOW); // début putByte(reg); // spécifier registre putByte(col); // ((data & 0x01) * 256) + data >> 1); // mettre données digitalWrite(load,HIGH); } // fonction putByte() : charge données vers matrice, MSB vers LSB void putByte(byte data) { byte i = 8; byte mask; while(i > 0) { // MSB vers LSB mask = 0x01 << (i - 1); // créer masque bit digitalWrite(clock, LOW); // tick if (data & mask){ // choisir bit digitalWrite(dataIn, HIGH);// envoyer 1 } else { digitalWrite(dataIn, LOW); // envoyer 0 } digitalWrite(clock, HIGH); // tock --i; // passer au bit inférieur } }

Schéma de câblage

Horloge à bascule Arduino avec matrice LED 8×8 – Projet DIY d horloge temps réel

Processus de fabrication

  1. Horloge POV Arduino : Construire un affichage LED à persistance rétinienne
  2. Construire une horloge Numitron rétro avec Arduino : simple, fiable et économe en énergie
  3. Construire une horloge maître LED personnalisée avec alarme – Visible à 12 mètres
  4. Jeu Tetris sur Matrice LED 16×8 DIY avec Arduino Nano
  5. MotionSense : Détection d'intrusion intelligente avec Arduino et ESP8266
  6. Affichage LED matrice interactif porte avec capteur PIR - Salutations fêtes Arduino
  7. Construire un robot quadrupède Arduino intelligent : guide étape par étape
  8. Contrôle fluide de la luminosité LED avec Bolt IoT et Arduino UNO
  9. Créer une jauge IoT connectée au Web avec Arduino, Yaler et IFTTT