From 1146bade7043fe9d2876df6ea3b86db74c80b5e7 Mon Sep 17 00:00:00 2001 From: edisondeng Date: Fri, 31 Jul 2026 19:30:02 +0800 Subject: [PATCH] feat(rtc): add PCF8563 full date read/write (day/month/year/weekday) PCF8563's second/minute/hour/day/weekday/month/year registers are contiguous (0x02-0x08), so PCF8563_ReadDateTime() bursts all 7 bytes in one transaction. PCF8563_ReadTime() becomes a thin wrapper that discards the date fields. WriteTime() is kept as its own 3-byte-only implementation (writing only sec/min/hour) rather than routed through the new WriteDateTime(), since forcing it through a 7-byte write would require synthesizing date values and risk corrupting the stored date; WriteDateTime() is added as a separate full 7-byte write for callers that actually have real date+weekday values to persist. --- Drivers/pcf8563.c | 81 +++++++++++++++++++++++++++++++++++++++++------ Drivers/pcf8563.h | 25 +++++++++++++++ 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/Drivers/pcf8563.c b/Drivers/pcf8563.c index b143354..07174ad 100644 --- a/Drivers/pcf8563.c +++ b/Drivers/pcf8563.c @@ -256,11 +256,11 @@ void PCF8563_ScanDiagnostic(void) } /** - * @brief 从 PCF8563 读取当前时间 + * @brief 从 PCF8563 连续读取时间与日期 (秒/分/时/日/星期/月/年,寄存器 0x02~0x08 地址连续) */ -bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec) +bit PCF8563_ReadDateTime(u8 *hour, u8 *min, u8 *sec, u8 *day, u8 *month, u8 *year) { - u8 raw_sec, raw_min, raw_hour; + u8 raw_sec, raw_min, raw_hour, raw_day, raw_weekday, raw_month, raw_year; I2C_Start(); I2C_SendByte(PCF8563_ADDR_WRITE); @@ -276,26 +276,51 @@ bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec) if (!I2C_WaitAck()) return 0; raw_sec = I2C_ReadByte(); - I2C_SendAck(1); // 发送 ACK + I2C_SendAck(1); raw_min = I2C_ReadByte(); - I2C_SendAck(1); // 发送 ACK + I2C_SendAck(1); raw_hour = I2C_ReadByte(); + I2C_SendAck(1); + + raw_day = I2C_ReadByte(); + I2C_SendAck(1); + + raw_weekday = I2C_ReadByte(); // 星期寄存器不使用,芯片自身的星期在改日期后可能与实际不符 + I2C_SendAck(1); + (void)raw_weekday; + + raw_month = I2C_ReadByte(); + I2C_SendAck(1); + + raw_year = I2C_ReadByte(); I2C_SendAck(0); // 发送 NACK 结束连续读取 I2C_Stop(); // 解析 BCD 数据 (掩码屏蔽无效位) - *sec = BCD2DEC(raw_sec & 0x7F); - *min = BCD2DEC(raw_min & 0x7F); - *hour = BCD2DEC(raw_hour & 0x3F); + *sec = BCD2DEC(raw_sec & 0x7F); + *min = BCD2DEC(raw_min & 0x7F); + *hour = BCD2DEC(raw_hour & 0x3F); + *day = BCD2DEC(raw_day & 0x3F); + *month = BCD2DEC(raw_month & 0x1F); // 忽略 bit7 世纪位,固定按 2000~2099 处理 + *year = BCD2DEC(raw_year); return 1; } /** - * @brief 将时间精准写入 PCF8563 RTC 芯片 + * @brief 从 PCF8563 读取当前时间 (兼容旧接口,只取时分秒,丢弃日期部分) + */ +bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec) +{ + u8 day, month, year; + return PCF8563_ReadDateTime(hour, min, sec, &day, &month, &year); +} + +/** + * @brief 将时间精准写入 PCF8563 RTC 芯片 (只写时分秒三个寄存器,不触碰日期寄存器) */ bit PCF8563_WriteTime(u8 hour, u8 min, u8 sec) { @@ -324,6 +349,44 @@ bit PCF8563_WriteTime(u8 hour, u8 min, u8 sec) return 1; } +/** + * @brief 将时间与日期一次性连续写入 PCF8563 RTC 芯片 (寄存器 0x02~0x08 共 7 字节连续写入) + */ +bit PCF8563_WriteDateTime(u8 hour, u8 min, u8 sec, u8 day, u8 month, u8 year, u8 weekday) +{ + I2C_Start(); + I2C_SendByte(PCF8563_ADDR_WRITE); + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(REG_VL_SECONDS); + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(DEC2BCD(sec & 0x7F)); + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(DEC2BCD(min & 0x7F)); + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(DEC2BCD(hour & 0x3F)); + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(DEC2BCD(day & 0x3F)); + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(weekday & 0x07); // 星期不是 BCD,直接写 0~6 + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(DEC2BCD(month & 0x1F)); // bit7 世纪位固定写 0,不处理跨世纪 + if (!I2C_WaitAck()) return 0; + + I2C_SendByte(DEC2BCD(year)); + if (!I2C_WaitAck()) return 0; + + I2C_Stop(); + + return 1; +} + bit PCF8563_TryReadDiagnostic(void) { u8 val = 0; diff --git a/Drivers/pcf8563.h b/Drivers/pcf8563.h index 367281f..39f5216 100644 --- a/Drivers/pcf8563.h +++ b/Drivers/pcf8563.h @@ -42,6 +42,31 @@ bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec); */ bit PCF8563_WriteTime(u8 hour, u8 min, u8 sec); +/** + * @brief 从 PCF8563 芯片连续读取时间与日期 (时/分/秒/日/月/年) + * @param hour 小时指针 (0~23) + * @param min 分钟指针 (0~59) + * @param sec 秒钟指针 (0~59) + * @param day 日指针 (1~31) + * @param month 月指针 (1~12) + * @param year 年指针 (0~99,代表 2000~2099,不处理世纪位) + * @return bit 1: 读取成功, 0: 通讯失败 + */ +bit PCF8563_ReadDateTime(u8 *hour, u8 *min, u8 *sec, u8 *day, u8 *month, u8 *year); + +/** + * @brief 将指定的时间与日期一次性连续写入 PCF8563 芯片 + * @param hour 小时 (0~23) + * @param min 分钟 (0~59) + * @param sec 秒钟 (0~59) + * @param day 日 (1~31) + * @param month 月 (1~12) + * @param year 年 (0~99,代表 2000~2099) + * @param weekday 星期 (0~6,需与软件侧约定的星期数值一致,芯片本身不做校验) + * @return bit 1: 写入成功, 0: 通讯失败 + */ +bit PCF8563_WriteDateTime(u8 hour, u8 min, u8 sec, u8 day, u8 month, u8 year, u8 weekday); + /** * @brief I2C 总线器件扫描诊断函数 * @details 逐个发送 I2C 写地址,检测总线上是否有响应的器件,并在串口打印发现的设备地址