Хабрахабр

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

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

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

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

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

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

#include "Wire.h"
#define PCF8563address 0x51 // Адрес устройства по умолчанию byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
String days[] = ; // функция перевода из двоично - десятичной системы в десятичную.
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.

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

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

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

листинг

#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

024 kHz 1.

768 kHz 32.

Теги
Показать больше

Похожие статьи

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

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

Кнопка «Наверх»
Закрыть