2026-05-10 21:35:40 +08:00

637 lines
18 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "PCF8563.h"
/* 用户自定义头文件*/
#include "public_diy.h"
#include "bsp_timer.h"
// #include "system_stm32f10x.h"
// #define SYSTEM_CORE_CLOCK_VAL (SystemCoreClock)
#define PCF8563_SLAVE_ADDR (0x51)
#define PCF8563_READ (1u)
#define PCF8563_WRITE (0u)
#define PCF8563_DELAY_US(val) (bsp_DelayUS(val))
#define PCF8563_DELAY_MS(val) (bsp_DelayMS(val))
typedef struct
{
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t day;
uint8_t week;
uint8_t month;
uint8_t year;
/* data */
}pcf8563_rtc_infor_Str;
static uint8_t pcf8563_init(void);
static uint8_t pcf8563_reboot(void);
static uint8_t pcf8563_set_rtc(rtc_time_infor rtc_infor);
static uint8_t pcf8563_read_rtc(rtc_time_infor * rtc_infor);
rtc_drv_str pcf8563_drv =
{
.rtc_type = RTCTYPE_PCF8563,
.init = pcf8563_init,
.reboot = pcf8563_reboot,
.get_rtc_time = pcf8563_read_rtc,
.set_rtc_time = pcf8563_set_rtc,
};
/* ========================================= 用户自定义驱动函数 ========================================== */
/*************************************************************************************
* @brief pcf8563使用的延时函数 us
* @param[in/out] val_us【参数注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
// void PCF8563_DELAY_US(uint16_t val_us)
// {
// bsp_DelayUS(val_us);
// }
/*************************************************************************************
* @brief pcf8563使用的延时函数 ms
* @param[in/out] val_ms【参数注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
// static void PCF8563_DELAY_MS(uint16_t val_ms)
// {
// bsp_DelayMS(val_ms);
// }
/*************************************************************************************
* @brief pcf8563 开始信号
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static void pcf8563_start_signal(void)
{
if(rtc_is_SDA_as_openDrain_output() == 0)
{
rtc_SDA_as_output();
}
RTC_W_SCL(1);
RTC_W_SDA(1);
// 不知道要延迟多久 先延迟这么多
// PCF8563_DELAY_MS(1);
PCF8563_DELAY_US(1);
RTC_W_SDA(0);
// 延迟 大于等于 0.6us
PCF8563_DELAY_US(1);
RTC_W_SCL(0);
}
/*************************************************************************************
* @brief pcf8563 结束信号
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static void pcf8563_stop_signal(void)
{
if(rtc_is_SDA_as_openDrain_output() == 0)
{
rtc_SDA_as_output();
}
RTC_W_SDA(0);
RTC_W_SCL(1);
// 延迟 大于等于 4us
PCF8563_DELAY_US(5);
RTC_W_SDA(1);
}
// /*************************************************************************************
// * @brief 读取pcf8563的Ack
// * @return uint8_t 【返回值注释】
// *
// * @warning 【不可重入,阻塞等警告】
// * @note 【重大修改】
// *************************************************************************************/
// uint8_t pcf8563_readAck(void)
// {
// uint8_t retVal;
// // uint8_t tmp_timeout = 3;
// rtc_SDA_as_input();
// RTC_W_SCL(1);
// PCF8563_DELAY_US(2);
// // 判断ack
// if(GET_RTC_SDA_STATE() == 0)
// {
// retVal = RET_OK;
// }
// else
// {
// retVal = RET_ERROR;
// }
// // 本周期剩下的低电平
// RTC_W_SCL(0);
// PCF8563_DELAY_US(2);
// // sda设为输出
// rtc_SDA_as_output();
// return retVal;
// }
// /*************************************************************************************
// * @brief 主动发送 NACK
// *
// * @warning 【不可重入,阻塞等警告】
// * @note 【重大修改】
// *************************************************************************************/
// void pcf8563_sendNAck(void)
// {
// rtc_SDA_as_output();
// // NACK
// RTC_W_SDA(1);
// // 本周期 高电平
// RTC_W_SCL(1);
// PCF8563_DELAY_US(2);
// // 本周期剩下的低电平
// RTC_W_SCL(0);
// PCF8563_DELAY_US(2);
// }
/*************************************************************************************
* @brief I2C发送一个字节
* @param[in/out] Byte 【参数注释】
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
void pcf8563_sendByte(uint8_t Byte)
{
uint8_t i;
if(rtc_is_SDA_as_openDrain_output() == 0)
{
rtc_SDA_as_output();
}
// RTC_W_SDA(0);
for (i = 0; i < 8; i++)
{
RTC_W_SDA(!!(Byte & (0x80 >> i)));
RTC_W_SCL(1);
PCF8563_DELAY_US(2);
RTC_W_SCL(0);
PCF8563_DELAY_US(2);
}
}
/*************************************************************************************
* @brief 主机接收pcf8563一字节数据
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
uint8_t pcf8563_recvByte(void)
{
uint8_t recv_val = 0;
uint8_t tmp_i = 0;
/* #### 主机释放SDA 如何释放? */
RTC_W_SDA(1);
/* 转为输入 */
if(rtc_is_SDA_as_floating_input() == 0)
{
rtc_SDA_as_input();
}
/* 主机接收数据 */
for(tmp_i = 0; tmp_i < 8; ++tmp_i)
{
RTC_W_SCL(1);
PCF8563_DELAY_US(2);
recv_val <<= 1;
recv_val |= GET_RTC_SDA_STATE();
RTC_W_SCL(0);
PCF8563_DELAY_US(2);
}
return recv_val;
}
/*************************************************************************************
* @brief 主机主动发ack
* @param[in/out] val 【参数注释】
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static uint8_t pcf8563_send_ACK(uint8_t val)
{
/* SDA设为输出 */
if(rtc_is_SDA_as_openDrain_output() == 0)
{
rtc_SDA_as_output();
}
/* SDA主动发送val相应的电平 */
RTC_W_SDA(val);
/* SCL置为1 使val电平状态保持 延迟2us*/
RTC_W_SCL(1);
PCF8563_DELAY_US(2);
/* SCL置为1 本周期剩下的低电平 延迟2us*/
RTC_W_SCL(0);
PCF8563_DELAY_US(2);
/* 结束逻辑 返回成功 */
return RET_OK;
}
/*************************************************************************************
* @brief 等待从机ACK 并返回ACK结果
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static uint8_t pcf8563_wait_ACK(void)
{
uint8_t retVal = RET_ERROR;
uint8_t wait_timer = 2;
/* #### 主机释放SDA 如何释放? */
RTC_W_SDA(1);
/* 转为输入 */
if(rtc_is_SDA_as_floating_input() == 0)
{
rtc_SDA_as_input();
}
/* 延迟1us */
PCF8563_DELAY_US(1);
/* SCL 拉高 */
RTC_W_SCL(1);
/* 超时最多2us 等待SDA为低 */
while(wait_timer > 0 && GET_RTC_SDA_STATE() > 0)
{
wait_timer--;
PCF8563_DELAY_US(1);
}
/* 根据SDA状态 判断是否成功接收 */
if(GET_RTC_SDA_STATE() == 0)
{
retVal = RET_OK;
}
else
{
retVal = RET_ERROR;
}
/* SCL 拉低 */
RTC_W_SCL(0);
/* 延迟2us */
PCF8563_DELAY_US(2);
return retVal;
}
/*************************************************************************************
* @brief 往 pcf8563内 写一个字节
* @param[in/out] addr 字地址
* @param[in/out] byte 写入的值
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
uint8_t pcf8563_write_one_byte(uint8_t addr, uint8_t byte)
{
uint8_t tmp_retVal = RET_ERROR;
uint8_t tmp_addr_rw = 0;
/* 1. 开始信号 */
pcf8563_start_signal();
/* 2. 第一个数据 从设备地址+读写状态 */
// 发送从设备地址 写
tmp_addr_rw = (PCF8563_SLAVE_ADDR << 1) + PCF8563_WRITE;
pcf8563_sendByte(tmp_addr_rw);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 3. 发字地址 */
pcf8563_sendByte(addr);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 4. 发数据 */
pcf8563_sendByte(byte);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 5. 停止信号 */
pcf8563_stop_signal();
return RET_OK;
}
/*************************************************************************************
* @brief 往 pcf8563内 写多个字节
* @param[in/out] addr 字地址
* @param[in/out] buf 需要写入内容的数组地址
* @param[in/out] len 长度
* @return uint8_t RET_INVALID无效 RET_OK: 成功 RET_ERROR错误
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
uint8_t pcf8563_write_bytes(uint8_t addr, uint8_t *buf, uint16_t len)
{
uint8_t tmp_retVal = RET_ERROR;
uint8_t tmp_i;
uint8_t tmp_addr_rw = 0;
/* 合法性校验 */
if(len == 0 || buf == NULL)
{
return RET_INVALID;
}
/* 1. 开始信号 */
pcf8563_start_signal();
/* 2. 第一个数据 从设备地址+读写状态 */
// 发送从设备地址 写
tmp_addr_rw = (PCF8563_SLAVE_ADDR << 1) + PCF8563_WRITE;
pcf8563_sendByte(tmp_addr_rw);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 3. 发字地址 */
pcf8563_sendByte(addr);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 4. 发连续地址的数据 */
for(tmp_i = 0; tmp_i < len; ++tmp_i)
{
pcf8563_sendByte(buf[tmp_i]);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
}
/* 5. 停止信号 */
pcf8563_stop_signal();
return RET_OK;
}
/*************************************************************************************
* @brief 往 pcf8563内 读一个字节
* @param[in/out] addr 字地址
* @param[in/out] byte 想读取的值
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
uint8_t pcf8563_read_one_byte(uint8_t addr, uint8_t *byte)
{
uint8_t tmp_retVal = RET_ERROR;
uint8_t tmp_addr_rw = 0;
// uint8_t tmp_value = 0;
/* 1. 开始信号 */
pcf8563_start_signal();
/* 2. 第一个数据 从设备地址+读写状态 */
// 发送从设备地址 写
tmp_addr_rw = (PCF8563_SLAVE_ADDR << 1) + PCF8563_WRITE;
pcf8563_sendByte(tmp_addr_rw);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 3. 发字地址 */
pcf8563_sendByte(addr);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 4. 发重新开始信号 */
pcf8563_start_signal();
/* 5. 再次发第一个数据 从设备地址 + 读状态 */
// 发送从设备地址 写
tmp_addr_rw = (PCF8563_SLAVE_ADDR << 1) + PCF8563_READ;
pcf8563_sendByte(tmp_addr_rw);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 6. 接收一字节数据 */
*byte = pcf8563_recvByte();
/* send ACK */
pcf8563_send_ACK(1);
/* 7. 停止信号 */
pcf8563_stop_signal();
return RET_OK;
}
/*************************************************************************************
* @brief 往 pcf8563内 读多个字节
* @param[in/out] addr 【参数注释】
* @param[in/out] buf 【参数注释】
* @param[in/out] len 【参数注释】
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
uint8_t pcf8563_read_bytes(uint8_t addr, uint8_t *buf, uint16_t len)
{
uint8_t tmp_retVal = RET_ERROR;
uint8_t tmp_addr_rw = 0;
// uint8_t tmp_value = 0;
uint8_t tmp_i;
/* 有效性检测 */
if(len == 0 || buf == NULL)
{
return RET_INVALID;
}
/* 1. 开始信号 */
pcf8563_start_signal();
/* 2. 第一个数据 从设备地址+读写状态 */
// 发送从设备地址 写
tmp_addr_rw = (PCF8563_SLAVE_ADDR << 1) + PCF8563_WRITE;
pcf8563_sendByte(tmp_addr_rw);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 3. 发字地址 */
pcf8563_sendByte(addr);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 4. 发重新开始信号 */
pcf8563_start_signal();
/* 5. 再次发第一个数据 从设备地址 + 读状态 */
// 发送从设备地址 写
tmp_addr_rw = (PCF8563_SLAVE_ADDR << 1) + PCF8563_READ;
pcf8563_sendByte(tmp_addr_rw);
/* wait ack*/
tmp_retVal = pcf8563_wait_ACK();
if(tmp_retVal == RET_ERROR)
{
pcf8563_stop_signal();
return RET_ERROR;
}
/* 6. 接收多个字节数据 */
for(tmp_i = 0; tmp_i < len; ++tmp_i)
{
buf[tmp_i] = pcf8563_recvByte();
if(tmp_i == (len - 1))
{
pcf8563_send_ACK(1);
}
else
{
pcf8563_send_ACK(0);
}
}
/* send ACK */
/* 7. 停止信号 */
pcf8563_stop_signal();
return RET_OK;
}
/*************************************************************************************
* @brief pcf8563 初始化
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static uint8_t pcf8563_init(void)
{
return RET_OK;
}
/*************************************************************************************
* @brief PCF8563 重启
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static uint8_t pcf8563_reboot(void)
{
/* 暂时还没研究 先设为无效 */
return RET_INVALID;
}
/*************************************************************************************
* @brief pcf8563 读取rtc值
* @param[in/out] rtc_infor【参数注释】
* @return uint8_t 【返回值注释】
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static uint8_t pcf8563_read_rtc(rtc_time_infor * rtc_infor)
{
uint8_t retVal = RET_ERROR;
pcf8563_rtc_infor_Str str_pcf8563_rtc_info;
/* 合法性检验 */
if(rtc_infor == NULL)
{
return RET_INVALID;
}
/* 读取rtc数据 */
retVal = pcf8563_read_bytes(0x02, (u8*)&str_pcf8563_rtc_info, sizeof(str_pcf8563_rtc_info));
/* 取需要用到的部分 */
str_pcf8563_rtc_info.second &= 0x7F;
str_pcf8563_rtc_info.minute &= 0x7F;
str_pcf8563_rtc_info.hour &= 0x3F;
str_pcf8563_rtc_info.day &= 0x3F;
str_pcf8563_rtc_info.week &= 0x07;
str_pcf8563_rtc_info.month &= 0x1F;
/* 装填数据 */
rtc_infor->year = str_pcf8563_rtc_info.year;
rtc_infor->month = str_pcf8563_rtc_info.month;
rtc_infor->day = str_pcf8563_rtc_info.day;
rtc_infor->week = str_pcf8563_rtc_info.week;
rtc_infor->hour = str_pcf8563_rtc_info.hour;
rtc_infor->minute = str_pcf8563_rtc_info.minute;
rtc_infor->second = str_pcf8563_rtc_info.second;
/* 返回 */
return retVal;
}
/*************************************************************************************
* @brief pcf8563 设置rtc的值
*
* @warning 【不可重入,阻塞等警告】
* @note 【重大修改】
*************************************************************************************/
static uint8_t pcf8563_set_rtc(rtc_time_infor rtc_infor)
{
uint8_t retVal = RET_ERROR;
pcf8563_rtc_infor_Str str_pcf8563_rtc_info;
/* 装填数据 准备下设 */
str_pcf8563_rtc_info.year = rtc_infor.year;
str_pcf8563_rtc_info.month = rtc_infor.month;
str_pcf8563_rtc_info.day = rtc_infor.day;
str_pcf8563_rtc_info.week = rtc_infor.week;
str_pcf8563_rtc_info.hour = rtc_infor.hour;
str_pcf8563_rtc_info.minute = rtc_infor.minute;
str_pcf8563_rtc_info.second = rtc_infor.second;
/* 设置rtc数据 */
retVal = pcf8563_write_bytes(0x02, (u8*)&str_pcf8563_rtc_info, sizeof(str_pcf8563_rtc_info));
return retVal;
}