Время на этих необычных часах высвечивается всего 30-ю светодиодами. Есть узнаваемый часовой круг и после предварительной тренировки можно понять сколько времени :))
Сейчас на часах 5 часов 46 минут.
Круг показывает часы, верхний экран — десятки минут, а нижний — минуты.
Часы используют внутренний таймер ардуино.
Тестирование показало точность не хуже ±1мин в трое суток.
Главная особенность этих часов в том, что как понятно — у ардуино просто не хватит портов для управления 30-ю светодиодами .
Поэтому, автор использовал оригинальную технику под названием Charlieplexing
В данном случае, для подключения 30 светодиодов потребуется (X=N*(N-1)) — всего 6 портов!
Есть и минус этой техники — отображние будет динамическим, т.е. диод будет светиться только маленький квант времени. Но из-за инертности восприятия глаза, наблюдателю будет казаться, что диод светиться постоянно.
Технология Charlieplexing
Если подать «1» Pin 1 и «0» на Pin 2, будет гореть светодиод Led 1. Светодиод Led 2 в этом случае светиться не будет. Если поменять полярность, то будет гореть Led 2.
Cхема ниже показывает, как экономятся порты — с помощью трех портов можно управлять шестью светодиодами:

Для отсоединения порта от схемы используется третье состояние порта — он включается «на вход».
Для arduino есть специальная библиотека для реализации принципа работы charlielexing.
Для изготовления автор использовал ProtoShield
Разводка платы:

Вид на светодиоды:

Монтаж

Прототип

скетч:
#include <Charlieplex.h>
unsigned long lastTick = 0, frameTick = 0, setTick = 0, cur_millis;//
int hour=0, minute=0, second=0; //start the time on 00:00:00
int munit, ihour, idecmin, iunitmin;
int frameNum = 0;
boolean ch = true, sets = false; //
#define NUMBER_OF_PINS 6
//define pins in the order you want to adress them
byte pins[] = {7,8,9,10,11,12};
#define PIN_SET_HOURS 5 // button for set hours
#define PIN_SET_MINS 6 // button for set minutes
//initialize object for the Charlieplexing
Charlieplex charlieplex = Charlieplex(pins,NUMBER_OF_PINS);
// pins in pairs for the hours
charliePin leds_hours[12] = {
{4, 5}, {4, 3}, {5, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}, {5, 4}, {0, 5}, {1, 5} , {2, 5}, {3, 5}
};
// pins in pairs for the decades of minutes
charliePin leds_decmin[5] = {
{2, 3}, {1, 3}, {0, 3}, {5, 2}, {4, 2}
};
// pins in pairs for the minutes
charliePin leds_min[9] = {
{3, 2}, {1, 2}, {0, 2}, {5, 1}, {4, 1}, {3, 1}, {2, 1}, {0, 1}, {5,0}
};
// pins in pairs for the alarms
charliePin leds_alarm[4] = {
{1, 0}, {2, 0}, {3, 0}, {4, 0}
};
void setup(){
ch = true;
lastTick = 0;
setup_sets;
}
void loop(){
cur_millis = millis(); // current time count
if (cur_millis - lastTick >= 1000) {
lastTick = cur_millis;
second++;
}
// move forward one minute every 60 seconds
if (second >= 60) {
minute++;
second = 0; // reset seconds to zero
ch = true; // flag of change in status of leds
}
// move forward one hour every 60 minutes
if (minute >=60) {
hour++;
minute = 0; // reset minutes to zero
}
if (hour >=12) {
hour=0;
minute = 0; // reset minutes to zero
}
if (ch) { // flag of change in status of leds
ihour = hour;
munit = minute%10;
iunitmin = munit-1;
idecmin = (minute - munit) / 10 - 1;
ch = false;
}
if (cur_millis - frameTick >= 1) { // shift of frame
frameTick = cur_millis;
frameNum++;
if (frameNum > 2) {
frameNum = 0;
}
charlieplex.clear(); // clear all
switch (frameNum) {
case 0: // show 0 frame
showpin(leds_hours[ihour]);
break;
case 1: // show 1 frame
if (idecmin >=0) {
showpin(leds_decmin[idecmin]);
}
break;
case 2: // show 2 frame
if (iunitmin >=0 ) {
showpin(leds_min[iunitmin]);
}
break;
}
}
check_sets();
}
void showpin(charliePin pin) {
charlieplex.charlieWrite(pin, HIGH);
}
void setup_sets(void) {
pinMode(PIN_SET_HOURS, INPUT);
pinMode(PIN_SET_MINS, INPUT);
}
void check_sets(void) { // check status of the buttons
if (sets) { // if in status of set then delay
if (cur_millis - setTick >= 300) {
sets = false;
setTick = 0;
}
} else {
if (digitalRead(PIN_SET_HOURS) == HIGH) {
hour++; sets = true; ch = true; setTick = cur_millis;
}
if (digitalRead(PIN_SET_MINS) == HIGH) {
minute++; sets = true; ch = true; setTick = cur_millis;
}
}
}
