从Arduino到I2C的PCF8563实时时钟之友

哈Ha 我碰巧在使用I2C的PCF 8563芯片上使用RTC,因为我没有找到正常的功能来使用Arduino进行更方便的工作,所以我不得不直接通过I2C进行工作。 我英语Internet 找到了解释性教程,其中对该过程进行了详细描述 。 本文部分是对RTC自身经验的部分翻译。



设定日期和时间


首先,我们进入手册( 在此处 ),并在其中查找一份登记册组织表。



要设置日期和时间,我们需要从02h到08h的寄存器。 这些寄存器中的数据以二进制十进制格式(BCD)存储,因此可以记录秒,分钟等。 首先,我们实现转换功能(从十进制格式到BCD,反之亦然),然后使用Wire.write()命令将它们写入从02h开始的寄存器中。 从相同的寄存器02h开始,我们以相同的方式从BCD转换回十进制。 从表中可以看出,某些寄存器中未使用位(用字母x表示),为了不使读取时信息过载,我们将使用按位与运算(逻辑“与”),它将重置我们不需要的位。 例如,一个月中的几天(Days),我们需要位0到5,使用操作(dayOfMonth&B00111111)我们重置6位和7位,其他所有内容都保持不变。

直接将代码本身与信息输出在串行监视器上:

#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到0h的寄存器中。



要通过某些设置(例如分钟和小时)启用警报,您需要将第7位(启用位)设置为1,为此,请使用逻辑运算OR(或)和值B10000000。

可以通过两种方式检查警报的运行情况:硬警报和软警报。 使用软方法,我们检查寄存器0x01的第3位(AF警报标志位),触发后等于3,将其设置为0,警报响起。



为了进行硬验证,您需要将同一寄存器(AIE)中的1位转换为1。 警报响起时,开发板上的INT(中断)引脚将进入导通状态,成为漏极开路输出,因此您可以安全地用电阻焊接LED,例如将其连接至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引脚(微电路的引脚7)是开漏的,因此您可以通过该引脚以不同的频率使LED闪烁,寄存器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); } 


从LED获取的波形示例

1赫兹



32赫兹



1.024 kHz



32.768 kHz

Source: https://habr.com/ru/post/zh-CN463265/


All Articles