单片机
返回首页

STC8H开发(十三): I2C驱动DS3231高精度实时时钟芯片

2022-07-21 来源:csdn

DS3231简介

DS3231是高精度I2C实时时钟芯片, I2C总线地址为固定的0xD0


内置温度补偿晶体振荡源(TCXO), 降低温度变化造成的晶体频率漂移, 在[-40°C, 85°C]范围内误差 ±0.432s/Day.

秒、分、时、星期、日期、月、年, 闰年补偿, 计数年份区间为[1990, 2190]

两个可编程闹钟, 可以按周或按日重复

方波输出

供电 2.3V – 5.5V (typical: 3.3V)

工作电流 200 – 300 μA

待机电流 110 – 170 μA

电池工作电流 70 – 150 μA

时间保持电池电流 0.84 – 3.5 μA


DS3231管脚和典型电路

32KHz - 32.768KHz输出(50%占空比), 漏极开路输出, 需要上拉电阻, 如不使用可保持开路.

VCC

INT/SQW - 低电平有效中断或方波输出(1Hz, 4kHz, 8kHz or 32kHz)

RST - 低电平有效复位引脚

GND

VBAT - 备用电源

SDA - I2C 数据

SCL - I2C 时钟

ZS-042模块

在某宝上最常见的DS3231是 ZS-042 模块, 模块集成一个CR2032电池座和一个AT24C32的8K字节EEPROM存储, 后者可以通过同一个I2C总线访问.


CR2032电池座

当电源中断时为DS3231提供备用电源


板载 AT24C32 EEPROM

存储芯片 AT24C32, 容量 32K Bit = 4K Byte, 地址可通过短路 A0/A1/A2修改, 根据 24C32 的数据手册, 这三个bit对应的是7位I2C地址的第五到第七位


1 0 1 0  A2 A1 A0 R/W


A0至A2内部电阻上拉, 开路为1, 短路为0, 不同的组合可以产生8个不同的地址, 默认全开路对应的地址为0xAE


使用STC8H3K驱动DS3231

接线

AT24C32的3对触点都保持开路


P32   -> SCL

P33   -> SDA

GND   -> GND

3.3V  -> VCC


示例代码

代码下载地址


Gitee https://gitee.com/iosetting/fw-lib_-stc8/tree/master/demo/i2c/ds3231

GitHub https://github.com/IOsetting/FwLib_STC8/tree/master/demo/i2c/ds3231

代码会将DS3231时间设置为 2022-07-10 14:21:10, 然后每隔一秒显示一次时间, 数值为十六进制


20-07-0A 0E:15:1E 00 00␍␊

20-07-0A 0E:15:1F 00 00␍␊

20-07-0A 0E:15:20 00 00␍␊

20-07-0A 0E:15:21 00 00␍␊

20-07-0A 0E:15:22 00 00␍␊


初始化I2C接口

使用P32和P33


void I2C_Init(void)

{

    // Master mode

    I2C_SetWorkMode(I2C_WorkMode_Master);

    /**

     * I2C clock = FOSC / 2 / (__prescaler__ * 2 + 4)

    */

    I2C_SetClockPrescaler(0x1F);

    // Switch alternative port

    I2C_SetPort(I2C_AlterPort_P32_P33);

    // Start I2C

    I2C_SetEnabled(HAL_State_ON);

}


void GPIO_Init(void)

{

    // SDA

    GPIO_P3_SetMode(GPIO_Pin_3, GPIO_Mode_InOut_QBD);

    // SCL

    GPIO_P3_SetMode(GPIO_Pin_2, GPIO_Mode_Output_PP);

}


基础I2C接口读写方法

#define DS3231_I2C_ADDR                 0xD0


uint8_t DS3231_Write(uint8_t reg, uint8_t dat)

{

    return I2C_Write(DS3231_I2C_ADDR, reg, &dat, 1);

}


uint8_t DS3231_MultipleRead(uint8_t reg, uint8_t *buf, uint8_t len)

{

    return I2C_Read(DS3231_I2C_ADDR, reg, buf, len);

}


BCD码与HEX的转换

uint8_t DS3231_Hex2Bcd(uint8_t hex)

{

    return (hex % 10) + ((hex / 10) << 4);

}


uint8_t DS3231_Bcd2Hex(uint8_t bcd)

{

    return (bcd >> 4) * 10 + (bcd & 0x0F);

}


读取时间

读取时间并转换为HEX, 使用一个uint8_t数组, 结构为


/**

    uint8_t year;

    uint8_t month;

    uint8_t week;

    uint8_t date;

    uint8_t hour;

    uint8_t minute;

    uint8_t second;

    DS3231_HourFormat_t format;

    DS3231_AmPm_t am_pm;

 */


从DS3231中读出时间


uint8_t DS3231_GetTime(uint8_t *t)

{

    uint8_t res;

    res = I2C_Read(DS3231_I2C_ADDR, DS3231_REG_SECOND, buff, 7);

    if (res != HAL_OK)

    {

        return res;

    }

    t[0] = DS3231_Bcd2Hex(buff[6]) + ((buff[5] >> 7) & 0x01) * 100; // year

    t[1] = DS3231_Bcd2Hex(buff[5] & 0x1F);                          // month

    t[2] = DS3231_Bcd2Hex(buff[3]); // week

    t[3] = DS3231_Bcd2Hex(buff[4]); // date

    t[7] = (buff[2] >> 6) & 0x01; // 12h/24h

    t[8] = (buff[2] >> 5) & 0x01; // am/pm

    if (t[7] == DS3231_FORMAT_12H)

    {

        t[4] = DS3231_Bcd2Hex(buff[2] & 0x1F); // hour

    }

    else

    {

        t[4] = DS3231_Bcd2Hex(buff[2] & 0x3F); // hour

    }

    t[5] = DS3231_Bcd2Hex(buff[1]); // minute

    t[6] = DS3231_Bcd2Hex(buff[0]); // second

    return HAL_OK;

}


设置时间

先校验各时间数值, 然后通过地址分别写入


uint8_t DS3231_SetTime(uint8_t *t)

{

    uint8_t res, reg;


    // Time validation

    if (t[0] > 200) t[0] = 200; // year


    if (t[1] == 0) t[1] = 1; // month

    else if (t[1] > 12) t[1] = 12;


    if (t[2] == 0) t[2] = 1; // week

    else if (t[2] > 7) t[2] = 7;


    if (t[3] == 0) t[3] = 1; // date

    else if (t[3] > 31) t[3] = 31;


    if (t[7] == DS3231_FORMAT_12H)

    {

        if (t[4] > 12) t[4] = 12; // hour

    }

    else if (t[7] == DS3231_FORMAT_24H)

    {

        if (t[4] > 23) t[4] = 23; // hour

    }


    if (t[5] > 59) t[5] = 59; // minute

    if (t[6] > 59) t[6] = 59; // second


    res = DS3231_Write(DS3231_REG_SECOND, DS3231_Hex2Bcd(t[6]));

    if (res != HAL_OK) return res;


    res = DS3231_Write(DS3231_REG_MINUTE, DS3231_Hex2Bcd(t[5]));

    if (res != HAL_OK) return res;


    if (t[7] == DS3231_FORMAT_12H)

    {

        reg = (uint8_t)((1 << 6) | (t[8] << 5) | DS3231_Hex2Bcd(t[4]));

    }

    else

    {

        reg = (0 << 6) | DS3231_Hex2Bcd(t[4]);

    }

    res = DS3231_Write(DS3231_REG_HOUR, reg);

    if (res != HAL_OK) return res;


    res = DS3231_Write(DS3231_REG_WEEK, DS3231_Hex2Bcd(t[2]));

    if (res != HAL_OK) return res;


    res = DS3231_Write(DS3231_REG_DATE, DS3231_Hex2Bcd(t[3]));

    if (res != HAL_OK) return res;


    if (t[0] >= 100)

    {

        res = DS3231_Write(DS3231_REG_MONTH, DS3231_Hex2Bcd(t[1]) | (1 << 7));

        if (res != HAL_OK) return res;

        return DS3231_Write(DS3231_REG_YEAR, DS3231_Hex2Bcd(t[0] - 100));

    }

    else

    {

        res = DS3231_Write(DS3231_REG_MONTH, DS3231_Hex2Bcd(t[1]));

        if (res != HAL_OK) return res;

        return DS3231_Write(DS3231_REG_YEAR, DS3231_Hex2Bcd(t[0]));

    }

}


读写ZS-042模块中的AT24C32

参考前面一篇 STC8H开发(十二): I2C驱动AT24C08,AT24C32系列EEPROM存储


参考

DS3231的模块ZS-042的讨论, 分析了5V供电时的电池充电问题和改造 https://forum.arduino.cc/t/zs-042-ds3231-rtc-module/268862/24

AT24C 的读写 https://www.likecs.com/show-204385163.html

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 用NE555制作定时器

    相关电子头条文章