ATtiny2313 + DS1307 (Arduino IDE)

Часы реального времени с последовательным интерфейсом 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

Comments

  1. Есть такой модуль, есть TM1637 с двумя разделительными точками, есть ардуинки NANO, PRO-MINI.
    ATtiny2313 нет, не вижу смысла его заказывать только для для теста модуля времени.
    Если б вы переписали скетч под ардуино, я бы протестил и выложил.

Добавить комментарий

Войти с помощью: