Amigos do relógio em tempo real PCF8563 do Arduino ao I2C

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 LED

1 Hz



32 Hz



1.024 kHz



32.768 kHz

Source: https://habr.com/ru/post/pt463265/


All Articles