Как стать автором
Обновить

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

Время на прочтение6 мин
Количество просмотров17K
Привет, Хабр. Довелось мне использовать 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

Теги:
Хабы:
Всего голосов 10: ↑9 и ↓1+8
Комментарии8

Публикации

Истории

Ближайшие события

Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург