Часы для любимой тещи.

Жили-были часы. Обычные, стрелочные. И постоянно с ними что-то случалось. То они отставали, то наоборот вперед убегали. И тикали. И ночью их было не видно.

Но у нас же на дворе 21 век! Меняем часы на цифровые. С большими цифрами! Пробег по магазинам показал, что хоть часы с большими цифрами и присутствуют на прилавках, но все поголовно имеют один большой минус: они светятся одной и той же яркостью. В итоге солнечным днем их не видно, а ночью они подобно прожектору слепят всех. Не годится.

Одновременно все магазинные часы требуют полочки или какой-либо ровной горизонтальной поверхности. Опять минус для отдельно взятого дома.

В общем, было решено взять и сделать часы самому.

Из закромов был извлечен большой индикатор, с 256 красными светодиодами, расположенными в 32 ряда по 8 штук. Ссылки на магазин давать не буду, но ищется по ключевому слову HT1632.

Далее была взята Arduino Leonardo (можно взять абсолютно любую ардуинку, её возможности будут использованы процентов на 5). Почему леонарда? Просто потому что  была под рукой.

В качестве хранилки времени был взят наборчик от мастеркита, рядом нашлось пара кнопок и фотодиод. Как их подключать, можно прочитать в предидущем тут https://blog.kiltum.tech/2013/09/22/Многофункциональный-термометропока/

Внимание! Индикатор подключается абсолютно точно так же, как и тут: http://www.lucadentella.it/en/category/ledmatrix_ht1632c/ Расположенные в сети библиотеки с похожими названиями не работают, так как рассчитаны на другую схему подключения.

Самым сложным оказалось найти подходящий корпус. В результате я просто купил подходящий пластмассовый, долго его резал-штукатурил-красил, но так до гламурного состояния и не довел. Опыта мало, ошибок много …

Все это долгое время валялось у меня на столе разобранным, пока я не взял себя за шкирку и не собрал все в одну кучу. Так как схема не просто простая, а очень простая, то я тупо собрал все навесным монтажем.

20131113_141210

Заодно опробовал и клеевой пистолет: вещь! Особенно для монтажа такого уровня.

Итак, что и как соединено по фотографии. Слева – направо.

Снаружи подходит обычный micro-usb кабель. Лично мне оказалось проще всего  обеспечить схему питанием +5В – у меня валяется много зарядок от телефонов.

Далее две кнопки, посаженные на analog in и фотодиод, выведенный на верхнюю поверхность часов.

С батарейкой – это часы реального времени от мастер-кита.

Далее сама ардуинка и провода, уходящие на индикатор.

Внимание! Индикатор в режиме “все включено на максимум” потребляет примерно 300мА. Встроенный в ардуинку стабилизатор попросту не выдержит. В данной схеме я воспользовался грязным хаком и подцепил питание индикатора на VIN. По схеме он зацеплен прямо на +5В от USB, а там предел 500мА. В общем, не повторяйте этого, если не знаете что делаете.

Как вы можете обратить внимание, я там наклеил неодимовых магнитиков. Практика показала, что их хватает для надежного крепления часов к корпусу холодильника в люом удобном месте.

Ну и как же без кода.

#include “Wire.h”
#include “RTClib.h”
#include <avr/pgmspace.h>

// HT1632C PINs

#define DISPLAY_CS 5
#define DISPLAY_WR 6
#define DISPLAY_DATA 7

// HT1632C Commands

#define HT1632C_READ B00000110
#define HT1632C_WRITE B00000101
#define HT1632C_CMD B00000100

#define HT1632_CMD_SYSON 0x01
#define HT1632_CMD_LEDON 0x03
#define HT1632_CMD_PWM 0xA0

// where PIN button is
#define BUTT_H A8
#define BUTT_M A10

int photoRPin = 0; // where photo is
int minLight;
int maxLight;
int lightLevel;
int adjustedLightLevel;
byte display_buffer[32];
long previous_millis;

RTC_DS1307 RTC;

// 7 width 8 – height
PROGMEM char font[] = {
B01111110, // 0
B11111111,
B10000001,
B10000001,
B11111111,
B01111110,

// 1
B01000001,
B11111111,
B11111111,
B00000001,
B00000000,
B00000000,

B01100001,
B11100011, // 2
B10000111,
B10001101,
B11111001,
B01110001,

B01100110, // 3
B11100111,
B10000001,
B10010001,
B11111111,
B01101110,

B11110000,
B11111000, // 4
B00001000,
B00001000,
B11111111,
B11111111,

B11110010,
B11110011, // 5
B10010001,
B10010001,
B10011111,
B10001110,

B01111110,
B11111111, // 6
B10010001,
B10010001,
B11011111,
B01001110,

B10000000, // 7
B10000111,
B10001111,
B10011000,
B11110000,
B11100000,
B01101110,
B11111111, // 8
B10010001,
B10010001,
B11111111,
B01101110,
B01110010,
B11111011, // 9
B10001001,
B10001001,
B11111111,
B01111110,
};

PROGMEM int fontwidth[] = {
6,4,6,6,6,6,6,6,6,6
};

void show_string(String st)
{
ht1632c_clear_display();

int middle=15-1;

show_digit(middle-pgm_read_byte_near(fontwidth+st.charAt(1)-‘0’)-pgm_read_byte_near(fontwidth+st.charAt(0)-‘0’)-1,st.charAt(0)-‘0’);

show_digit(middle-pgm_read_byte_near(fontwidth+st.charAt(1)-‘0’),st.charAt(1)-‘0’);

middle=17+1;

show_digit(middle,st.charAt(2)-‘0’);

show_digit(middle+pgm_read_byte_near(fontwidth+st.charAt(2)-‘0’)+1,st.charAt(3)-‘0’);

}

 

void show_digit(int pos, int digit)
{
for(int i=0;i<pgm_read_byte_near(fontwidth+digit);i++) display_buffer[pos+i]=pgm_read_byte_near(font+digit*6 + i);
}

void show_dots(int on)
{
if(on==1)
{
display_buffer[15]=B01100110;
display_buffer[16]=B01100110;
}
else
{
display_buffer[15]=0;
display_buffer[16]=0;
}
}
// —————————————-
// HT1632C functions
// —————————————-

void ht1632c_clear_display() {
for(int i = 0; i < 32; i++) display_buffer[i] = 0x00;
//ht1632c_display_buffer();
}

void ht1632c_display_buffer() {

digitalWrite(DISPLAY_CS, LOW);
ht1632c_send_bits(HT1632C_WRITE, 1 << 2);
ht1632c_send_bits(0x00, 1 << 6);
for(int i = 0; i < 32; i++) ht1632c_send_bits(display_buffer[i], 1<<7);
digitalWrite(DISPLAY_CS, HIGH);
}

void ht1632c_send_command(byte command) {

digitalWrite(DISPLAY_CS, LOW);
ht1632c_send_bits(HT1632C_CMD, 1 << 2);
ht1632c_send_bits(command, 1 << 7);
ht1632c_send_bits(0, 1);
digitalWrite(DISPLAY_CS, HIGH);
}

void ht1632c_send_bits(byte bits, byte firstbit) {

while(firstbit) {
digitalWrite(DISPLAY_WR, LOW);
if (bits & firstbit) digitalWrite(DISPLAY_DATA, HIGH);
else digitalWrite(DISPLAY_DATA, LOW);
digitalWrite(DISPLAY_WR, HIGH);
firstbit >>= 1;
}
}

void setup()
{
Serial.begin(9600);

pinMode(DISPLAY_CS, OUTPUT);
pinMode(DISPLAY_WR, OUTPUT);
pinMode(DISPLAY_DATA, OUTPUT);

pinMode(BUTT_H,INPUT);
pinMode(BUTT_M,INPUT);
digitalWrite(BUTT_H,HIGH);
digitalWrite(BUTT_M,HIGH);

// enable System oscillator and LED duty cycle generator
ht1632c_send_command(HT1632_CMD_SYSON);
ht1632c_send_command(HT1632_CMD_LEDON);
ht1632c_send_command(HT1632_CMD_PWM+15); // full light!

ht1632c_clear_display();
previous_millis=0;
Wire.begin();
RTC.begin();
RTC.adjust(DateTime(__DATE__, __TIME__));

minLight=200;
maxLight=800;
}

int dig=1000;

String c_to(int dig)
{
String ret(dig);
if(dig<10)
return “0”+ret;
else
return ret;
}

char s;
String txtMsg;

void loop ()
{

while (Serial.available() > 0) {
s=(char)Serial.read();
if (s == ‘n’) {
if(txtMsg.charAt(2)==’:’)
{
DateTime nw = RTC.now();
DateTime nq = DateTime(nw.year(),nw.month(),nw.day(),String(txtMsg.substring(0,2)).toInt(),String(txtMsg.substring(3,5)).toInt(),0);
RTC.adjust(nq);
Serial.println(“Time is changed”);
}
else
{
Serial.println(“To change time, just print current time like ’12:24′”);
}
txtMsg=””;
} else {
txtMsg +=s;
}
}

if(analogRead(BUTT_H)<500)
{
delay(150);
if(analogRead(BUTT_H)<500) // if still pressed
{
DateTime nw = RTC.now();
DateTime nq = DateTime(nw.year(),nw.month(),nw.day(),nw.hour()+1,nw.minute(),nw.second());
RTC.adjust(nq);
previous_millis=millis()-1100;
//delay(100);

}}

if(analogRead(BUTT_M)<500)
{
delay(150);
if(analogRead(BUTT_M)<500) // if still pressed
{
DateTime nw = RTC.now();
DateTime nq = DateTime(nw.year(),nw.month(),nw.day(),nw.hour(),nw.minute()+1,nw.second());
RTC.adjust(nq);
previous_millis=millis()-1100;
//delay(100);

}}

long current_millis = millis();

if(current_millis – previous_millis > 1000) {
previous_millis = current_millis;
// do it

DateTime now = RTC.now();

show_string(String(c_to(now.hour())+c_to(now.minute())));

if((now.second() % 2) == 0)
show_dots(1);
else
show_dots(0);

Serial.print(now.day());
Serial.print(“/”);
Serial.print(now.month(), DEC);
Serial.print(“/”);
Serial.print(now.year(), DEC);
Serial.print(” “);

Serial.print(now.hour(), DEC);
Serial.print(“:”);
Serial.print(now.minute(), DEC);
Serial.print(“:”);
Serial.print(now.second(), DEC);
Serial.print(” l:”);

ht1632c_display_buffer();

// now ajust brightness

lightLevel=analogRead(photoRPin);
// Serial.println(lightLevel);
if(minLight>lightLevel)
{
minLight=lightLevel;
}
if(maxLight<lightLevel)
{
maxLight=lightLevel;
}

//Serial.println(maxLight-minLight);
adjustedLightLevel = map(lightLevel, minLight, maxLight, 0, 15);
Serial.println(adjustedLightLevel);

ht1632c_send_command(HT1632_CMD_PWM+adjustedLightLevel);

}
}

На мой взгляд, ничего ранее не описанного в нем нет (но если что непонятно, то спрашивайте), поэтому я сразу перехожу к готовому результату.

20131113_165232

 

Здесь часы собраны и расположены на испытательном стенде – обычной маркерной доске.

Практика использования в течении пары дней (больше просто времени не было и мы уезжали) показала, что все выбранные решения были верны. Днем часы было видно далеко, а ночью они не слепили. В общем, теперь можно сваять нечто и более монструозное.