Дружим часы реального времени 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/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *