- PVSM.RU - https://www.pvsm.ru -

Дружим часы реального времени PCF8563 с Arduino по I2C

Привет. Довелось мне использовать RTC на микросхеме PCF 8563 по I2C.Так как нормальных функции для более удобной работы с Arduino я не нашел, пришлось работать напрямую через I2C. В Англоязычном интернете нашел толковый туториал с подробным описанием процесса [1]. Данная статья является отчасти переводом отчасти собственным опытом работы с этой RTC.

Дружим часы реального времени PCF8563 с Arduino по I2C - 1

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

Первым дела лезем в мануал (он здесь [2]) и ищем там таблицу организации регистров.

Дружим часы реального времени PCF8563 с Arduino по I2C - 2

Для установки даты и времени нам понадобится регистры с 02h по 08h. Данные в этих регистрах хранятся в двоично – десятичном формате (BCD), поэтому для записи секунд, минут и т.д. сначала реализуем функцию перевода (из десятичного формата в BCD и обратно) а затем командой Wire.write() пишем их в регистры начиная с 02h. Считываем по той же схеме переводя из BCD обратно в десятичную систему, начиная с того же регистра 02h. Как видно из таблицы биты в некоторых регистрах не используются (обозначены буквой x), дабы не нацеплять лишней информации при чтении будем использовать битовую операцию AND (логическое «И») которое обнулит ненужные нам биты. К примеру дни месяца (Days), на нужны биты с 0 по 5-ый, используя операцию (dayOfMonth & B00111111) обнуляем 6 и 7 бит, все остальное остается нетронутым.

Непосредственно сам код с выводом информации на serial monitor:

#include "Wire.h"
#define PCF8563address 0x51 // Адрес устройства по умолчанию 

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
String days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

// функция перевода из двоично - десятичной системы в десятичную.
byte bcdToDec(byte value)
{
 return ((value / 16) * 10 + value % 16);
}
// И обратно
byte decToBcd(byte value){
 return (value / 10 * 16 + value % 10);
}

// функция установки времени и даты в PCF8563
void setPCF8563()
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x02);
 Wire.write(decToBcd(second)); 
 Wire.write(decToBcd(minute));
 Wire.write(decToBcd(hour));   
 Wire.write(decToBcd(dayOfMonth));
 Wire.write(decToBcd(dayOfWeek)); 
 Wire.write(decToBcd(month));
 Wire.write(decToBcd(year));
 Wire.endTransmission();
}

// функция считывания времени и даты из PCF8563
void readPCF8563()
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x02);
 Wire.endTransmission();
 Wire.requestFrom(PCF8563address, 7);
 second   = bcdToDec(Wire.read() & B01111111); // удаление ненужных бит из данных 
 minute   = bcdToDec(Wire.read() & B01111111); 
 hour    = bcdToDec(Wire.read() & B00111111); 
 dayOfMonth = bcdToDec(Wire.read() & B00111111);
 dayOfWeek = bcdToDec(Wire.read() & B00000111); 
 month   = bcdToDec(Wire.read() & B00011111); 
 year    = bcdToDec(Wire.read());
}
void setup()
{
 Wire.begin();
 Serial.begin(9600);
 // Выставляем время и дату 
 second = 0;
 minute = 28;
 hour = 9;
 dayOfWeek = 2;
 dayOfMonth = 13;
 month = 8;
 year = 13;
 setPCF8563();
}
void loop()
{
 readPCF8563();
 Serial.print(days[dayOfWeek]); 
 Serial.print(" "); 
 Serial.print(dayOfMonth, DEC);
 Serial.print("/");
 Serial.print(month, DEC);
 Serial.print("/20");
 Serial.print(year, DEC);
 Serial.print(" - ");
 Serial.print(hour, DEC);
 Serial.print(":");
 if (minute < 10)
 {
  Serial.print("0");
 }
 Serial.print(minute, DEC);
 Serial.print(":"); 
 if (second < 10)
 {
  Serial.print("0");
 } 
 Serial.println(second, DEC); 
 delay(1000);
}

Установка будильника

В PCF 8563 есть возможность включения будильника и его настройки на конкретное время, день недели или месяца. Настройки будильника расположены в регистра с 09h по 0Сh в двоично – десятичном формате.

Дружим часы реального времени PCF8563 с Arduino по I2C - 3

Чтобы включить срабатывание будильника по каким либо настройкам, например минуты и часы надо 7-ой бит(бит включения) установить в единицу для этого используем логический операцию ИЛИ (OR) и значение B10000000.

Проверку срабатывание будильника можно осуществить 2-мя методами: хардовым и софтовым. Используя софтовый метод мы проверяем 3-ий бит регистра 0x01 (AF alarm flag bit).При срабатывании он равен единице, присвоив ему значение 0 будильник отключается.

Дружим часы реального времени PCF8563 с Arduino по I2C - 4

При хардовой проверке нужно 1 бит в том же регистре(AIE) перевести в единицу. При срабатывании будильника пин INT (interrupt) на плате переходит в проводящее положение, являясь выходом с открытым стоком поэтому смело можно припаивать например светодиод с резистором и подключать это все к 5 вольтам.

Теперь сам скетч:

листинг

#include "Wire.h"
#define PCF8563address 0x51

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte alarmMinute, alarmHour, alarmDay, alarmDayOfWeek;
String days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

byte bcdToDec(byte value)
{
 return ((value / 16) * 10 + value % 16);
}

byte decToBcd(byte value){
 return (value / 10 * 16 + value % 10);
}

// Функция устанавливающая дату и время в будильник 
void setPCF8563alarm()
{
 byte am, ah, ad, adow;
 am = decToBcd(alarmMinute);
 am = am | 100000000; // Установка бита включение будильника по минутам   
 ah = decToBcd(alarmHour);
 ah = ah | 100000000; // Установка бита включение будильника по часам  
 ad = decToBcd(alarmDay);
 ad = ad | 100000000; // Установка бита включение будильника по дням месяца
 adow = decToBcd(alarmDayOfWeek);
 adow = ad | 100000000; //Установка бита включение будильника по дням недели

 // запись минут и часов срабатывания будильника на PCF8563
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x09);
 Wire.write(am); 
 Wire.write(ah);

 // опционально. запись дня месяца и недели на срабатывания будильника
 /*
 Wire.write(ad);
 Wire.write(adow); 
 */
 Wire.endTransmission();
  
 // опционально . включение INT пина при хардовой проверки
 // отключается при использование функции PCF8563alarmOff()

 Wire.beginTransmission(PCF8563address);
 Wire.write(0x01);
 Wire.write(B00000010);
 Wire.endTransmission();
}

void PCF8563alarmOff()
// функция выключения будильника с обнулением регистра.
{
 byte test;
 // получение значения регистра 0x01h
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x01);
 Wire.endTransmission();
 Wire.requestFrom(PCF8563address, 1);
 test = Wire.read();

 // установка 3 го бита в 0 
 test = test - B00001000;

 // запись нового значения в регистр 0x01h
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x01);
 Wire.write(test);
 Wire.endTransmission();
}

void checkPCF8563alarm()
// проверка срабатывания будильника
{
 byte test;
 // получение значения регистра 0x01h и присваивание его переменной test
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x01);
 Wire.endTransmission();
 Wire.requestFrom(PCF8563address, 1);
 test = Wire.read();
 test = test & B00001000; 
 if (test == B00001000) // Проверка на срабатывание
 {
    Serial.println("** alarm **");
    delay(2000);

  // Выключаем будильник после срабатывания 
  PCF8563alarmOff();
 }
}

void setPCF8563()
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x02);
 Wire.write(decToBcd(second)); 
 Wire.write(decToBcd(minute));
 Wire.write(decToBcd(hour));   
 Wire.write(decToBcd(dayOfMonth));
 Wire.write(decToBcd(dayOfWeek)); 
 Wire.write(decToBcd(month));
 Wire.write(decToBcd(year));
 Wire.endTransmission();
}

void readPCF8563()
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x02);
 Wire.endTransmission();
 Wire.requestFrom(PCF8563address, 7);
 second   = bcdToDec(Wire.read() & B01111111); 
 minute   = bcdToDec(Wire.read() & B01111111);
 hour    = bcdToDec(Wire.read() & B00111111); 
 dayOfMonth = bcdToDec(Wire.read() & B00111111);
 dayOfWeek = bcdToDec(Wire.read() & B00000111); 
 month   = bcdToDec(Wire.read() & B00011111); 
 year    = bcdToDec(Wire.read());
}

void setup()
{
 Wire.begin();
 Serial.begin(9600);
 second = 50;
 minute = 44;
 hour = 13;
 dayOfWeek = 1;
 dayOfMonth = 19;
 month = 8;
 year = 13;
 setPCF8563();
 // Установка даты и времени срабатывания будильника 
 alarmMinute = 45;
 alarmHour = 13;
 setPCF8563alarm();
}
void loop()
{
 readPCF8563();
 Serial.print(days[dayOfWeek]); 
 Serial.print(" "); 
 Serial.print(dayOfMonth, DEC);
 Serial.print("/");
 Serial.print(month, DEC);
 Serial.print("/20");
 Serial.print(year, DEC);
 Serial.print(" - ");
 Serial.print(hour, DEC);
 Serial.print(":");
 if (minute < 10)
 {
  Serial.print("0");
 }
 Serial.print(minute, DEC);
 Serial.print(":"); 
 if (second < 10)
 {
  Serial.print("0");
 } 
 Serial.println(second, DEC); 
 delay(1000);

 //Проверка будильника 
 checkPCF8563alarm();
}

Использование в качестве генератора

Как и многие RTC микросхему PCF8563 можно использовать в качестве генератора сигналов. Вывод COT (pin 7 микросхемы ) это открытый сток поэтому помигать светодиодом через этот пин можно с разной частотой.За параметры частоты отвечает регистр 0x0D.

Дружим часы реального времени PCF8563 с Arduino по I2C - 5

Седьмой бит данного регистра (FE) включает генератор.Биты 0 и 1 задают требуемую частоту.Биты с 6-го по 2-ой не используются.

Записывая в регистр следующие значения можно получить нужную частоту:

  • 10000000 — 32.768 kHz;
  • 10000001 — 1.024 kHz;
  • 10000010 — 32 Hz;
  • 10000011 — 1 Hz;
  • 0 — отключение вывода;

Пример скетча:

#include "Wire.h"
#define PCF8563address 0x51

void PCF8563oscOFF()
// Выключение генератора
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x0D);
 Wire.write(0);
 Wire.endTransmission();
}

void PCF8563osc1Hz()
// настройка генератора на 1 Hz
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x0D);
 Wire.write(B10000011);
 Wire.endTransmission();
}

void PCF8563osc32Hz()
// настройка генератора на 32 Hz
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x0D);
 Wire.write(B10000010);
 Wire.endTransmission();
}

void PCF8563osc1024kHz()
// настройка генератора на 1.024 kHz
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x0D);
 Wire.write(B10000001);
 Wire.endTransmission();
}

void PCF8563osc32768kHz()
// настройка генератора на 32.768 kHz
{
 Wire.beginTransmission(PCF8563address);
 Wire.write(0x0D);
 Wire.write(B10000000);
 Wire.endTransmission();
}

void setup()
{
 Wire.begin();
}

void loop()
{
 PCF8563osc1Hz();
 delay(2000);
 PCF8563osc32Hz();
 delay(2000);
 PCF8563osc1024kHz();
 delay(2000);
 PCF8563osc32768kHz();
 delay(2000);
 PCF8563oscOFF();
 delay(2000);
}

Примеры форм сигналов снятого со светодиода

1 Hz

Дружим часы реального времени PCF8563 с Arduino по I2C - 6

32 Hz

Дружим часы реального времени PCF8563 с Arduino по I2C - 7

1.024 kHz

Дружим часы реального времени PCF8563 с Arduino по I2C - 8

32.768 kHz

Дружим часы реального времени PCF8563 с Arduino по I2C - 9

Автор: burguroom12

Источник [3]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/razrabotka-pod-arduino/326736

Ссылки в тексте:

[1] толковый туториал с подробным описанием процесса: https://tronixstuff.com/2013/08/13/tutorial-arduino-and-pcf8563-real-time-clock-ic/

[2] он здесь: https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf

[3] Источник: https://habr.com/ru/post/463265/?utm_source=habrahabr&utm_medium=rss&utm_campaign=463265