Русское описание DS1307.

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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.

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

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


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

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

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

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

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

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

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

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

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

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

#include
#include
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); /*Чтение регистра даты*/
}
}

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

В окне отладчика I2C видно что сначала посылается адрес регистра в 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.


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

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-ми регистров.

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

(Скачали: 341 чел.)

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

DS1307 это небольшой модуль, предназначенный для подсчета времени. Собранный на базе микросхемы DS1307ZN с реализацией питания от литиевой батарейки (LIR2032), что позволяет работать автономно в течение длительного времени. Также на модуле, установлена энергонезависимая память EEPROM объемом 32 Кбайт (AT24C32). Микросхема AT24C32 и DS1307ZN связаны обшей шиной интерфейсом I2C.

Технические параметры

Напряжение питания: 5В
Рабочая температура: – 40℃ … + 85℃
Память: 56 байт (энергонезависимая)
Батарейка: LIR2032 (автоматическое определение источника питания)
Размеры: 28мм х 25мм х 8 мм
Интерфейса: I2C

Общие сведения

Использовании модуля DS1307 зачастую очень оправдано, например, когда данные считываются редко, интервалом более недели, использовать собственные ресурсы контроллера, неоправданно или невозможно. Обеспечивание бесперебойное питание, например платы Arduino, на длительный срок дорого, даже при использовании батареи.
Благодаря собственной памяти и автономностью, можно регистрировать события, (при автономном питании) например изменение температуры и так далее, данные сохраняются в памяти их можно считать из памяти модуля. Так что модуль DS1307 часто используют, когда контроллерам Arduino необходимо знать точное время, для запуска какого то события и так далее.


На нижний стороне модуля, почти полностью занимает держатель батарейки.


Обмен данными с другими устройствами осуществляется по интерфейсу I2C с выводов SCL и SDA. Конденсаторы С1 и С2 необходимы для снижения помех по линию питания. Чтобы обеспечить надлежащего уровня сигналов SCL и SDA установлены резисторы R2 и R3 (подтянуты к питанию). Для проверки работоспособности модуля, на вывод 7 микросхему DS1307Z, подается сигнал SQ, прямоугольной формы с частотой 1 Гц. Элементы R4, R5, R6, VD1 необходимы для подзарядку литиевой батарейки. Так же, на плате предусмотрено посадочное место (U1), для установки датчика температуры DS18B20 (при необходимости можно впаять его), считывать показания, можно с вывода DS, который подтянут к пиатнию, через резистор R1 сопротивлением 3.3 кОм. Принципиальную схему и назначение контактов можно посмотреть на рисунках ниже.


На плате расположено две группы контактов, шагом 2.54 мм, для удобного подключения к макетной плате, буду использовать штырьевые разъемы, их необходимо впаять.


Первая группа контактов:
DS: вывод DS18B20 (1-wire)

VCC: «+» питание модуля
GND: «-» питание модуля

Вторая группа контактов:
SQ: вход 1 МГц
DS: вывод DS18B20 (1-wire)
SCL: линия тактирования (Serial CLock)
SDA: линия данных (Serial Dфta)
VCC: «+» питание модуля
GND:«-» питание модуля
BAT:

Подзарядка батареи
Как описывал ваше модуль может заряжать батарею, реализовано это, с помощью компонентов R4, R5, R6 и диода D1. Но, данная схема имеет недостаток, через резистор R4 и R6 происходит разряд батареи (как подметил пользователь ALEXEY, совсем не большой). Так как модуль потребляем незначительный ток, можно удалить цепь питания, для этого убираем R4, R5, R6 и VD1, вместо R6 поставим перемычку (после удаления компонентов, можно использовать обычную батарейку CR2032).


Подключение DS1307 к Arduino

Необходимые детали:
Arduino UNO R3 x 1 шт.
Провод DuPont, 2,54 мм, 20 см x 1 шт.
Кабель USB 2.0 A-B x 1 шт.
Часы реального времени RTC DS1307 x 1 шт.

Подключение:
Для подключения часы реального времени DS1307, необходимо впаять впаять штыревые разъемы в первую группу контактов. Далее, подключаем провода SCL (DS1307) к выводу 4 (Arduino UNO) и SDA (DS1307) к выводу 5 (Arduino UNO), осталось подключить питания VCC к +5V и GND к GND. Кстати, в различных платах Arduino вывода интерфейса I2C отличаются, назначение каждого можно посмотреть ниже.



Скачиваем и устанавливаем библиотеки «DS1307RTC» и «TimeLib» в среду разработки IDE Arduino (посмотрите в конец статьи). При первом включении необходимо запрограммировать время, откройте пример из библиотеки DS1307RTC «Файл» —> «Примеры» —> «DS1307RTC» —> «SetTime», или скопируйте код снизу.

// Подключаем библиотеку DS1307RTC const char *monthName = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; tmElements_t tm; void setup() { bool parse=false; bool config=false; // get the date and time the compiler was run if (getDate(__DATE__) && getTime(__TIME__)) { parse = true; // and configure the RTC with this info if (RTC.write(tm)) { config = true; } } Serial.begin(9600); while (!Serial) ; // wait for Arduino Serial Monitor delay(200); if (parse && config) { Serial.print("DS1307 configured Time="); Serial.print(__TIME__); Serial.print(", Date="); Serial.println(__DATE__); } else if (parse) { Serial.println("DS1307 Communication Error:-{"); Serial.println("Please check your circuitry"); } else { Serial.print("Could not parse info from the compiler, Time=\""); Serial.print(__TIME__); Serial.print("\", Date=\""); Serial.print(__DATE__); Serial.println("\""); } } void loop() { } bool getTime(const char *str) { int Hour, Min, Sec; if (sscanf(str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false; tm.Hour = Hour; tm.Minute = Min; tm.Second = Sec; return true; } bool getDate(const char *str) { char Month; int Day, Year; uint8_t monthIndex; if (sscanf(str, "%s %d %d", Month, &Day, &Year) != 3) return false; for (monthIndex = 0; monthIndex < 12; monthIndex++) { if (strcmp(Month, monthName) == 0) break; } if (monthIndex >= 12) return false; tm.Day = Day; tm.Month = monthIndex + 1; tm.Year = CalendarYrToTm(Year); return true; }

Загружаем данную код в контроллер Arduino (время берется с ОС), открываем «Мониторинг порта»


Программа
В библиотеке есть еще один пример, открыть его можно DS1307RTC «Файл» —> «Примеры» —> «DS1307RTC» —> «ReadTest»

/* Тестирование производилось на Arduino IDE 1.6.12 Дата тестирования 23.11.2016г. */ #include // Подключаем библиотеку Wire #include // Подключаем библиотеку TimeLib #include // Подключаем библиотеку DS1307RTC void setup() { Serial.begin(9600); // Устанавливаем скорость передачи данных while (!Serial) ; // Ожидаем подключение последовательного порта. Нужно только для Leonardo delay(200); // Ждем 200 мкс Serial.println("DS1307RTC Read Test"); // Выводим данные на последовательный порт Serial.println("-------------------"); // Выводим данные на последовательный порт } void loop() { tmElements_t tm; if (RTC.read(tm)) { Serial.print("Ok, Time = "); print2digits(tm.Hour); Serial.write(":"); print2digits(tm.Minute); Serial.write(":"); print2digits(tm.Second); Serial.print(", Date (D/M/Y) = "); Serial.print(tm.Day); Serial.write("/"); Serial.print(tm.Month); Serial.write("/"); Serial.print(tmYearToCalendar(tm.Year)); Serial.println(); } else { if (RTC.chipPresent()) { Serial.println("The DS1307 is stopped. Please run the SetTime"); Serial.println("example to initialize the time and begin running."); Serial.println(); } else { Serial.println("DS1307 read error! Please check the circuitry."); Serial.println(); } delay(9000); } delay(1000); } void print2digits(int number) { if (number >= 0 && number < 10) { Serial.write("0"); } Serial.print(number); }

Провода DuPont, 2,54 мм, 20 см
Часы реального времени RTC DS1307

Купить в Самаре и области
Купить контроллер Arduino UNO R3 в г. Самаре
Купить провода DuPont, 2,54 мм, 20 см в г. Самаре
Купить часы реального времени RTC DS1307 в г. Самаре

Модуль рассматриваемый в статье содержит в себе сразу две микросхемы: DS1307 (часы реального временис I2C- интерфейсом) и AT24C32 (микросхема памяти EEPROM на 32K bit).

В данной статье рассмотрим работу только микросхемы часов реального времени DS1307.

Основные технические характеристики:

Подсчет реального времени в секундах, минутах, часах, датах месяца, месяцах, днях недели и годах с учетом высокосности текущего года вплоть до 2100 г.

56 байт энергонезависимого ОЗУ для хранения данных

2-х проводной последовательный интерфейс

Программируемый генератор прямоугольных импульсов. Может выдавать 1 ГЦ, 4.096 кГЦ, 8,192 кГЦ и 32,768 кГц.

Автоматическое определение отключения основного источника питания и подключение резервного

24-х часовой и 12-ти часовой режим

Потребление не более 500 нA при питании от резервной батареи питания при температуре 25C°

Микросхема выпускается в восьмипиновых DIP и SOIC корпусах. Распиновка для всех одинакова. Далее приведу строки из даташита для полноты картины.

Документация на микросхему (datasheet)

Назначение выводов:

. X1, X2 - Служат для подключения 32.768 кГц кварцевого резонатора

. Vbat - Вход для любой стандартной трёхвольтовой литиевой батареи или другого источника энергии. Для нормальной работы DS1307 необходимо, чтобы напряжение батареи было в диапазоне 2.0 ... 3.5 В. Литиевая батарея с ёмкостью 48 мА/ч или более при отсутствии питания будет поддерживать DS1307 в
течение более 10 лет при температуре 25°C.

. GND - общий минус

. Vcc - Это вход +5 В. Когда питающее напряжение выше 1.25 * VBAT, устройство полностью,доступно, и можно выполнять чтение и запись данных. Когда к устройству подключена батарея на 3 В, и Vcc ниже, чем 1.25 * VBAT, чтение и запись запрещены, однако функция отсчёта времени продолжает работать. Как только Vcc падает ниже VBAT, ОЗУ и RTC переключаются на батарейное питание VBAT.

. SQW/OUT - Выходной сигнал с прямоугольными импульсами.

. SCL - (Serial Clock Input - вход последовательных синхроимпульсов) - используется для синхронизации данных по последовательному интерфейсу.

. SDA - (Serial Data Input/Output - вход/выход последовательных данных) - вывод входа/выхода для двухпроводного последовательного интерфейса.

Работа с выводом SQW/OUT .

Для начала рассмотрим структуру регистров DS1307.

Структура регистров микросхемы DS1307


Нас интересует "Управляющий регистр" находящийся по адресу 0x7, т.к. он определяет работу вывода SQW/OUT.

Если бит SQWE = 1. то начинается формирование прямоугольных импульсов, если SQWE = 0, то на выходе вывода будет значение бита OUT.

За частоту импульсов отвечают биты RS0 и RS1, а именно:

RS0 RS1 Частота
0 0 1 Гц
0 1 4.096 кГц
1 0 8.192 кГц
1 1 32.768 кГц

Приведем пример:

Если нам нужно начать формирование прямоугольных импульсов с частотой 1 Гц, то необходимо в 0x7 регистр микросхемы, которая имеет адрес 0x68 отправить байт 00010000 или 0x10 в шестнадцатиричной системе счисления.

При помощи библиотеки Wire.h , это можно сделать следующим образом:

Wire .beginTransmission (0x68); Wire .write (0x7); Wire .write (0x10); Wire .endTransmission ();

Подключение к Arduino:

Выводы отвечающие за интерфейс I2C на платах Arduino на базе различных контроллеров разнятся.

Необходимые библиотеки:

для работы с DS1307: http://www.pjrc.com/teensy/td_libs_DS1307RTC.html
для работы со временем: http://www.pjrc.com/teensy/td_libs_Time.html

Установка времении

. Вручную в коде

Время задается вручную в программном коде и заливается в плату Arduino. Данный способ не самый точный т.к. время на компиляцию и загрузку может занимать различный временной промежуток.

Пример программного кода

#include #include void setup () { Serial .begin (9600); while (!Serial ) ; // Только для платы Leonardo // получаем время с RTC Serial //синхронизация не удаласть else Serial .println ("RTC has set the system time" ); //установим вручную 16.02.2016 12:53 TimeElements te; te.Second = 0; //секунды te.Minute = 53; //минуты te.Hour = 12; //часы te.Day = 16; //день te.Month = 2; // месяц te.Year = 2016 - 1970; //год в библиотеке отсчитывается с 1970 time_t timeVal = makeTime(te); RTC .set (timeVal); setTime (timeVal); } void loop () { digitalClockDisplay(); //вывод времени delay (1000); } void digitalClockDisplay() { Serial Serial .print (" " ); Serial .print (day ()); Serial .print (" " ); Serial .print (month ()); Serial .print (" " ); Serial .print (year ()); Serial //выводим время через ":" Serial .print (":" ); if (digits < 10) Serial .print ("0" ); Serial .print (digits); }


. Установкой из "Монитора порта"

Более точный вариант установки времени. Время задается через "монитор порта" по ходу работы контроллера.

Открываем монитор, вводим данные в нужном формате, смотрим на эталонные часы, подлавливаем момент и шелкаем "отправить".

Пример программного кода

//формат указания текущего времени "ДД.ММ.ГГ чч:мм:сс" //где ДД - день, ММ - месяц, ГГ - год, чч - часы, мм - минуты, сс - секунлы //ГГ - от 00 до 99 для 2000-2099 годов #include #include bool isTimeSet = false ; //флаг, указывающий на то, была ли уже задана дата void setup () { Serial .begin (9600); while (!Serial ) ; // Только для платы Leonardo setSyncProvider (RTC .get ); // получаем время с RTC if (timeStatus () != timeSet) Serial .println ("Unable to sync with the RTC" ); //синхронизация не удаласть else Serial .println ("RTC has set the system time" ); } void loop () { if (Serial .available ()) { //поступила команда с временем setTimeFromFormatString(Serial .readStringUntil ("\n" )); isTimeSet = true ; //дата была задана } if (isTimeSet) //если была задана дата { digitalClockDisplay(); //вывод времени } delay (1000); } void digitalClockDisplay() { Serial .print (hour ()); printDigits(minute ()); printDigits(second ()); Serial .print (" " ); Serial .print (day ()); Serial .print (" " ); Serial .print (month ()); Serial .print (" " ); Serial .print (year ()); Serial .println (); } void printDigits(int digits) { //выводим время через ":" Serial .print (":" ); if (digits < 10) Serial .print ("0" ); Serial .print (digits); } void setTimeFromFormatString(String time) { //ДД.ММ.ГГ чч:мм:сс int day = time.substring(0, 2).toInt(); int month = time.substring(3, 5).toInt(); int year = time.substring(6, 8).toInt(); int hours = time.substring(9, 11).toInt(); int minutes = time.substring(12, 14).toInt(); int seconds = time.substring(15, 17).toInt(); TimeElements te; te.Second = seconds; te.Minute = minutes; te.Hour = hours; te.Day = day ; te.Month = month ; te.Year = year + 30; //год в библиотеке отсчитывается с 1970. Мы хотим с 2000 time_t timeVal = makeTime(te); RTC .set (timeVal); setTime (timeVal); }


Купить в России

Отзывы об этих часах в интернете самые противоречивые. Кто-то говорит что часы замечательные, а кто-то называет их убогой поделкой Далласа. И вот я, дабы развеять все недостоверные слухи, достал микруху из загашника начала экспериментировать.

Особенности:

  • Очень маленькое энергопотребление. Производитель обещает 10 лет работы часов от одной стандартной батарейки CR2032
  • 56 байт памяти для хранения пользовательских данных. Думаю не особо нужная опция, но может кому-то и пригодится.
  • Программируемый вывод для тактирования внешних устройств. Может выдавать 1 Гц, 4.096 кГц, 8.192 кГц и 32.768 кГц.
  • 24-х часовой и 12-ти часовой режим

Распиновка

Выводы часов расположены следующим образом:


X1, X2 — Выводы для подключения кварцевого резонатора на частоту 32.768 кГц
VBAT — Вывод для подключения 3-х вольтовой батареи резервного питания
GND — Земля
SDA — линия данных шины i2c
SCL — линия тактовых импульсов шины i2c
SQW/OUT – выходной сигнал для тактирования внешних устройств
VCC — питание 5 вольт

Подключение к контроллеру
Обвязка минимальна. Потребуется кварц 32.768 кГц, пара резисторов для работы шины i2c и батарейка на три вольта.


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


Кстати может работать и без кварца. Для этого на ногу X1 подают внешний тактовый сигнал с частотой 32.768 кГц, а X2 остаётся висеть в воздухе.

Организация памяти часов
Данная микруха наделена 64 байтами памяти. Первые восемь байт — рабочие. В них хранится время, дата, день недели. Остальные выделены под нужды пользователя. В них можно хранить например какие-нибудь настройки или еще что-нибудь. Естественно, когда резервное питание пропадает, вся информация в этой памяти разрушается. Вся работа с часами (чтение и установка времени/даты) сводится к тому, чтобы читать и записывать нужные ячейки памяти.


Все числа в памяти хранятся в двоично-десятичном формате. Это значит что в одном байте может хранится сразу две цифры. Например число 0x23 — содержит в себе цифру 2 и цифру 3. На каждую цифру выделяется по 4 бита. Зачем так сделано? Для удобства и экономии памяти. Кроме времени и даты в памяти хранятся несколько бит настроек:

  • Clock Halt — управляет часами. Когда бит установлен то часы стоят. Чтобы запустить ход часов необходимо записать в этот бит 0. После подключения батареи резервного питания, этот бит уставлен и часы не считают время! Об этом нужно помнить.
  • 24/12 — этот бит выбора режима часов. Когда этот бит равен единице то используется 12-ти часовой режим. В противном случае 24-х часовой. Если используется 12-ти часовой режим то пятый бит показывает AM или PM сейчас. Если бит равен 1 то значит PM. В 24-х часовом режиме этот бит используется для хранения десятков часов совместно с битом 4.
  • Output — управляет состоянием ноги SQW/OUT. Бит установлен — на ноге лог 1. Сброшен — на ноге 0. Для управления таким образом, бит SQWE должен быть сброшен.
  • SQWE — когда бит установлен, на ноге SQW/OUT появляются прямоугольные импульсы.
  • RS1, RS0 — этими битами задается частота импульсов. Зависимость частоты от комбинации бит находится в таблице ниже:

Софт

Для работы с часами DS1307 была написана нехитрая библиотека содержащая следующие базовые функции:

DS_start — запускает часы. Запустить часы можно так же установив время.
DS_stop — останавливает часы
DS_set_time — Установка времени. Перед вызовом процедуры нужно поместить в tmp1 — секунды в tmp2 — минуты и в tmp3-часы. Часы в 24-х часовом формате.
DS_get_time: — считывание времени из часов. секунды будут записаны в tmp1, минуты в tmp2, часы в tmp3
DS_get_date: — считывание даты из часов. День будет записан в tmp1, месяц в tmp2, год в tmp3
DS_set_date: — установка даты. Перед вызовом процедуры нужно поместить в tmp1 — день в tmp2 — месяц и в tmp3-год (последние 2 цифры)

Процедуры установки/чтения времени и даты могут воспринимать/возвращать входные данные в двоично-десятичном формате и в десятичном. Для выбора желаемого формата нужно закомментировать или раскомментировать по три строчки в каждой процедуре (в коде есть примечания по этому поводу).

Тестовая программа позволяет управлять часами через UART (скорость 9600, контроллер работает на частоте 8 мГц). При запуске сразу выдаются время, дата и приглашение ввести команду от 1 до 3. При выборе варианта 1 происходит повторное считывание времени/даты. Вариант 2 позволяет установить время, а вариант 3 дату. Если хочется попробовать поиграть с часами в то в архив с исходником включён файл для симуляции.


Точность
Тут очень многое зависит от применяемого кварца и разводки платы. Даташит сообщает что емкость кварца должна быть 12.5 пф. Говорят, что лучше всего применять кварцы от материнских плат. Для коррекции хода можно подпаять к резонатору подстроечный конденсатором и при помощи него в небольших пределах менять частоту. Лично у меня эти часы работают вторые сутки и отстали на 3 секунды. Что-то мне подсказывает, что дело в ёмкости кварца, попробую другой отпишусь.

Вывод
Неплохие часы. Для любительского применения идеальный вариант. Хотя некоторые пишут о глюках, но я пока не столкнулся.

Урок 17

Часть 1

Часы реального времени DS1307

Продолжаем занятия по программированию МК AVR .

И сегодня мы познакомимся с очень хорошей микросхемой DS1307 . Данная микросхема представляет собой часы реального времени (real time clock или RTC ).

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

Данная микросхема представлена компанией Dallas , вот её распиновка и основные технические характеристики

Здесь мы видим, что есть у нас ножки SDA и SCL, назначение которых мы очень прекрасно знаем из . Также есть ножки X1 и X2 для подключения кварцевого резонатора на 32768 Гц, ножки питания — VCC и GND, выход для импульсов продолжительностью 1 секунда либо другой частоты в зависимости от настроек определенных регистров, а также плюсовой контак для батарейки, которая подключается для поддержания хода часов в момент отключения основного питания. Отрицательный контакт данной батарейки мы подключаем к общему проводу питания.

Также мы видим, что данная микросхема исполняется в планарных и DIP-корпусах.

Питаться данная микросхема может как и от 3 вольт, так и от 5 вольт.

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

Так как данная микросхема у меня установлена в том же модуле, в котором установлена и микросхема EEPROM, а шина обмена у нас одна, то "узнавать" микросхема DS1307 о том, что обращаются именно к ней, будет, конечно, по адресу, который у неё другой, нежели у микросхемы EEPROM.

Вот диаграммы приёма и передачи данных микросхемы


Адрес, по которому мы будем обращаться к данной микросхеме, выделен синим.

В принципе. особой разницы с диаграммами микросхемы EEPROM мы на видим.

Ещё отличие в обращении будет в том, что адресация памяти будет уже однобайтная, так как ячеек памяти или регистров у данной микросхемы очень мало.

Вот что из себя представляют данные регистры

Назначение данных регистров:

00h — секунды. Секунды хранятся в двоично-десятичном виде. То есть в младших 4 битах хранятся единицы секунд, а в более старших трёх — десятки. Также есть бит SH — это бит запуска микросхемы.

01h — минуты. Хранятся аналогично.

02h — более универсальный регистр. Здесь хранятся часы. В четырех младших битах — единицы чаов, в следующих более старших двух — десятки, в следующем 6 бите — флаг того, после полудня сейчас время или до полудня, в 7 бите — режим хранения — 12- часовой или 24-часовой.

03h — день недели. Хранится в младших 3 битах, остальные биты не используются.

04h — здесь хранится день месяца, также в двоично-десятичном формате. В четыреё малдших битах — единицы, в двух следующих постарше — десятки, остальные биты не используются.

05h — номер месяца в году — хранится в двоично-десятичном формате точно также, как и часы.

06h — номер года, причём не полный четырёхзначный, а только двузначный. В младших четырех битах — единицы, в старших — десятки.

Вот этими семью регистрами мы и будем пользоваться. Последний регистр предназначен для конфигурирования частоты импульсов на импульсном выходе микросхемы, это делается в младших двух битах регистра. по умолчанию он будет 1 гц частотой, нам этого достаточно, чтобы помигать двоеточием, поэтому мы не будем пользоваться данными битами. Биты SOWE и OUT также применяются для настройки и включения формирователя даннх квадратных импульсов.

Проект для работы с данной микросхемой был создан обычным образом с именем MyClock1307 , файлы, связанные с EEPROM оттуда убраны, а добавлены файлы RTC.c и RTC.h .

#ifndef MAIN_H_

#define MAIN_H_

#define F_CPU 8000000UL

#include

#include

#include

#include

#include

#include "usart.h"

#include "twi.h"

#include "RTC.h"

#endif /* MAIN_H_ */

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

#include "main.h"

unsigned char sec , min , hour , day , date , month , year ;

int main ( void )

{

I2C_Init ();

USART_Init (8);

While (1)

{

}

}

От прошлого кода останется лишь инициализация I2C и USART.

Теперь нам надо как-то вообще запустить микросхему. Если микросхема новая, либо никогда не использовалась, либо кто-то специально для каких-то целей изменил значение бита CH, то она ещё не "ходит".

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

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

Поэтому, собственно, используя наши знания предыдущего занятия, напишем писать функцию установки времени.

Первым делом мы, само собой, передадим условие СТАРТ

//Устанавливаем время

I2C_StartCondition ();

Затем передаём адрес с битом записи 0

I2C_StartCondition ();

I2C_SendByte (0b11010000);

Перейдём на адрес 0, а значит к той части памяти, где расположен самый первый регистр

I2C_SendByte (0b11010000);

I2C_SendByte (0); //Переходим на 0x00

Прежде чем писать какие-то значения в регистры микросхемы, мы вспомним, что числа мы сначала должны преобразовать в двоично-десятичный формат, который будет удобен для регистров. Для этого мы зайдём в файл RTC.c и такую функцию и напишем. Она будет очень лёгкой и в объяснении не нуждается

unsigned char RTC_ConvertFromBinDec ( unsigned char c )

{

unsigned char ch = (( c /10)<<4)|( c %10);

return ch ;

}

Ну и также давайте напишем и функцию обратного типа, переводящую число из двоично-десятичного формата в десятичный. С помощью неё мы, наоборот, будем считанные показания времени преобразовывать в вид, удобный нашему восприятию (ЧПИ — человеко-понятный интерфейс)

unsigned char RTC_ConvertFromDec ( unsigned char c )

{

unsigned char ch = (( c >>4)*10+(0b00001111& c ));

return ch ;

}

Здесь также всё придельно ясно, мы сдвигаем вправо старшую тетраду байта, умножаем её на десять и прибавляем младшую тетраду (старшую отмаскировываем нулями)

Напишем прототипы данных функций в файле RTC.c

#include "main.h"

unsigned char RTC_ConvertFromDec ( unsigned char c ); //перевод двоично-десятичного числа в десятичное

unsigned char RTC_ConvertFromBinDec ( unsigned char c ); //перевод десятичного числа в двоично-десятичное

Соберём код, а прошивать контроллер пока не будем. Нам нужно ещё дописать код записи в регистры и написать в бесконечный цикл процедуру чтения времени и даты и отправку всего этого в USART, а затем уж прошьём полностью весь код, прописав правильные значения времени и даты в установку времени.