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

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



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


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



Для установки даты и времени нам понадобится регистры с 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 в двоично – десятичном формате.



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

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



При хардовой проверке нужно 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.



Седьмой бит данного регистра (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



32 Hz



1.024 kHz



32.768 kHz

Источник: https://habr.com/ru/post/463265/


Интересные статьи

Интересные статьи

Надпись “Поддержка Flash Player будет прекращена в декабре 2020 года” в браузере способна вызвать различные эмоции у пользователей, начиная от облегчения, что де уязвимости решены, до осо...
Я активно интересуюсь роботами, и недавно сделал двуногого робота под управлением Arduino. После этого я захотел сделать четвероногого робота, имитирующего таких животных, как собаки ...
Новая методика взлома преодолевает проблему «джиттера сети», которая может влиять на успешность атак по сторонним каналам Новая методика, разработанная исследователями Левенско...
Всем привет. В этой статье расскажу о том, как мне удалось реализовать управление Arduino через интернет с помощью подключенного к интернету ПК. В общем случае данный способ можно использовать дл...
Однажды, в понедельник, мне пришла в голову мысль — "а покопаюсь ка я в новом ядре" (новым относительно, но об этом позже). Мысль не появилась на ровном месте, а предпосылками для нее стали: ...