Модуль часов реального времени DS3231 (ZS-042) построен на микросхеме DS3231SN, которая является часами реального времени. В отличии от старой модели часов, например на микросхеме DS1307, эти часы содержат внутренний кварцевый резонатор, благодаря чему часы имеют точный ход.
Микросхема RTC DS3231 отсчитывает секунды, минуты, часы, день недели, даты месяца, месяцы, годы. Дата по окончании месяца автоматически подстраивается для месяцев, у которых дней меньше 31, включая учет февраля и коррекцию дней для високосного года (до 2100 года). Часы работают либо в 24-часовом, либо в 12-часовом формате с индикатором ~AM/PM. Предоставляется два программируемых по времени дня будильника, и программируемый выход прямоугольного сигнала. Адрес и данные передаются последовательно через двунаправленную шину I2C.
Основные возможности микросхемы DS3231:
- Очень точная система RTC, которая полностью обслуживают все функции отсчета времени.
- Точность ±2 ppm в диапазоне 0°..+40°C.
- Точность ±3.5 ppm в диапазоне -40°..+85°C.
- Выход цифрового датчика температуры с точностью ±3°C.
- Регистр учета старения (Aging Trim).
- Система входа/выхода для генерации сброса микроконтроллера с подавлением дребезга (RST Output/Pushbutton Reset Debounce Input).
- Два программируемых по времени дня будильника (Time-of-Day Alarm).
- Programmable Square-Wave Output Signal.
- Простой последовательный интерфейс I2C, позволяющий подключить микросхему к любому микроконтроллеру. Скорость работы интерфейса до 400 кГц.
- Вход резервного питания для подключения батареи с очень низким потреблением энергии.
- Работа от уровня напряжения 3.3V.
Установка и считывание времени производится при помощи регистров согласно следующей таблице:
Для работы с модулем DS3231 под управлением Arduino существуют несколько библиотек, но при использовании микроконтроллера ATtiny2313 использование библиотек не целесообразно из-за малого объема памяти (2 кБ). Следующий пример скетча не использует библиотек, что позволило оптимально использовать память ATtiny2313. Так же хочу отметить, что скетч не поддерживает изменение и считывание данных регистров отвечающих за управление будильниками (регистры с 0x07 по 0x0D), поддерживаются только регистры отвечающие за хранение времени и температурного датчика.
Для примера использования часов реального времени DS3231 с микроконтроллером ATtiny2313, можно собрать простые часы, в качестве индикатора будет использован модуль индикатора TM1637 который представляет собой 4-х разрядный семисегментный дисплей на базе драйвера TM1637.
Схема часов
Перед загрузкой скетча рекомендую ознакомится со статьей — ATtiny2313 + Arduino IDE
Часы работают следующим образом — с 0 по 25 и с 30 по 50 секунду индикатор показывает время, точка мигает в такт секундам, далее с 25 по 30 секунду индикатор показывает число и месяц, потом с 50 по 55 выводится показания датчика температуры, а с 55 до 59 секунды индикатор показывает ход секунд.
Температура представлена 10-битным кодом с разрешающей способностью 0.25°C, и она доступна по в регистрах по адресам 11h и 12h, поэтому на индикатор часов выводятся сотые доги градуса кратные 0,25 °С.
Корректировка времени
// set_time(21,2,3,8,14,20,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59
Для корректировки времени раскомментируйте эту сроку, загрузите скетч, а затем закомментируйте сроку и снова загрузите скетч.
Если необходимо скорректировать только один параметр времени, то в тех параметрах которые Вы не хотите менять укажите число 255.
// set_time(255,255,3,9,255,255,255);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59
После применения этой функции будет скорректировано только дата и месяц.
#define SDA 2 // PB3 #define SCL 3 // PB2 #define SQW 4 // PB4 byte bb; void setup(){ DDRB &= ~(1 << SQW);PORTB |= (1 << SQW); // set_time(21,3,3,9,22,02,0);// год 00-99, ДН 1-7 (1=ВС), месяц 1-12, дата 1-31, час 0-23, минуты 0-59, секунды 0-59 ds_write(0x0E, 0b00000000); // выход 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(7) & 0x70) >> 4) * 10); int temper = (ds_read(0x11)*100 + ((ds_read(0x12) & 0b11000000) >> 6)*25) ; 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(temper, 2, 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){ if(second < 255){ds_write(0x00,(second/10<<4)+second%10);} if(minute < 255){ds_write(0x01,(minute/10<<4)+minute%10);} if(hours < 255){ds_write(0x02,(hours/10<<4)+hours%10);} if(days < 255){ds_write(0x03,days);} if(datas < 255){ds_write(0x04,(datas/10<<4)+datas%10);} if(monts < 255){ds_write(0x05,(monts/10<<4)+monts%10);} if(years < 255)ds_write(0x06,(years/10<<4)+years%10); }
Скетч использует 1638 байт (79%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 10 байт (7%) динамической памяти, оставляя 118 байт для локальных переменных. Максимум: 128 байт.Arduino IDE 1.8.9 | Плата для прошивки версии 1.2.5 (выбрать в менеджере плат)