Arduino I2C + DS1307实时时钟#

https://www.cnblogs.com/zlbg/p/4227428.html

主要特性#

DS1307是Maxim的串行、I2C实时时钟芯片。主要特性有:

  • 工作电压:主电源电压4.5~5.5V,电池电压2.0~3.5V

  • 功耗:电池供电、备份模式时<500nA

  • 接口:I2C,最大速率100kbps

  • 可编程方波输出

  • 电源自动切换、失效检测

  • 内置56字节大小、支持电池备份的RAM

  • 封装:8-Pin SO/PDIP

管脚定义#

img

  • X1、X2: 接32.768kHz晶体,要求晶体负载电容12.5pF

  • Vcc:主电源,范围4.5~5.5V。当需要对DS1307读写时,需要接Vcc。

  • VBAT:接电池,范围2.0~3.5V。

  • GND:地

  • SDA、SCL:I2C接口数据线、时钟线。

  • SQW/OUT:方波输出脚、通过写寄存器来使能。

与Arduino的连接#

采用I2C接口与Arduino连接。SQW/OUT脚亦为开漏(open-drain)设计,需要接上拉电阻。

img

DS1307的VCC脚接Arduino UNO的5V;GND脚接Arduino UNO的GND;SDA脚接Arduino UNO的A4(SDA);SCL脚接Arduino UNO的A5(SCL)。

功能调试#

  1. 写寄存器时,先写入寄存器指针(Register pointer),之后依次写入寄存器内容。每写入一个字节,Register pointer都自动加一。

  2. 读寄存器时,也是先写入Register pointer,之后发Sr(Repeated start),依次读出寄存器内容。同样的,每读出一个字节,Register pinter都自动加一。

测试代码#

  1. 首先设置DS1307时间。代码中timeDec数组保存的是当前时间,根据实际调整。

/*
real time clock using DS1307
function: set the time
*/

#include <Wire.h>

#define ADDRESS_DS1307 0x68

byte timeDec[] = {15, 1, 15, 5, 19, 20, 0};
byte timeBcd[] = {0, 0, 0, 0, 0, 0, 0};
//time = {year, month, date, day, hours, minutes, seconds};

void setup()
{
    Wire.begin();
    Serial.begin(9600);

    //convert decimal to BCD code
    int i;
    for (i = 0; i < 7; i++)
    {
        timeBcd[i] = DecToBcd(timeDec[i]);
    }

    //set the time
    Wire.beginTransmission(ADDRESS_DS1307);
    Wire.write(0x00);
    for (i = 0; i < 7; i++)
    {
        Wire.write(timeBcd[6-i]);
    }
    Wire.endTransmission();

    Serial.println("Time has been set.");

}

void loop()
{
    delay(4000);
}

// Convert normal decimal numbers to binary coded decimal
byte DecToBcd(byte val)
{
    byte res;
    if ((val <= 99) && (val >= 0))
    {
        res = ((val/10)<<4) | (val%10);
    }
    else
    {
        res = 0;
        Serial.println("Error");
    }
    return res;
}
// Convert binary coded decimal to normal decimal numbers
byte BcdToDec(byte val)
{
    byte res;
    if (val <= 0x99)
    {
        res = (val >> 4)*10 + (val & 0x0F);
    }
    else
    {
        res = 0;
        Serial.println("Error");
    }
    return res;
}
  1. 之后可以向DS1307获取实时时间。

/*
real time clock using DS1307
function: read the time
*/

#include <Wire.h>

#define ADDRESS_DS1307 0x68

byte timeBcd[] = {0, 0, 0, 0, 0, 0, 0};
//time = {year, month, date, day, hours, minutes, seconds};

void setup()
{
    Wire.begin();
    Serial.begin(9600);
}

void loop()
{
    //read the time
    Wire.beginTransmission(ADDRESS_DS1307);
    Wire.write(0x00);
    Wire.endTransmission();
    Wire.requestFrom(ADDRESS_DS1307, 7);
    if (Wire.available() >= 7)
    {
        for (int i = 0; i < 7; i++)
        {
            timeBcd[6-i] = Wire.read();
        }
    }

    //print
    Serial.print("20"); Serial.print(timeBcd[0], HEX); Serial.print("/");
    Serial.print(timeBcd[1], HEX); Serial.print("/"); Serial.print(timeBcd[2], HEX);
    Serial.print(" "); Serial.print(BcdToDay(timeBcd[3])); Serial.print(" ");
    Serial.print(timeBcd[4], HEX); Serial.print(":");
    Serial.print(timeBcd[5], HEX); Serial.print(":");
    Serial.print(timeBcd[6], HEX); Serial.println();

    delay(1000);
}


// Convert binary coded decimal to day
String BcdToDay(byte val)
{
    String res;
    switch(val)
    {
        case 1: res = "Sunday"; break;
        case 2: res = "Monday"; break;
        case 3: res = "Tuesday"; break;
        case 4: res = "Wednesday"; break;
        case 5: res = "Thursday"; break;
        case 6: res = "Friday"; break;
        case 7: res = "Saturday"; break;
        default: res = "Error!";
    }
    return res;
}

程序运行后,通过串口打印当前时间如下图。

img

  1. 通过设置控制寄存器,可以设置SQW/OUT管脚输出高电平、低电平或某个频率的方波。方波支持的频率有1Hz、4.096kHz、8.192kHz、32.768kHz。以下代码设置的频率为32.768kHz。

img View Code

与示波器测试的信号图形相符。

img

参考资料#

Maxim - DS1307 64x8、串行、I²C实时时钟 Tutorial – Using DS1307 and DS3231 Real-time Clock Modules with Arduino Digital Clock with Arduino and DS1307 Assemble an Adafruit DS1307 Real Time Clock Kit