Hallo Habr. Ich habe zufällig RTC auf dem PCF 8563-Chip mit I2C verwendet. Da ich keine normalen Funktionen für eine bequemere Arbeit mit Arduino gefunden habe, musste ich direkt über I2C arbeiten. Ich habe
im englischen Internet ein
erklärendes Tutorial mit einer detaillierten Beschreibung des Prozesses gefunden . Dieser Artikel ist teilweise eine Übersetzung aus seiner eigenen Erfahrung mit diesem RTC.

Datum und Uhrzeit einstellen
Als erstes klettern wir in das Handbuch (
es ist hier ) und suchen dort nach einer Tabelle der Registerorganisation.

Um Datum und Uhrzeit einzustellen, benötigen wir Register von 02h bis 08h. Die Daten in diesen Registern werden daher im binären Dezimalformat (BCD) gespeichert, um Sekunden, Minuten usw. aufzuzeichnen. Zuerst implementieren wir die Übersetzungsfunktion (vom Dezimalformat nach BCD und umgekehrt) und schreiben sie dann mit dem Befehl Wire.write () ab 02h in Register. Wir lesen auf die gleiche Weise und übertragen von BCD zurück zum Dezimalsystem, beginnend mit demselben Register 02h. Wie Sie der Tabelle entnehmen können, werden in einigen Registern (angezeigt durch den Buchstaben x) keine Bits verwendet. Um Informationen beim Lesen nicht zu überladen, verwenden wir die bitweise UND-Verknüpfung (logisches „UND“), mit der die nicht benötigten Bits zurückgesetzt werden. Zum Beispiel benötigen wir an den Tagen des Monats (Tage) die Bits 0 bis 5, wobei wir mit der Operation (dayOfMonth & B00111111) die 6 und 7 Bits zurücksetzen, alles andere bleibt unberührt.
Direkt der Code selbst mit der Ausgabe von Informationen auf einem seriellen 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); }
Alarm einstellen
In PCF 8563 können Sie den Alarm aktivieren und für eine bestimmte Zeit, einen bestimmten Wochentag oder einen bestimmten Monat einstellen. Die Alarmeinstellungen befinden sich im Register von 09h bis 0h im binären Dezimalformat.

Damit der Alarm gemäß einigen Einstellungen, z. B. Minuten und Stunden, funktioniert, müssen Sie das 7. Bit (Aktivierungsbit) auf eins setzen. Verwenden Sie dazu die logische Operation ODER (ODER) und den Wert B10000000.
Die Überprüfung der Alarmfunktion kann auf zwei Arten erfolgen: hart und weich. Mit der Soft-Methode prüfen wir das 3. Bit des Registers 0x01 (AF-Alarmflag-Bit). Wenn es ausgelöst wird, ist es gleich eins und weist ihm den Wert 0 zu. Der Alarm wird ausgelöst.

Für eine harte Überprüfung müssen Sie 1 Bit im selben Register (AIE) in eins übersetzen. Wenn der Alarm ausgelöst wird, befindet sich der INT-Pin (Interrupt) auf der Platine in einer leitenden Position und ist ein Open-Drain-Ausgang, sodass Sie beispielsweise eine LED mit einem Widerstand sicher löten und alles an 5 Volt anschließen können.
Nun die Skizze selbst:
Auflistung #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(); }
Verwendung als Generator
Wie viele RTCs kann der PCF8563 als Signalgenerator verwendet werden. Der COT-Pin (Pin 7 der Mikroschaltung) ist ein offener Drain, sodass Sie eine LED mit einer anderen Frequenz durch diesen Pin blinken können. Das Register 0x0D ist für die Frequenzparameter verantwortlich.

Das siebte Bit dieses Registers (FE) schaltet den Generator ein. Die Bits 0 und 1 stellen die gewünschte Frequenz ein. Die Bits 6 bis 2 werden nicht verwendet.
Wenn Sie die folgenden Werte in das Register schreiben, können Sie die gewünschte Frequenz erhalten:
- 10000000 - 32,768 kHz;
- 10000001 - 1,024 kHz;
- 10000010 - 32 Hz;
- 10000011-1 Hz;
- 0 - Ausgabe deaktivieren;
Skizzenbeispiel:
#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); }
Beispiele für Wellenformen von der LED1 Hz
32 Hz
1,024 kHz
32,768 kHz