Часы на PCF8523 и AVR-микроконтроллере

Приветствую всех. Сегодня предлагаю рассмотреть часы на микросхеме PCF8523. Когда-то их можно было получить бесплатным сэмплом от компании NXP. При первом рассмотрении уже видно, что эта микросхема часов реального времени достаточно навороченная. Но это не делает работу с ней сложной. Разработчики наделили ее хорошим функционалом и возможностями.

Итак, RTC PCF8523 — это часы реального времени и календарь, оптимизированные для низкого потребления мощности. Данные передаются по средствам I2C интерфейса с максимальной скоростью 1000 кбит / с. Имеются функции будильника и таймера, которые могут генерировать сигналы на выходах микросхемы. Также имеется цепь резервного питания, отслеживаются сбои в основном питании и при этом происходит переключение на питании от батарейки (батарейку можно заменить на ионистор, если кому-то так удобнее, благодаря низкому потреблению тока, время работы от ионисторного источника в зависимости от емкости, может достигать несколько недель, неплохо).

Характеристики:

  • для работы необходим внешний кварцевый резонатор на 32768 Гц
  • напряжение питания от 1 до 5,5 вольт
  • разрешение времени от секунд до лет
  • потребление тока 150 нА
  • максимальная частота работы I2C — 1 МГц
  • возможность подстройки частоты кварца выбором конденсаторов 7 или 12,5 пФ (внутри микросхемы)
  • функция power-on reset
  • программная подстройка частоты кварца
  • часы содержат 20 регистров

 Указатель на регистр при обращении (чтение или запись) автоматически смещается на единицу вниз. Как и во многих других микросхемах эта функция нормально так упрощает чтение и запись. 20 регистров включают в себя:

  • регистры настроек
  • регистры времени и даты
  • регистры будильника
  • регистр подстройки частоты кварца (подстройка хода часов)
  • регистры таймера

Все подробности по содержанию каждого регистра можно посмотреть в даташите. 

В целом микросхема RTC PCF8523 является весьма и весьма хорошей, как по функционалу, так и по исполнению и качеству. В сравнении с народной DS1307 единственным минусом может быть лишь цена, и то не всегда. Размер относительно одинаков, если не мелочиться, функционал в разы и разы больше.

Одним из главных вопросов является то, как же общаться с микросхемой по I2C интерфейсу. Именно по этой микросхеме PCF8523 есть одни большие грабли, точнее косяк разработчиков или инженеров — неправильная информация в даташите по этому вопросу. Спустя 2 года после выхода микросхемы на рынок, они, правда, это исправили, но если у кого-то скачан и хранится старый даташит, то лучше его перекачать. А именно, информация содержала неправильные адреса (ленивые инженеры не глядя скопировали их с микросхемы RTC PCF2129). Главное, что все же исправили.

Вот так, в соответствии с рисунком идет правильное общение (чтение или запись) с микросхемой по I2C интерфейсу:

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

Теперь, зная все про микросхему PCF8523, можно сделать часы на ее основе. Конструкция будет на основе микроконтроллера Atmega8.

Схема:

Помимо микроконтроллера Atmega8, конструкция содержит ЖК дисплей, можно использовать любой на основе контроллера HD44780 16 символов, 2 строки, линейный стабилизатор напряжения LM7805  на 5 вольт, можно заменить любым другим с аналогичными характеристиками, непосредственно сама микросхема часов реального времени PCF8523 со всей необходимой обвязкой, кнопки управления можно заменить любыми другими помимо тактовых. Также конструкция содержит реализацию будильника на основе функций PCF8523, при срабатывании будильника на ЖК дисплее загорится соответствующий символ, а также на ножке PB0 микроконтроллера будет сформирован сигнал высокого логического уровня. По схеме к этой ножке подключен светодиод для индикации, его можно заменить на любое другое устройство для сигнализации будильника — например, внешнее звуковое устройство. Тактирование микроконтроллера происходит от внутреннего RC генератора частотой 8 МГц. Дополнительные выводы микросхемы RTC присутствуют на схеме и печатной плате для модуля часов, но функционально не задействованы.

Программная реализация функционирования часов на основе микросхемы часов реального времени PCF8523 на gcc (программный код на С для работы с часами):

// функции работы с микросхемой PCF8523

void pcf8523_init(void){

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x00); // передача адреса памяти (Control)
i2c_send_byte(0b00000010); // запись значения Control_1 (по дефолту 00000000) тут общие натройки
i2c_send_byte(0b00000000); // запись значения Control_2 (по дефолту 00000000) тут по таймерам, будильнику

i2c_send_byte(0b00000000); // запись значения Control_3 (по дефолту 111-0000) тут по батарейке, значения по даташиту стр. 8-10
// контроль батреки включен (нули в 5-7 байтах), прерывания не используются
i2c_stop_cond(); // остановка i2c

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x0E); // передача адреса памяти (Offset — коррекция времени)
i2c_send_byte(0b00001000); // 0x0E даташит стр.27 (по дефолту 00000000 (без коррекции))
i2c_send_byte(0b00110000); // 0x0F CLKOUT_ctrl (сдесь включаются таймеры, а также выход CLKOUT (частота))
i2c_stop_cond(); // остановка i2c

}

void pcf8523_reset(void) {
// софт ресет до заводских параметров

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x00); // передача адреса памяти (Control)
i2c_send_byte(0b01011000); // запись значения сброса параметров в регистр Control_1
i2c_stop_cond(); // остановка i2c
}

void pcf8523_set_time(unsigned char hour1,unsigned char min1, unsigned char sec1){

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x03); // передача адреса памяти — регистры времени 3-5
i2c_send_byte(bin(sec1)); // 0x03 секунды
i2c_send_byte(bin(min1)); // 0x04 минуты
i2c_send_byte(bin(hour1)); // 0x05 часы
i2c_stop_cond(); // остановка i2c

}

// в некоторых даташитах адреса написаны неправильно, так что внимательно (за 11 год было с косяками, за 13й год все нормально)
void pcf8523_get_time(void){

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи (для чтения) — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x03); // передача адреса памяти — регистры времени 3-5
i2c_stop_cond(); // остановка i2c

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010001); // передача адреса устройства, режим чтения — 0b11010001 (1101000 — slave адрес + 1 бит чтения)
sec = bcd(i2c_get_byte(0)); // чтение секунд, ACK
min = bcd(i2c_get_byte(0)); // чтение минут, ACK
hour = bcd(i2c_get_byte(1)); // чтение часов, NACK
i2c_stop_cond(); // остановка i2c

}

void pcf8523_set_date(unsigned char day, unsigned char wday, unsigned char month, unsigned char year){

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x06); // передача адреса памяти — регистры даты 6-9
i2c_send_byte(bin(day)); // 0x06 день месяца
i2c_send_byte(bin(wday)); // 0x07 день недели (воскресенье — 0, пн 1, вт 2, ср 3, чт 4, пт 5, сб 6)
i2c_send_byte(bin(month)); // 0x08 месяц
i2c_send_byte(bin(year)); // 0x09 год
i2c_stop_cond(); // остановка i2c

}

void pcf8523_get_date(void){

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи (для чтения) — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x06); // передача адреса памяти — регистры даты 6-9
i2c_stop_cond(); // остановка i2c

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010001); // передача адреса устройства, режим чтения — 0b11010001 (1101000 — slave адрес + 1 бит чтения)
day = bcd(i2c_get_byte(0)); // чтение секунд, ACK
wday = bcd(i2c_get_byte(0)); // чтение минут, ACK
month = bcd(i2c_get_byte(0));// чтение минут, ACK
year = bcd(i2c_get_byte(1)); // чтение часов, NACK
i2c_stop_cond(); // остановка i2c

}

void pcf8523_set_alarm(unsigned char hour, unsigned char min, unsigned char start) {

// чтобы запретить будильник отправляем в минуты и часы единицу в 7й бит: 0x80 или 0b10000000 или 128 через bin

// выставить все нобходимое в Control_1 (bit AIE) и Control_2 (флаг AF) для звонка, даташит стр. 26

unsigned char r1 = 0, r2 = 0;

if(start == 1){
r1 |= (0<<7) | (bin(min)<<0);
r2 |= (0<<7) | (bin(hour)<<0);
}
else{
r1 |= (1<<7) | (bin(min)<<0);
r2 |= (1<<7) | (bin(hour)<<0);
}

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x0A); // передача адреса памяти — регистры времени будильника 0A-0B
i2c_send_byte(r1); // 0x0A минуты звонка
i2c_send_byte(r2); // 0x0B часы звонка
//i2c_send_byte(0b10000000); // 0x0C часы день (месяца) звонка — нам не надо, мы не пользуем — отключено
//i2c_send_byte(0b10000000); // 0x0D часы день (недели) звонка — нам не надо, мы не пользуем — отключено
i2c_stop_cond(); // остановка i2c

}

void pcf8523_get_alarm_time (void){

char hh5 = 0, mm5 = 0;

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи (для чтения) — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x0A); // передача адреса памяти
i2c_stop_cond(); // остановка i2c

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010001); // передача адреса устройства, режим чтения — 0b11010001 (1101000 — slave адрес + 1 бит чтения)
mm5 = i2c_get_byte(0); // чтение секунд, ACK
hh5 = i2c_get_byte(1); // чтение минут, NACK

if((hh5 & (1<<7))) alarm_on = 0; else alarm_on = 1; //
alarm_hour = bcd (hh5);
alarm_min = bcd (mm5);

i2c_stop_cond(); // остановка i2c

}

unsigned char pcf8523_get_alarm(void) {
// считываем состояние будильника для программного отслеживания звонка

char alarm = 0, get = 0;

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи (для чтения) — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x01); // передача адреса памяти
i2c_stop_cond(); // остановка i2c

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010001); // передача адреса устройства, режим чтения — 0b11010001 (1101000 — slave адрес + 1 бит чтения)
alarm = i2c_get_byte(1); // чтение регистра Control_2, NACK интересует лишь 3й байт AF (флаг состояния будильника)
i2c_stop_cond(); // остановка i2c

if((alarm & (1<<3))) get = 1; else get = 0; // если в 3 бите 1, значит будильник сработал

return get;

// для сброса звонка вызываем функцию pcf8523_alarm_reset
// флаг сработки сбрасывается в 0 и ожидается снова время сработки
// включается и выключается будильник в функции pcf8523_set_alarm переменной start

}

void pcf8523_alarm_reset(void) {
// сбросит флаг срабатывания будильника AF в Control_2 в нолик

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x01); // передача адреса памяти (Control)
i2c_send_byte(0<<3); // сдвигом записать нолик нодо тут (так же правильно??)
i2c_stop_cond(); // остановка i2c
//

}

unsigned char pcf8523_low_bat(void) {
// прочитает состояние резервной батареи (возвращаемое значение — bat, 1 — разряжена)

char low = 0, bat = 0;

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010000); // передача адреса устройства, режим записи (для чтения) — 0b11010000 (1101000 — slave адрес + 0 бит записи)
i2c_send_byte(0x02); // передача адреса памяти — регистры даты 6-9
i2c_stop_cond(); // остановка i2c

i2c_start_cond(); // запуск i2c
i2c_send_byte(0b11010001); // передача адреса устройства, режим чтения — 0b11010001 (1101000 — slave адрес + 1 бит чтения)
low = i2c_get_byte(1); // чтение регистра Control_3, NACK интересует лишь 2й байт BLF (флаг состояния резервной батареи)
i2c_stop_cond(); // остановка i2c

if((low & (1<<2))) bat = 1; else bat = 0; // если во 2 бите 1, значит разряжена

return bat;

}

bcd — перевод из двоично десятичного кода
bin — перевод в двоичный код из десятичного
Фактически, это библиотека для работы с часами PCF8523, нужно лишь оформить в .c и .h файлы.

В функции инициализации часов заложено включение необходимых нам настроек, а также значение коррекции хода часов. Коррекцию можно задать в 2-х режимах работы — сигнал коррекции каждую минуту или сигнал коррекции каждый час. В зависимости от значения, записанного в этот регистр происходит коррекция числа тиков кварца. В идеале часовой кварц должен иметь частоту 32768 Гц, но в реальности все может быть иначе. К примеру, частота кварца чуть ниже — часы будут немного отставать и наоборот, если частота чуть больше — часы будут спешить. Определение необходимого значения, которое нужно записать в регистр коррекции происходит экспериментально — в зависимости от каждодневного хода часов, либо по средствам измерения реальной частоты кварцевого резонатора.

Пример расчета коррекции частоты кварца (не самого кварца напрямую, а компенсация ошибки частоты кварца программно внутри микросхемы часов):

Результат расчета переводится в двоичную систему и записывается в регистр коррекции. Особых пояснению, думаю, не нужно.

Дополнительно частоту кварца можно регулировать внесением в схему подстроечного конденсатора, подключенного к ножке кварца. Также рекомендуют в подобных часах использовать кварцы из материнских плат, потому что они там более качественные. 

Опрос состояния кнопок происходит по прерыванию таймера 0 (прерывания по переполнению таймера). В функции main инициализируем таймер 0, порты микроконтроллера, циклический опрос времени, даты и состояний часов (вызов функций работы с часами) и вывод всего этого добра на ЖК дисплей. Так же для установки времени, даты и параметров будильника небольшая менюшка для управления переменными. Это весь состав часов.

Управление часами:

  • кнопка S2 — сброс микроконтроллера (reset, перезагрузка)
  • кнопка S4 — вход меню настроек и перелистывание уровней (часы будильника — минуты будильника — включенность будильника — и так далее, а при завершении всех уровней переход на отображение времени и даты — главное меню)
  • кнопка S3 — управление переменными (увеличение на единицу переменной, при переполнении приравнивается к 0, например, часы от 0 до 23)
  • кнопка S2 — выход из настроек, если находимся в настройках, или сброс срабатывания будильника в главном меню

Модуль часов на основе PCF8523 (печатная плата прилагается ниже):

На печатной плате расположение перемычки исправлено.

В целом часы собирались и тестировались на макетной плате:

Фьюзы для программирования микроконтроллера:

К статье прилагается печатная плата для модуля часов PCF8523, прошивка, проект протеус (8 версия, в которой как раз присутствует PCF8523 в библиотеке элементов), небольшое видео работы часов, демонстрирующее работоспособность.

Статья носит более обучающий характер или пример, нежели практический.


Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот

IC1
МК AVR 8-битATmega81
IC2
RTCPCF85231
VR1
Линейный регуляторLM7805CT1
HG1
LCD-дисплейSC16021
на базе HD44780Z1
Кварц32768 Гц1
R1
Подстроечный резистор10 кОм1
3296W-1-103LFR2,R4,R5,R7-R9
Резистор10 кОм6
R3
Резистор390 Ом1
R6
Резистор200 Ом1
C1,C4
Конденсатор220 мкФ2
С5
Конденсатор10 мкФ1
C2,C3,C6
Конденсатор100 нФ3
S1-S4
Тактовая кнопкаTC-A1094
LED1
Светодиод1

Элемент питания3 В1
cr2032Добавить все

Скачать список элементов (PDF)

Прикрепленные файлы:

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

Ваш адрес email не будет опубликован.