Привет, Хабр. Довелось мне использовать 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:
В PCF 8563 есть возможность включения будильника и его настройки на конкретное время, день недели или месяца. Настройки будильника расположены в регистра с 09h по 0Сh в двоично – десятичном формате.
Чтобы включить срабатывание будильника по каким либо настройкам, например минуты и часы надо 7-ой бит(бит включения) установить в единицу для этого используем логический операцию ИЛИ (OR) и значение B10000000.
Проверку срабатывание будильника можно осуществить 2-мя методами: хардовым и софтовым. Используя софтовый метод мы проверяем 3-ий бит регистра 0x01 (AF alarm flag bit).При срабатывании он равен единице, присвоив ему значение 0 будильник отключается.
При хардовой проверке нужно 1 бит в том же регистре(AIE) перевести в единицу. При срабатывании будильника пин INT (interrupt) на плате переходит в проводящее положение, являясь выходом с открытым стоком поэтому смело можно припаивать например светодиод с резистором и подключать это все к 5 вольтам.
Теперь сам скетч:
Как и многие RTC микросхему PCF8563 можно использовать в качестве генератора сигналов. Вывод COT (pin 7 микросхемы ) это открытый сток поэтому помигать светодиодом через этот пин можно с разной частотой.За параметры частоты отвечает регистр 0x0D.
Седьмой бит данного регистра (FE) включает генератор.Биты 0 и 1 задают требуемую частоту.Биты с 6-го по 2-ой не используются.
Записывая в регистр следующие значения можно получить нужную частоту:
Пример скетча:
Примеры форм сигналов снятого со светодиода
1 Hz
32 Hz
1.024 kHz
32.768 kHz
Установка даты и времени
Первым дела лезем в мануал (он здесь) и ищем там таблицу организации регистров.
Для установки даты и времени нам понадобится регистры с 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