Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Arduino Flip Clock met 8×8 LED Matrix – DIY Real-Time Clock Project

Onderdelen en benodigdheden

Arduino Nano R3 × 1
Maxim Integrated DS3231M – ±5ppm, I2C Real-Time Clock × 1
8×8 LED Matrix met MAX7219 driver × 1
RGB Diffused Common Cathode LED × 1
Weerstand 220 ohm × 2
Rotary Encoder met Push-Button × 1

Benodigde tools en machines

Solderbout (generiek)

Apps en online services

Arduino IDE

Over dit project

Ik bouwde deze 8×8 LED Matrix Module Clock, ontwikkeld door Adrian Jones. De tijd wordt weergegeven door te scrollen van links naar rechts, of – onder softwarematige controle – van boven naar beneden. Elk cijfer van de tijd glijdt achtereenvolgens van de rechterkant naar binnen en stopt momentaan in het midden, waarna het iets helderder wordt. Vervolgens scrollt het naar links terwijl het volgende cijfer in beeld komt. De cyclus herhaalt zich met een korte pauze tussen opeenvolgende weergaves.

Voor verticaal omvliegen (top to bottom) moet je de volgende regel wijzigen:

static boolean top2bottom = false;

naar:

static boolean top2bottom = true;

Zoals je in de commentaar van de code kunt zien, zijn veel parameters aanpasbaar: scrollsnelheid, aantal lege regels tussen karakters, 12/24-uurs weergave, milliseconden tussen karakters, helderheid, etc.

De tijd kan eenvoudig ingesteld worden met een rotary encoder. Een tweekleurige LED toont de instelmodus (minuten, uren of normaal). Ik plaatste de klok in een behuizing bestaande uit twee basisstukken, zodat de toegang tot het binnenste heel praktisch is.

Arduino Flip Clock met 8×8 LED Matrix – DIY Real-Time Clock Project

Code

code Arduino

//*****************************************************************************************//
// MATRIX CLOCK
// Adrian Jones, March 2014
// - allows left-to-right and top-to-bottom scrolling
//*****************************************************************************************//
#include <Wire.h> // I2C-WIRE library
#include <RTClib.h> // RTC-Library

// define max7219 registers and control pins
#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}, // blank 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 (coded as '^'
  {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 codes as '~' Hex 7E, Dec 126
};

// define RTC operation
RTC_DS1307 RTC; // Tiny RTC (DS1307) module (SDA - A4, SCL - A5)

// rotary encoder, switch and LED control
#define enc_PinA 2 // encoder A to pin 2 (interrupt 0)
#define enc_PinB 4 // encoder B to pin 4
#define enc_Switch 3 // encoder switch to pin 3 (interrupt 1)
#define mode_Pin 8 // mode LED pin
#define min_Pin 9 // minute LED pin

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 - nothing, 1 - hour set, 2 - min set

// define display strings
#define max_array_size 100
char ac[max_array_size] = {};
byte rc[8] = {};
String display_message = "";
int arraylen;

// operational parameters
#define delay_line 75 // ms between line shifts
#define delay_char 400 // ms between characters
#define delay_mess 500 // ms between messages
#define cblanks 1 // number of blank lines between characters
#define eblanks 0 // number of additional blank lines (above 8) at the end of the message

// display features
static boolean top2bottom = false; // display direction (top to bottom, or right to left
static boolean hour24 = false; // 24 hour display?
static boolean charHI = true; // highlight whole character
static boolean doSerial = true; // serial output?

//*****************************************************************************************//
// Initial Setup
//*****************************************************************************************//
void setup () {
  Wire.begin();
  Serial.begin(57600);
  if(doSerial) Serial.print("MATRIX Clock - Adrian Jones, Mar. 2014");
  
  // 8x8 LED matrix control pins
  pinMode(dataIn, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(load, OUTPUT);
  initMatrix(); // initialize LED matrix
  
  // LED pins
  pinMode(mode_Pin, OUTPUT); // mode pin
  digitalWrite(mode_Pin, 1);
  pinMode(min_Pin, OUTPUT); // minute pin
  digitalWrite(min_Pin, 1);
  
  // encoder control
  pinMode(enc_PinA, INPUT_PULLUP);
  digitalWrite(enc_PinA, HIGH); // rotary encoder pin A
  pinMode(enc_PinB, INPUT_PULLUP);
  digitalWrite(enc_PinB, HIGH); // rotary encoder pin B
  pinMode(enc_Switch, INPUT_PULLUP);
  digitalWrite(enc_Switch, HIGH); // encoder switch
  
  attachInterrupt(0, rotEncoder, CHANGE); // time setting
  attachInterrupt(1, swEncoder, CHANGE); // mins / hours
  
  // RTC
  RTC.begin();
  if (! RTC.isrunning()) {
    RTC.adjust(DateTime(__DATE__, __TIME__));
    if(doSerial) Serial.println(" (RTC reset)");
  } else {
    if(doSerial) Serial.println(" (RTC running)");
  }
}

//*****************************************************************************************//
// Main Loop
//*****************************************************************************************//
void loop () {
  DateTime now = RTC.now();
  display_message = createMessage(now);
  arraylen = initDisplayString(display_message);
  
  if(updateFlag) {
    show_time_and_date(now);
    updateFlag = false;
  }
  
  while(rotating) {
    delay(1); // debounce
    adjTime(now, clockwise);
    show_time_and_date( RTC.now() );
    display_message = createMessage(now);
    arraylen = initDisplayString(display_message);
    delay(1);
    rotating = false; // Reset the interrupt flag back to false
  }
  
  delay(5);
  
  for (int i = 0; i < (arraylen-7); i++) {
    for (int j = 1; j < 9; j++) {
      maxSingle(j,ac[i+8-j]);
    }
    // row 1 gets ac[i+8], row 2 gets ac[i+7] etc... row 8 gets ac[i+0]
    
    if(i%(8+cblanks) == 0) {
      if(charHI) maxSingle(max7219_reg_intensity, 0x01);
      newDelay(delay_char);
    } else {
      maxSingle(max7219_reg_intensity, 0x00);
      newDelay(delay_line);
    }
  }
  
  if(mode == 0) newDelay(delay_mess);
}

// ********************************************************************************** //
// INTERRUPT ROUTINES
// ********************************************************************************** //

// function rotEncoder(): ISR called when encoder rotated
void rotEncoder(){
  delay(1);
  enc_A = digitalRead(enc_PinA);
  enc_B = digitalRead(enc_PinB);
  if(!enc_A && enc_A_prev){
    clockwise = (!enc_A && enc_B)? true : false;
    if(mode != 0) rotating = true;
  }
  enc_A_prev = enc_A;
}

// function swEncoder(): ISR called when encoder button pushed
void swEncoder(){
  delay(1);
  if(digitalRead (enc_Switch) != LOW) return;
  delay(1);
  if(digitalRead (enc_Switch) != LOW) return;
  mode++;
  mode = mode % 3;
  digitalWrite(mode_Pin, !(mode == 1));
  digitalWrite(min_Pin, !(mode == 2));
  updateFlag = true;
}

// ********************************************************************************** //
// OPERATION ROUTINES
// ********************************************************************************** //

void newDelay (int dly) {
  for (int z=1; z< dly; z++) {
    delay(1);
    if(rotating || updateFlag) break;
  }
}

void initMatrix() {
  maxSingle(max7219_reg_scanLimit, 0x07);
  maxSingle(max7219_reg_decodeMode, 0x00);
  maxSingle(max7219_reg_shutdown, 0x01);
  maxSingle(max7219_reg_displayTest, 0x00);
  for (int e=1; e<=8; e++) {maxSingle(e,0); }
  maxSingle(max7219_reg_intensity, 0x00);
}

void adjTime(DateTime now, boolean dir) {
  if(mode == 1) {
    int adj_hrs = now.hour();
    if(dir) {
      if(++adj_hrs >= 25) adj_hrs = 1;
    } else {
      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) {
    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() ));
  }
}

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));
    }
  }
}

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 = "Current date/time: ";
    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) {
    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) {
    new_mess += hr;
  }
  if(mode == 2) {
    if(mn < 10) new_mess += '0';
    new_mess += mn;
  }
  return new_mess;
}

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++; }
  return x;
}

void maxSingle(byte reg, byte col) {
  digitalWrite(load, LOW);
  putByte(reg);
  putByte(col);
  digitalWrite(load,HIGH);
}

void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);
    digitalWrite(clock, LOW);
    if (data & mask){
      digitalWrite(dataIn, HIGH);
    } else {
      digitalWrite(dataIn, LOW);
    }
    digitalWrite(clock, HIGH);
    --i;
  }
}

Schema

Arduino Flip Clock met 8×8 LED Matrix – DIY Real-Time Clock Project

Productieproces

  1. Arduino POV-klok: Bouw een Persistence-of-Vision LED-display
  2. Bouw een retro Numitron-klok met Arduino: Eenvoudig, betrouwbaar en energiezuinig
  3. Bouw een Aangepaste LED Hoofdklok met Alarm – Zichtbaar vanaf 12 Meter
  4. Bouw een Tetris-spel met Arduino Nano op een Zelfgemaakte 16×8 LED-matrix
  5. MotionSense: Slimme inbraakdetectie met Arduino en ESP8266
  6. Interactieve LED-matrix deurdisplay met PIR-bewegingsensor – Arduino vakantiegroet
  7. Bouw een Slimme Arduino Vierpotige Robot: Stap-voor-Stap Handleiding
  8. Naadloze LED-dimmer met Bolt IoT en Arduino UNO
  9. Web-IoT Meter Bouwen met Arduino, Yaler en IFTTT
  10. Arduino-gebaseerde Afstotende Magnetische Levitatie: Eenvoudige Schakeling & DIY Handleiding
  11. High-Performance Arduino Weerballon Datalogger