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.
This commit is contained in:
edisondeng
2026-07-31 19:30:02 +08:00
parent 4a55c1f9eb
commit 1146bade70
2 changed files with 97 additions and 9 deletions

View File

@@ -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,12 +276,25 @@ 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();
@@ -290,12 +303,24 @@ bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec)
*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;

View File

@@ -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 写地址,检测总线上是否有响应的器件,并在串口打印发现的设备地址