Arduino Flip Clock на матрице 8×8 LED — DIY проект реального времени
Компоненты и материалы
| Arduino Nano R3 | ×1 |
| DS3231M — RTC модуль (I2C, ±5 ppm) | ×1 |
| Модуль матрицы 8×8 LED с драйвером MAX7219 | ×1 |
| RGB LED (общий анод) | ×1 |
| Резистор 220 Ом | ×2 |
| Ротационный энкодер с кнопкой | ×1 |
Необходимые инструменты
- Паяльник
Программное обеспечение
- Arduino IDE
О проекте
Эти часы на матрице 8×8 LED разработаны Эдрианом Джонсом. Время отображается прокруткой слева направо (или сверху вниз при изменении параметра). Каждая цифра выезжает справа, останавливается в центре, слегка ярче, затем уходит влево, уступая место следующей.
Для вертикального режима («сверху вниз») измените в коде:
static boolean top2bottom = false;
// на:
static boolean top2bottom = true;
Во многих параметрах можно настраивать: скорость прокрутки, количество пустых строк между символами, 12/24-часовой формат, задержку между символами, яркость и др.
Установка времени производится вращательным энкодером. Двухцветный LED индицирует режим настройки (часы, минуты или нормальный). Корпус состоит из двух половин, обеспечивая удобный доступ к внутренностям.
Код
//*****************************************************************************************//
// MATRIX CLOCK
// Adrian Jones, March 2014
// - позволяет прокрутку слева направо и сверху вниз
//*****************************************************************************************//
#include
#include
#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
#define load 10
#define clock 11
char alphanum[][8] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // пробел
{0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10}, // !
// ... (полная таблица символов опущена для краткости)
{0xE0,0xA0,0xE0,0x80,0x8A,0x15,0x15,0x11} // pm (~)
};
RTC_DS1307 RTC;
#define enc_PinA 2
#define enc_PinB 4
#define enc_Switch 3
#define mode_Pin 8
#define min_Pin 9
unsigned char enc_A, enc_B, enc_A_prev=0;
static boolean rotating = false, clockwise = false, updateFlag = false;
static int mode = 0;
#define max_array_size 100
char ac[max_array_size] = {};
byte rc[8] = {};
String display_message = "";
int arraylen;
#define delay_line 75
#define delay_char 400
#define delay_mess 500
#define cblanks 1
#define eblanks 0
static boolean top2bottom = false;
static boolean hour24 = false;
static boolean charHI = true;
static boolean doSerial = true;
void setup() {
Wire.begin();
Serial.begin(57600);
if(doSerial) Serial.print("MATRIX Clock - Adrian Jones, Mar. 2014");
pinMode(dataIn, OUTPUT); pinMode(clock, OUTPUT); pinMode(load, OUTPUT);
initMatrix();
pinMode(mode_Pin, OUTPUT); digitalWrite(mode_Pin, 1);
pinMode(min_Pin, OUTPUT); digitalWrite(min_Pin, 1);
pinMode(enc_PinA, INPUT_PULLUP); digitalWrite(enc_PinA, HIGH);
pinMode(enc_PinB, INPUT_PULLUP); digitalWrite(enc_PinB, HIGH);
pinMode(enc_Switch, INPUT_PULLUP); digitalWrite(enc_Switch, HIGH);
attachInterrupt(0, rotEncoder, CHANGE);
attachInterrupt(1, swEncoder, CHANGE);
RTC.begin();
if (!RTC.isrunning()) {
RTC.adjust(DateTime(__DATE__, __TIME__));
if(doSerial) Serial.println(" (RTC reset)");
} else {
if(doSerial) Serial.println(" (RTC running)");
}
}
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);
adjTime(now, clockwise);
show_time_and_date(RTC.now());
display_message = createMessage(now);
arraylen = initDisplayString(display_message);
delay(1);
rotating = false;
}
delay(5);
for(int i=0; i < (arraylen-7); i++) {
for(int j=1; j<9; j++) maxSingle(j, ac[i+8-j]);
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);
}
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);
if(mode != 0) rotating = true;
}
enc_A_prev = enc_A;
}
void swEncoder() {
delay(1);
if(digitalRead(enc_Switch) != LOW) return;
delay(1);
if(digitalRead(enc_Switch) != LOW) return;
mode = (mode + 1) % 3;
digitalWrite(mode_Pin, !(mode == 1));
digitalWrite(min_Pin, !(mode == 2));
updateFlag = true;
}
void newDelay(int dly) {
for(int z=1; z= 25) h = 1; }
else { if(h == 0) h = 24; if(--h <= 0) h = 24; }
RTC.adjust(DateTime(now.year(), now.month(), now.day(), h, now.minute(), now.second()));
}
if(mode == 2) {
int m = now.minute();
if(dir) { if(++m >= 60) m = 0; }
else { if(--m < 0) m = 59; }
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), m, 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 dt) {
if(doSerial) {
int h = dt.hour(); if(h==0) h=24;
int m = dt.minute(), s = dt.second();
String te = "Current date/time: " + String(dt.year()) + "/" + dt.month() + "/" + dt.day() + " ";
if(h<10) te += "0"; te += h; te += ":";
if(m<10) te += "0"; te += m; te += ":";
if(s<10) te += "0"; te += s;
Serial.println(te);
}
}
String createMessage(DateTime dt) {
String msg = " ";
int hr = dt.hour() % 24; if(hr==0) hr=24;
int mn = dt.minute();
if(mode == 0) {
if(hour24) msg += hr; else msg += (hr>12? hr-12:hr);
msg += ':'; if(mn<10) msg += '0'; msg += mn;
if(!hour24) msg += (hr>12? "~" : "^");
}
if(mode == 1) msg += hr;
if(mode == 2) { if(mn<10) msg += '0'; msg += mn; }
return msg;
}
int initDisplayString(String message) {
int x=0;
for(int y=0; y0; i--) {
mask = 0x01 << (i-1);
digitalWrite(clock, LOW);
digitalWrite(dataIn, (data & mask) ? HIGH : LOW);
digitalWrite(clock, HIGH);
}
}
Схема подключения
Схема показывает подключение матрицы MAX7219 (DIN=12, CLK=11, CS=10), RTC DS3231 (SDA=A4, SCL=A5), энкодера (A=2, B=4, SW=3) и индикаторных LED (mode=8, min=9).
Производственный процесс
- Arduino POV-часы: сборка дисплея на эффекте сохранения образа
- Ретро-часы на индикаторах Numitron с Arduino: просто, надёжно, экономно
- Создание пользовательских LED-часов с будильником — видно с 12 метров
- Tetris на Arduino Nano: самостоятельная сборка 16×8 LED-матрицы на 74HC595
- MotionSense: умная система обнаружения проникновения на Arduino и ESP8266
- Интерактивный LED-дисплей в двери с PIR-датчиком — новогоднее приветствие на Arduino
- Пошаговое руководство: сборка умного четырёхногого робота на Arduino
- Бесшовное управление яркостью светодиодов с помощью Bolt IoT и Arduino UNO
- Веб-управляемый IoT-индикатор на Arduino, Yaler и IFTTT
- Магнитная левитация на отталкивании с Arduino: Простая схема и DIY-руководство