Часы реального времени с последовательным интерфейсом DS1307 – это малопотребляющие полные двоично-десятичные часы-календарь, включающие 56 байтов энергонезависимой статической ОЗУ. Адреса и данные передаются последовательно по двухпроводной двунаправленной шине. Часы-календарь отсчитывают секунды, минуты, часы, день, дату, месяц и год. Последняя дата месяца автоматически корректируется для месяцев с количеством дней меньше 31, включая коррекцию високосного года. Часы работают как в 24-часовом, так и в 12-часовом режимах с индикатором AM/PM. DS1307 имеет встроенную схему наблюдения за питанием, которая обнаруживает перебои питания и автоматически переключается на питание от батареи.
Модуль часов реального времени DS1307 собранный на базе микросхемы DS1307ZN с питание от литиевой батарейки (LIR2032), что позволяет работать автономно в течение длительного времени. Также на модуле, установлена энергонезависимая память EEPROM объемом 32 Кбайт (AT24C32).
Отличительные особенности:
- Подсчет реального времени в секундах, минутах, часах, датах месяца, месяцах, днях недели и годах с учетом высокосности текущего года вплоть до 2100 г.
- 56 байт энергонезависимого ОЗУ для хранения данных
- 2 проводной последовательный интерфейс I2C
- Программируемый генератор прямоугольных импульсов
- Автоматическое определение отключения основного источника питания и подключение резервного
- Потребление не более 500 нA при питании от резервной батареи питания при температуре 25°C
- Возможность поставки в промышленном диапазоне температур: от -40°C до+85°C
Установка и считывание времени производится при помощи регистров согласно следующей таблице:
Для работы с модулем DS1307 под управлением Arduino существуют несколько библиотек, но при использовании микроконтроллера ATtiny2313 использование библиотек не целесообразно из-за малого объема памяти (2 кБ). Следующий пример скетча не использует библиотек, что позволило оптимально использовать память ATtiny2313.
Для примера использования часов реального времени DS1307 можно собрать простые часы, в качестве индикатора будет использован модуль индикатора TM1637 который представляет собой 4-х разрядный семисегментный дисплей на базе драйвера TM1637.
Схема часов
Перед загрузкой скетча рекомендую ознакомится со статьей — ATtiny2313 + Arduino IDE
Часы работают следующим образом — с 0 по 25 и с 30 по 50 секунду индикатор показывает время, точка мигает в такт секундам, далее с 25 по 30 и с 50 по 55 секунду индикатор показывает число и месяц, а с 55 до 59 секунды индикатор показывает ход секунд.
Корректировка времени
// set_time(21,2,3,8,14,20,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59
Для корректировки времени раскомментируйте эту сроку, загрузите скетч, а затем закомментируйте сроку и снова загрузите скетч.
#define SDA 3 // PB3 #define SCL 2 // PB2 #define SQW 4 // PB4 byte bb; void setup(){ DDRB &= ~(1 << SQW);PORTB |= (1 << SQW); // set_time(21,2,3,8,22,21,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59 ds_write(0x07, 0b00010000); // выход SQW, частота 1 Гц delay(500); } void loop() { byte sec = (ds_read(0) & 0x0F) + (((ds_read(0) & 0x70) >> 4) * 10); byte min = (ds_read(1) & 0x0F) + (((ds_read(1) & 0x70) >> 4) * 10); byte hour = ((ds_read(2) & 0x0F) + ((ds_read(2) & 0x70) >> 4) * 10); byte day = (ds_read(3) & 0x0F); byte datat = ((ds_read(4) & 0x0F) + ((ds_read(4) & 0x70) >> 4) * 10); byte mont = ((ds_read(5) & 0x0F) + ((ds_read(5) & 0x70) >> 4) * 10); byte year = ((ds_read(6) & 0x0F) + ((ds_read(6) & 0x70) >> 4) * 10); if(((PINB >> SQW) & 1)==1){bb = 0;}else{bb = 2;} if(sec >= 0 && sec <= 25){print_time(hour *100 + min, bb, 7, 0);} if(sec > 25 && sec <= 30){print_time(datat *100 + mont, 0, 7, 0);} if(sec > 30 && sec <= 50){print_time(hour *100 + min, bb, 7, 0);} if(sec > 50 && sec <= 55){print_time(datat *100 + mont, 0, 7, 0);} if(sec > 55){print_time(sec, 0, 7, 1);} } void tm_dec(byte dig) { for (int i = 0; i < 8; i++) { DDRB |= (1 << 0); del(); if (dig & 0x01) DDRB &= ~(1 << 1); else DDRB |= (1 << 1); del();DDRB &= ~(1 << 0); del(); dig = dig >> 1;} DDRB |= (1 << 0); DDRB &= ~(1 << 1); del(); DDRB &= ~(1 << 0); del(); if (((PINB >> 1) & 1) == 0) DDRB |= (1 << 1); del();DDRB |= (1 << 0); del(); } void tm_stop() { DDRB |= (1 << 1); del(); DDRB &= ~(1 << 0); del(); DDRB &= ~(1 << 1); del(); } void tm_start() { DDRB |= (1 << 1); del(); } void print_time(int t, byte pd_t, int br, bool mn) { tm_start(); tm_dec(0b10001000 + br); //tm_stop();tm_start(); tm_dec(0x40); tm_stop(); tm_start(); int data0,data1; if(mn==1){data0 = 10;data1 = 10;} else{data0 = t / 1000;data1 = t / 100 % 10;} int data2 = t / 10 % 10; int data3 = t % 10; for (byte n = 0; n < 4; n++) { int data; switch (n) { case 0: data = data0; break; case 1: data = data1; break; case 2: data = data2; break; case 3: data = data3; break; } switch (data) { // XGFEDCBA case 0: data = 0b00111111; break; // 0 case 1: data = 0b00000110; break; // 1 case 2: data = 0b01011011; break; // 2 case 3: data = 0b01001111; break; // 3 case 4: data = 0b01100110; break; // 4 case 5: data = 0b01101101; break; // 5 case 6: data = 0b01111101; break; // 6 case 7: data = 0b00000111; break; // 7 case 8: data = 0b01111111; break; // 8 case 9: data = 0b01101111; break; // 9 case 10: data = 0b00000000; break; // пусто } if (n == 0) {data0 = data;} if (n == 1) {data1 = data;} if (n == 2) {data2 = data;} if (n == 3) {data3 = data;} } switch (pd_t) { case 1 : data2 = data2 + 0b10000000; break; case 2 : data1 = data1 + 0b10000000; break; case 3 : data0 = data0 + 0b10000000; break; } tm_dec(0xC0); tm_dec(data0); tm_dec(data1); tm_dec(data2); tm_dec(data3); tm_stop(); } void del() {delayMicroseconds(200);} bool i2c_read_bit() { bool i2c_bit = 1; DDRB &= ~(1 << SDA); delayMicroseconds(10); DDRB &= ~(1 << SCL); if((PINB >> SDA) & 1) i2c_bit=0; delayMicroseconds(10); DDRB |= (1 << SCL); return i2c_bit; } byte i2c_write_byte(byte data){ for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;} return i2c_read_bit(); } byte i2c_read_byte(byte a){ byte i, data=0; for(i=0; i<8; i++){if (!i2c_read_bit()) data++;if(i!=7) data<<=1;} i2c_write_bit(a);return data; } void i2c_write_bit(byte b){ delayMicroseconds(5); if(b){DDRB |= (1 << SDA);}else{DDRB &= ~(1 << SDA);} delayMicroseconds(5); DDRB &= ~(1 << SCL); delayMicroseconds(10); DDRB |= (1 << SCL); } void i2c_start(){ delayMicroseconds(10); DDRB &= ~(1 << SDA); DDRB &= ~(1 << SCL); delayMicroseconds(10); DDRB |= (1 << SDA); PORTB &= ~(1 << SDA); delayMicroseconds(10); DDRB |= (1 << SCL); PORTB &= ~(1 << SCL); delayMicroseconds(10); } void i2c_stop() { DDRB |= (1 << SDA); delayMicroseconds(10); DDRB &= ~(1 << SCL); delayMicroseconds(10); DDRB &= ~(1 << SDA); } byte ds_read(byte reg){ byte data = 0; i2c_start(); i2c_write_byte(0b11010000); i2c_write_byte(reg); i2c_start(); i2c_write_byte(0b11010001); data = i2c_read_byte(0); i2c_stop(); return data; } void ds_write(byte reg, byte data){ i2c_start(); i2c_write_byte(0b11010000); i2c_write_byte(reg); i2c_write_byte(data); i2c_stop(); } void set_time(byte years, byte days, byte monts, byte datas, byte hours ,byte minute, byte second){ ds_write(0x00,(second/10<<4)+second%10); ds_write(0x01,(minute/10<<4)+minute%10); ds_write(0x02,(hours/10<<4)+hours%10); ds_write(0x03,days); ds_write(0x04,(datas/10<<4)+datas%10); ds_write(0x05,(monts/10<<4)+monts%10); ds_write(0x06,(years/10<<4)+years%10); }
Скетч использует 1594 байт (77%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 10 байт (7%) динамической памяти, оставляя 118 байт для локальных переменных. Максимум: 128 байт.Arduino IDE 1.8.9 | Плата для прошивки версии 1.2.5 (выбрать в менеджере плат)
Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=3218#p3218
Есть такой модуль, есть TM1637 с двумя разделительными точками, есть ардуинки NANO, PRO-MINI.
ATtiny2313 нет, не вижу смысла его заказывать только для для теста модуля времени.
Если б вы переписали скетч под ардуино, я бы протестил и выложил.