Oi Habr. Por acaso, usei o RTC no chip PCF 8563 via I2C. Como não encontrei funções normais para um trabalho mais conveniente com o Arduino, tive que trabalhar diretamente através do I2C. Encontrei um
tutorial explicativo na Internet em inglês
com uma descrição detalhada do processo . Este artigo é parcialmente uma tradução em parte de sua própria experiência com este RTC.

Definir data e hora
A primeira coisa que entramos no manual (
é aqui ) e procuramos uma tabela de organização de registros lá.

Para definir a data e a hora, precisamos de registros das 02h às 08h. Os dados nesses registradores são armazenados em formato decimal binário (BCD), portanto, para gravar segundos, minutos, etc. primeiro, implementamos a função de conversão (do formato decimal para o BCD e vice-versa) e, em seguida, com o comando Wire.write (), as escrevemos nos registros a partir das 02h. Lemos da mesma maneira, transferindo do BCD de volta para o sistema decimal, começando no mesmo registro 02h. Como você pode ver na tabela, os bits não são usados em alguns registros (indicados pela letra x), para não sobrecarregar as informações durante a leitura, usaremos a operação de bit AND (lógica "AND") que redefinirá os bits que não precisamos. Por exemplo, nos dias do mês (Dias), precisamos dos bits 0 a 5, usando a operação (dayOfMonth & B00111111) redefinimos os 6 e 7 bits, tudo o resto permanece intocado.
Diretamente o próprio código com a saída de informações em um monitor serial:
#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); }
Definir um alarme
No PCF 8563, você pode ativar o alarme e configurá-lo para um horário específico, dia da semana ou mês. As configurações de alarme estão localizadas no registro de 09h a 0h no formato decimal binário.

Para ativar o alarme em algumas configurações, por exemplo, minutos e horas, é necessário definir o 7º bit (bit de habilitação) como 1. Para isso, use a operação lógica OR (OR) e o valor B10000000.
A verificação do funcionamento do alarme pode ser feita de duas maneiras: forte e suave. Utilizando o método soft, verificamos o terceiro bit do registrador 0x01 (bit de sinalizador de alarme AF) Quando acionado, é igual a um, configurando-o para 0, o alarme dispara.

Para verificação rígida, você precisa converter 1 bit no mesmo registro (AIE) em um. Quando o alarme dispara, o pino INT (interrupção) na placa entra em uma posição condutora, sendo uma saída de dreno aberto, para que você possa soldar com segurança um LED com um resistor, por exemplo, e conectar tudo a 5 volts.
Agora o próprio esboço:
listagem #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(); }
Use como gerador
Como muitos RTCs, o PCF8563 pode ser usado como um gerador de sinal. O pino COT (pino 7 do microcircuito) é um dreno aberto, para que você possa piscar um LED através desse pino com uma frequência diferente.O registro 0x0D é responsável pelos parâmetros de frequência.

O sétimo bit deste registrador (FE) liga o gerador.Os bits 0 e 1 definem a frequência desejada.Os bits 6 a 2 não são utilizados.
Escrevendo os seguintes valores no registro, você pode obter a frequência desejada:
- 10000000 - 32,768 kHz;
- 10000001 - 1,024 kHz;
- 10000010 - 32 Hz;
- 10000011 - 1 Hz;
- 0 - desativar saída;
Exemplo de esboço:
#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); }
Exemplos de formas de onda retiradas do LED1 Hz
32 Hz
1.024 kHz
32.768 kHz