Files
stc32g128k/Drivers/pcf8563.c

435 lines
10 KiB
C
Raw Permalink Normal View History

#include "pcf8563.h"
#include "../App/system.h"
// 动态引脚对调全局标志 (0: 默认 SCL=P3.2, SDA=P3.3; 1: 对调 SCL=P3.3, SDA=P3.2)
volatile u8 i2c_swapped = 0;
static void SCL_W(u8 val)
{
if (!i2c_swapped) P32 = val;
else P33 = val;
}
static void SDA_W(u8 val)
{
if (!i2c_swapped) P33 = val;
else P32 = val;
}
static u8 SDA_R(void)
{
if (!i2c_swapped) return P33;
else return P32;
}
// 动态延时参数 (单位: us)
volatile u8 i2c_delay_us = 30;
/**
* @brief I2C (START)
*/
static void I2C_Start(void)
{
SDA_W(1);
SCL_W(1);
Delay_us(i2c_delay_us);
SDA_W(0);
Delay_us(i2c_delay_us);
SCL_W(0);
Delay_us(i2c_delay_us);
}
/**
* @brief I2C (STOP)
*/
static void I2C_Stop(void)
{
SDA_W(0);
Delay_us(i2c_delay_us);
SCL_W(1);
Delay_us(i2c_delay_us);
SDA_W(1);
Delay_us(i2c_delay_us);
}
/**
* @brief I2C /
* @param ack 1: ACK(0), 0: NACK(1)
*/
static void I2C_SendAck(bit ack)
{
SDA_W(!ack);
Delay_us(i2c_delay_us);
SCL_W(1);
Delay_us(i2c_delay_us);
SCL_W(0);
Delay_us(i2c_delay_us);
SDA_W(1);
Delay_us(i2c_delay_us);
}
/**
* @brief I2C (Wait ACK)
* @return bit 1: , 0:
*/
static bit I2C_WaitAck(void)
{
u8 retry = 0;
SDA_W(1); // 释放 SDA 接收 ACK
Delay_us(i2c_delay_us);
SCL_W(1);
Delay_us(i2c_delay_us);
while (SDA_R()) {
retry++;
Delay_us(5);
if (retry > 250) {
I2C_Stop();
return 0; // 超时未收到 ACK 应答,立即优雅退出,防止死锁
}
}
SCL_W(0);
Delay_us(i2c_delay_us);
return 1;
}
/**
* @brief I2C
* @param dat of
*/
static void I2C_SendByte(u8 dat)
{
u8 i;
for (i = 0; i < 8; i++) {
SDA_W((dat & 0x80) ? 1 : 0);
Delay_us(i2c_delay_us);
SCL_W(1);
Delay_us(i2c_delay_us);
SCL_W(0);
Delay_us(i2c_delay_us);
dat <<= 1;
}
SDA_W(1); // 释放 SDA 接收 ACK
Delay_us(i2c_delay_us);
}
/**
* @brief I2C
* @return u8
*/
static u8 I2C_ReadByte(void)
{
u8 i, dat = 0;
SDA_W(1); // 设为输入
Delay_us(i2c_delay_us);
for (i = 0; i < 8; i++) {
dat <<= 1;
SCL_W(1);
Delay_us(i2c_delay_us);
if (SDA_R()) {
dat |= 0x01;
}
SCL_W(0);
Delay_us(i2c_delay_us);
}
return dat;
}
/* ====== BCD 与二进制 10 进制互转辅助函数 ====== */
static u8 BCD2DEC(u8 bcd)
{
return ((bcd >> 4) * 10) + (bcd & 0x0F);
}
static u8 DEC2BCD(u8 dec)
{
return (((dec / 10) << 4) | (dec % 10));
}
static void I2C_ReleaseBus(void)
{
u8 i;
SDA_W(1);
SCL_W(1);
Delay_us(30);
// 如果 SDA 被拉低,说明总线被死锁占用
if (SDA_R() == 0) {
for (i = 0; i < 9; i++) {
SCL_W(0);
Delay_us(30);
SCL_W(1);
Delay_us(30);
if (SDA_R() == 1) {
break; // 从机已释放总线,提前退出
}
}
}
// 强制产生停止条件恢复空闲
SDA_W(0);
Delay_us(30);
SCL_W(1);
Delay_us(30);
SDA_W(1);
Delay_us(30);
}
/* ====== PCF8563 驱动核心接口 ====== */
bit PCF8563_Init(void)
{
// 1. 默认引脚尝试 (SCL=P3.2, SDA=P3.3)
i2c_swapped = 0;
I2C_ReleaseBus(); // 强力总线死锁释放
I2C_Start();
I2C_SendByte(PCF8563_ADDR_WRITE);
if (I2C_WaitAck()) {
Uart_SendString("[RTC] Detected Normal pin mapping (SCL=P32, SDA=P33)\r\n");
} else {
// 2. 尝试对调引脚 (SCL=P3.3, SDA=P3.2)
I2C_Stop();
i2c_swapped = 1;
I2C_ReleaseBus(); // 强力总线死锁释放
I2C_Start();
I2C_SendByte(PCF8563_ADDR_WRITE);
if (I2C_WaitAck()) {
Uart_SendString("[RTC] Detected SWAPPED pin mapping (SCL=P33, SDA=P32)!\r\n");
} else {
// 恢复默认,防止干扰
i2c_swapped = 0;
Uart_SendString("[RTC-ERR] PCF8563 Offline on both normal/swapped pins!\r\n");
return 0;
}
}
I2C_SendByte(REG_CTRL_STATUS1);
if (!I2C_WaitAck()) return 0;
I2C_SendByte(0x00); // 正常模式,不停止芯片计数
if (!I2C_WaitAck()) return 0;
I2C_Stop();
return 1;
}
void PCF8563_ScanDiagnostic(void)
{
u16 addr;
u8 found = 0;
Uart_SendString("[I2C-SCAN] --- 1. Scanning with default pins (SCL=P32, SDA=P33) ---\r\n");
i2c_swapped = 0;
for (addr = 0x02; addr < 0x100; addr += 2) {
I2C_Start();
I2C_SendByte((u8)addr);
if (I2C_WaitAck()) {
Uart_SendString("[I2C-SCAN] Device Found: 0x");
Uart_SendHex8((u8)addr);
Uart_SendString("\r\n");
found = 1;
}
I2C_Stop();
Delay_ms(2);
}
Uart_SendString("[I2C-SCAN] --- 2. Scanning with SWAPPED pins (SCL=P33, SDA=P32) ---\r\n");
i2c_swapped = 1;
for (addr = 0x02; addr < 0x100; addr += 2) {
I2C_Start();
I2C_SendByte((u8)addr);
if (I2C_WaitAck()) {
Uart_SendString("[I2C-SCAN] Device Found: 0x");
Uart_SendHex8((u8)addr);
Uart_SendString("\r\n");
found = 1;
}
I2C_Stop();
Delay_ms(2);
}
// 扫描结束后,根据 init 侦测结果重新绑定,此处临时归零
i2c_swapped = 0;
Uart_SendString("[I2C-SCAN] Dual-mode Address Scan Completed!\r\n");
}
/**
* @brief PCF8563
*/
bit PCF8563_ReadTime(u8 *hour, u8 *min, u8 *sec)
{
u8 raw_sec, raw_min, raw_hour;
I2C_Start();
I2C_SendByte(PCF8563_ADDR_WRITE);
if (!I2C_WaitAck()) return 0;
// 设置起始读取地址为 0x02 (REG_VL_SECONDS)
I2C_SendByte(REG_VL_SECONDS);
if (!I2C_WaitAck()) return 0;
// 重新产生 Start 读取数据
I2C_Start();
I2C_SendByte(PCF8563_ADDR_READ);
if (!I2C_WaitAck()) return 0;
raw_sec = I2C_ReadByte();
I2C_SendAck(1); // 发送 ACK
raw_min = I2C_ReadByte();
I2C_SendAck(1); // 发送 ACK
raw_hour = I2C_ReadByte();
I2C_SendAck(0); // 发送 NACK 结束连续读取
I2C_Stop();
// 解析 BCD 数据 (掩码屏蔽无效位)
*sec = BCD2DEC(raw_sec & 0x7F);
*min = BCD2DEC(raw_min & 0x7F);
*hour = BCD2DEC(raw_hour & 0x3F);
return 1;
}
/**
* @brief PCF8563 RTC
*/
bit PCF8563_WriteTime(u8 hour, u8 min, u8 sec)
{
I2C_Start();
I2C_SendByte(PCF8563_ADDR_WRITE);
if (!I2C_WaitAck()) return 0;
// 定位写入起始寄存器 0x02
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_Stop();
return 1;
}
bit PCF8563_TryReadDiagnostic(void)
{
u8 val = 0;
Uart_SendString("[I2C-DIAG] --- Test 1: Trying 30us Delay (30kHz) ---\r\n");
i2c_delay_us = 30;
i2c_swapped = 0;
I2C_ReleaseBus();
I2C_Start();
I2C_SendByte(0xA2);
if (I2C_WaitAck()) {
Uart_SendString("[I2C-DIAG] (swapped=0, 30us) 0xA2 ACK OK\r\n");
I2C_SendByte(0x00);
if (I2C_WaitAck()) {
I2C_Start();
I2C_SendByte(0xA3);
if (I2C_WaitAck()) {
val = I2C_ReadByte();
I2C_SendAck(0);
I2C_Stop();
Uart_SendString("[I2C-DIAG] (swapped=0, 30us) Success! Reg 0x00=0x");
Uart_SendHex8(val);
Uart_SendString("\r\n");
return 1;
}
}
}
I2C_Stop();
i2c_swapped = 1;
I2C_ReleaseBus();
I2C_Start();
I2C_SendByte(0xA2);
if (I2C_WaitAck()) {
Uart_SendString("[I2C-DIAG] (swapped=1, 30us) 0xA2 ACK OK\r\n");
I2C_SendByte(0x00);
if (I2C_WaitAck()) {
I2C_Start();
I2C_SendByte(0xA3);
if (I2C_WaitAck()) {
val = I2C_ReadByte();
I2C_SendAck(0);
I2C_Stop();
Uart_SendString("[I2C-DIAG] (swapped=1, 30us) Success! Reg 0x00=0x");
Uart_SendHex8(val);
Uart_SendString("\r\n");
return 1;
}
}
}
I2C_Stop();
Uart_SendString("[I2C-DIAG] --- Test 2: Retrying with ultra-slow 200us Delay (2.5kHz) ---\r\n");
i2c_delay_us = 200;
i2c_swapped = 0;
I2C_ReleaseBus();
I2C_Start();
I2C_SendByte(0xA2);
if (I2C_WaitAck()) {
Uart_SendString("[I2C-DIAG] (swapped=0, 200us) 0xA2 ACK OK\r\n");
I2C_SendByte(0x00);
if (I2C_WaitAck()) {
I2C_Start();
I2C_SendByte(0xA3);
if (I2C_WaitAck()) {
val = I2C_ReadByte();
I2C_SendAck(0);
I2C_Stop();
Uart_SendString("[I2C-DIAG] (swapped=0, 200us) Success! Reg 0x00=0x");
Uart_SendHex8(val);
Uart_SendString("\r\n");
return 1;
}
}
}
I2C_Stop();
i2c_swapped = 1;
I2C_ReleaseBus();
I2C_Start();
I2C_SendByte(0xA2);
if (I2C_WaitAck()) {
Uart_SendString("[I2C-DIAG] (swapped=1, 200us) 0xA2 ACK OK\r\n");
I2C_SendByte(0x00);
if (I2C_WaitAck()) {
I2C_Start();
I2C_SendByte(0xA3);
if (I2C_WaitAck()) {
val = I2C_ReadByte();
I2C_SendAck(0);
I2C_Stop();
Uart_SendString("[I2C-DIAG] (swapped=1, 200us) Success! Reg 0x00=0x");
Uart_SendHex8(val);
Uart_SendString("\r\n");
return 1;
}
}
}
I2C_Stop();
// 恢复默认设置
i2c_swapped = 0;
i2c_delay_us = 30;
Uart_SendString("[I2C-DIAG] Both 30us and 200us diagnostic trial failed.\r\n");
return 0;
}