目录

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管脚和典型电路

  1. 32KHz - 32.768KHz输出(50%占空比), 漏极开路输出, 需要上拉电阻, 如不使用可保持开路.
  2. VCC
  3. INT/SQW - 低电平有效中断或方波输出(1Hz, 4kHz, 8kHz or 32kHz)
  4. RST - 低电平有效复位引脚
  5. GND
  6. VBAT - 备用电源
  7. SDA - I2C 数据
  8. 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

示例代码

代码下载地址

代码会将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存储

参考

最新文章

  1. [翻译] 聚集索引表 VS 堆表
  2. 9月8日HTML表单元素(form、文本、按钮、选择)
  3. 在hexo静态博客中利用d3-cloud来展现标签云
  4. java web 学习 --第九天(Java三级考试)
  5. opencart 引入 TWIG 模板引擎
  6. 媲美oracle awr/statspack的mysql awr第一版发布
  7. Python基本数据结构-字典-创建/访问/基本操作/格式化输出
  8. Hope
  9. hover带有动画效果的导航
  10. Spring事务源码阅读笔记
  11. GitLab搭建详细过程
  12. Apache和Tomcat的区别与联系
  13. html css笔记zht
  14. Round #3
  15. php:数组与json数据相互转换
  16. BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并
  17. mysql 数据表操作 目录
  18. tensorflow学习6
  19. Pandas的index属性
  20. Jordan标准形

热门文章

  1. 08. 树莓派安装MySQL
  2. 小米电视去广告之adb实战
  3. Day 007:PAT训练--1108 Finding Average (20 分)
  4. DDT数据驱动性能测试(一)
  5. Unity—TextMeshPro
  6. this-2
  7. 这 BUG,绝了
  8. 图解KMP字符串匹配算法+代码实现
  9. Mysql limit 优化优化
  10. 【FAQ】申请华为运动健康服务授权的4个常见问题及解决方法