Подписаться на получение новых статей на почту:

Шаг №29. Подключаем часы реального времени DS1307 к AVR

Обновлено 23.07.2018. Всем привет. Для работы с часами, в прошлой статье был рассмотрен интерфейс TWI, на который мы сегодня будем ссылаться. Ну что ж начнем. Данные часы являются TWI совместимыми, т.е. принцип обмена данными по шине будет таким же как мы и рассматривали.

На рисунке ниже представлено расположение выводов, описание, и сам вид наших часов или как далее будем их называть RTC (Real-time clock) — часы реального времени или генератор импульсов времени. Данный “девайс” DS1307 считает секунды, минуты, часы, день месяца, месяц, день недели и год вместе с високосными. Календарь действителен до 2100 года. Я думаю на наш век хватит:).

 

 

Распиновка DS1307Описание выводов DS1307

Внешний вид ds1307.

Как видно из описания имеется вход для аварийного питания от батареи, при отключенном внешнем питание. В этом режиме RTC поддерживает только свое основное назначение – отсчет времени, без внешних запросов. Напряжение питания батареи должно быть 2 – 3.5V. В техническом описание пишется что при заряде более 48 мА/ч, при температуре 25 град Цельсия, наша схема продержится около 10 лет. Более чем надо. На рисунке ниже представлена “таблеточка” CR2032 и крепление, которые будем использовать.

 

 

Литиевая батарейка CR2032.Крепление под батарейку CR2032.

Теперь пройдемся по внешнему питанию. Рабочее напряжение часов 5В с небольшим диапазоном 4,5 -5,5В. Напряжение от батареи 3В(минимум 2, максимум 3,5В) Работа RTC делится на три режима по напряжению:

1. Vcc=5В – чтение, запись, отсчет;
2. Vcc= ниже 1,25*Vbat , но выше Vbat +0.2V — только отсчет батареи от внешнего питания.
3. Vcc ниже Vbat: RTC и ОЗУ переходит на питание от батареи. Потребление в активном состоянии 1,5 мА, от батареи 500-800нА.
Напряжение для передачи/приема информации:
Логический 0: -0.5В — +0.8В
Логическая 1: 2.2 В – Vcc+0.3В

Как и в прошлых постах попробуем запустить в Proteus. Отладим код. И перенесем все в железо. Ниже приведена схема подключения.

Схема подключения DS1307 к микроконтроллеру

Где SQW/OUT – это вывод часов который можно запрограммировать на вывод частоты 1Гц, 4.096Гц, 8.192Гц и 32,768Гц. Т.е. можно использовать для внешнего прерывания контроллера с периодичностью в 1 с. Очень полезная функция. Но нам не пригодится. Кстати он тоже с открытым коллектором, поэтому необходим подтягивающий резистор. Номинал 4,7 кОм.

Выводы Х1 и Х2 – к ним подключаем кварцевый резонатор с частотой 32,768 кГц. Либо можно применить внешний тактовый генератор с той же частотой. Но при этом вывод X1 подключается к сигналу, а X2 остаётся неподключенным (висеть в воздухе.).

Ну и выводы SDA и SCL, с которыми мы познакомились в прошлой статье.

Немного остановимся на резонаторе (рисунок ниже). Который можно назвать сердцем часов, и от которого зависит точность хода. Качество самого резонатора, лежит на совести производителя, но со своей стороны, мы можем уменьшить погрешность, которую вносят внешние факторы, если будем придерживаться следующих рекомендаций по размещению резонатора:

 

кварцевый резонатор

1. Чем ближе резонатор к контактам Х1 Х2 тем меньше вероятность возникновения помех и уменьшение паразитной емкости.

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

3. Контур в виде защитного кольца необходимо поместить вокруг кристалла, что помогает изолировать кристалл от шума.

4. Проводники поместить в кольцо и и подключить к заземлению.

5. Припаиваем резонатор к земле. Если земля разведена верно и есть уверенность.

На рисунке ниже видно контур и место припая к земле.

Монтаж кварцевого резонатора

Как подключать разобрались. Идем далее – разберемся как с ним работать. RTC является программируемым и имеет 8 байт специальных регистров для его конфигурации и энергонезависимую статическую память 56 байтов. Для обмена информации необходима 2-х проводная шина данных, т.е. последовательная шина данных- интерфейс TWI, который мы рассмотрели в прошлой статье. Итак для работы пробежимся по даташиту. Что нам необходимо:

Таблица регистров. Рисунок ниже. Первые восемь регистров – для вывода и программирования наших часов. При обращении по адресу 00H к 7-му биту(CH) и установкой его в 0 –запускаем часы. Хочется отметить, что конфигурация регистров может быть любая, поэтому при первом запуске необходимо его настроить под свои требования. Остальные семь битов единицы и десятки секунд.

Таблица регистров DS1307.

01H – Минуты.
02H – Часы, которые настраиваются:
           — Бит 6 – при 1 вывод 12 часовой формат, 0 – 24.
           — Бит 5 – при 1 (при 12 часовом формате) PM , 0-AM
           — Бит 5 – (при 24 ч формате) это вывод второго десятка часов (20-23часа.)
           — Бит4 – первый десяток часов, остальные биты это единицы часов.
03H – день недели;
04H – дата;
05H – месяц года
06H – год.

Ну и последний регистр 07H. Данный регистр является управляющим.Где OUT отвечает за управление выводом SQW/OUT. Ниже таблица включения вывода.

OUT
SQWE
SQW/OUT
1
0
1
0
0
0

SQWE – при установке этого бита в ,1 на вывода выходят импульсы с заданной частотой,которая устанавливается ,битами RS1 и RS0.

Выходная частота DS1307.

Этот вывод нам не пригодится в проекте. Хотя для него я развел на плате дорожку. В качестве экспериментов может быть где то в будущем и применим, ведь здесь можно сделать прерывании в 1 с.

Теперь имея всю необходимую информацию, напишем функции для работы с часами. А также запустим проект в Proteus. Который будет иметь следующий вид:

Подключение ds1307 к avr в proteus

!!! Обратите внимание, что резонатор в Proteus, можно и не подключать к часам(обведенное красным).

На рисунке выведен терминал часов, который отображает время, которое в свою очередь привязано к системному времени. Терминал отладчика протокола I2C или TWI, на котором отображается время отправки и приема сигнала, где D0 – передаваемая команда, D1 -  прием. Ниже я буду выводить скриншоты терминала с результатом работы программы.

Программа. Рассмотрев основные настройки часов напишем функцию инициализации.

/*Функция инициализации включает в себя установку скорости обмена данных по формуле(в предыдущей статье), установка пред делителя и включение модуля TWI*/
void init_DS1307 (void)
{
TWBR = 2; /*При частоте 1 МГц */
 TWSR = (0 << TWPS1)|(0 << TWPS0); /*Пред делитель на 64*/
TWCR |= (1 << TWEN); /*Включение модуля TWI*/
}

Далее напишем функцию записи. На рисунке ниже приведен формат записи DS1307 с адресом 1101.

Формат записи DS1307.

void write_DS1307 (uint8_t reg, uint8_t time) /*передаем два параметра: адрес регистра, к которому будем обращаться и передаваемую информацию*/
{
/* Формируем состояние СТАРТ, выставляя разряды регистра управления*/
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
/*Разрешить работу модуля TWEN; Сформировать состояние старт TWSTA; Сбросить флаг TWINT */
/*Ждем окончания формирования условия старт, т.е. пока не установится флаг, код статуса = 08*/
while (!(TWCR & (1<<TWINT)));
/*Далее перелаем пакет адреса (адрес устройства). Содержимое пакета загружается в регистр TWDR*/
TWDR = 0xd0; /*0b1101000 + 0 – адрес + бит записи*/
/*Сбрасываем флаг для передачи информации*/
TWCR = (1<<TWINT)|(1<<TWEN);
/*Ждем установки флага*/
while (!(TWCR & (1<<TWINT)));
/*передаем регистр к которому будем обращаться*/
TWDR = reg;
TWCR = (1<<TWINT)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
/*Передаем информацию для записи в байт регистра*/
TWDR = time;
TWCR = (1<<TWINT)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
/*формируем состояние СТОП*/
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

В этой функции мы передали три байта, адрес устройства, адрес регистра и байт информации для записи в этот регистр и сформировали состояние СТОП.

Осталась последняя функция чтения. Ниже формат чтения.

Формат чтения DS1307.

В данной функции выполняется передача байта адреса устройства +бит записи, байт адреса регистра для установки на него указатель, выполнение условия ПОВСТАР, передача байта адреса устройства +бит чтения, чтение регистра, адрес которого мы передали ранее.

!!!        Если мы будем обращаться к часам в формате чтения, то при повторном обращении к часам указатель сдвигается на один байт вниз включая 56 байт ОЗУ, от 00H до 3FH. При достижении последнего адреса, указатель переходит на адрес 00.

/*Функция чтения данных из DS1307*/
uint8_t read_DS1307 (uint8_t reg) /*Передаем адрес регистра*/
{
       uint8_t time;
      /*формируем состояние СТАРТ*/
       TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
       TWDR = 0xd0; /*Передаем адрес + бит записи*/
       TWCR = (1<<TWINT)|(1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
       TWDR = reg;   /*Адрес регистра*/
       TWCR = (1<<TWINT)|(1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
      /*формируем состояние ПОВСТАР*/
       TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
       TWDR = 0xd1; /*Передаем адрес + бит чтения*/
       TWCR = (1<<TWINT)|(1<<TWEN);
       while (!(TWCR & (1<<TWINT)));
       /*считываем данные*/
      TWCR = (1<<TWINT)|(1<<TWEN);
      while (!(TWCR & (1<<TWINT)));
      time = TWDR;
      time = (((time & 0xF0) >> 4)*10)+(time & 0x0F);
     /*формируем состояние СТОП*/
      TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
      return time;
}

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

#include <avr/io.h>
#include <util/delay.h>
uint8_t time;
void init_DS1307 (void);
uint8_t read_DS1307 (uint8_t reg);
void write_DS1307 (uint8_t reg, uint8_t time);
int main (void)
{
      DDRC = 0×00;  /*Выставляем порт как вход*/
      PORTC = 0xFF; /*Подтягиваем сопротивление*/
      init_DS1307;
      while (1)
      {
              _delay_ms (50);
              read_DS1307 (0×04); /*Чтение регистра даты*/
      }
}

Ниже результат выполнения программы чтение даты.

Чтение даты DS1307 в Proteus.

В окне отладчика I2C (TWI) видно что сначала посылается адрес регистра в RTC (зеленый кружочек), в данном случае 04, который отвечает за дату месяца, и далее часы передают ответ 21 (красный кружочек).

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

while (1)
{
      _delay_ms (500);
      read_DS1307 (0×01);       /*Считываем минуту*/
      _delay_ms (500);
      write_DS1307 (0×01, 15); /*Записываем необходимую минуту*/
      _delay_ms (500);
      read_DS1307 (0×01);       /*Считываем минуту*/
}

На рисунке видно, что сначала идет обращение к регистру 01, считывается минута 23. Далее мы используем функцию записи, и вносим значение 15. При следующей функции чтения у нас на табло часов значение 15.

Изменение минуты DS1307 в Proteus.

Ну и последний пример программы это вывод значений всех регистров

while (1)
{
        delay_ms (500);
        read_DS1307 (0×00);
        _delay_ms (500);
        read_DS1307 (0×01);
        _delay_ms (500);
        read_DS1307 (0×02);
        _delay_ms (500);
        read_DS1307 (0×03);
        _delay_ms (500);
        read_DS1307 (0×04);
        _delay_ms (500);
        read_DS1307 (0×05);
        _delay_ms (500);
        read_DS1307 (0×06);
        _delay_ms (500);
}

На рисунке ниже видно, что вывелись данные 7-ми регистров.

Вывод данных DS1307 в Proteus.

Исходник с проектом прилагается:

Исходник и проект. ( Скачали: 570 чел. ) 

На этом все. В следующей статьеподключим часы в железе, выведем время на индикатор и познакомимся с двоично-десятичным форматом для работы с часами. Всем пока.

Просмотрено 12576 раз.

Я на Google+

Шаг №29. Подключаем часы реального времени DS1307 к AVR: Один комментарий

  1. Здравствуйте. Отличный материал.

    В функции read_DS1307 вначале описана переменная time, а в конце возвращаем ее значение, но в коде не нашел строчки где в эту переменную помещаем значение?

    Имеется комментарий /*считываем данные*/ но переменная time не участвует. Так как именно читать данные?

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

Ваш e-mail не будет опубликован.

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Subscribe without commenting