STM32模拟IIC读取PCF8563
2019-08-10 来源:eefocus
一、首先是对于PCF8563芯片的介绍与使用说明:
PCF8563 是PHILIPS 公司推出的一款工业级内含I2C 总线接口功能的具有极低功耗的多功能时钟/日历芯片。PCF8563 的多种报警功能、定时器功能、时钟输出功能以及中断输出功能能完成各种复杂的定时服务,甚至可为单片机提供看门狗功能。是一款性价比极高的时钟芯片,它已被广泛用于电表、水表、气表、电话、传真机、便携式仪器以及电池供电的仪器仪表等产品领域。
多于的我并不想赘述了太多,我会将中英文手册和源码见后;由于PCF8563是IIC通讯的,又据说STM32芯片硬件IIC的问题(至于好不好用我还没试过,都是道听途说),所以采用模拟IIC完成本程序的通讯。
整个实现过程分成了两部分:
1.IIC底层驱动程序 IIC.c和 IIC.h ;
2.PCF8563.c 和 PCF8563.h;
下面开始我的代码表演(其实都是前辈们写烂了的代码,我又做了整理,思路符合自己更加清晰而已)!!!
二、IIC驱动程序
1.h头文件:
/******************************************************************************
* @ File name --> iic.h
* @ Brief --> MCU模拟IIC通讯函数
* @ --> 要改变传输频率,请修改延时函数中的数值即可
******************************************************************************/
#ifndef _iic_h_
#define _iic_h_
/******************************************************************************
外部函数头文件
******************************************************************************/
#include 'system.h'
#include 'Systick.h'
/******************************************************************************
外部引脚修改区
******************************************************************************/
/* IIC_SCL时钟端口、引脚定义 */
#define IIC_SCL_PORT GPIOB
#define IIC_SCL_PIN (GPIO_Pin_6)
#define IIC_SCL_PORT_RCC RCC_APB2Periph_GPIOB
/* IIC_SDA时钟端口、引脚定义 */
#define IIC_SDA_PORT GPIOB
#define IIC_SDA_PIN (GPIO_Pin_7)
#define IIC_SDA_PORT_RCC RCC_APB2Periph_GPIOB
/******************************************************************************
对于低速晶振的支持
是否使用延时函数进行调整通讯频率
******************************************************************************/
#define _USER_DELAY_CLK 1 //定义了则使用延时调整通讯频率
//0:不使用延时函数调整通讯频率,对于低速MCU时候用
//1:使用延时函数调整通讯频率,对于高速MCU时候用
/******************************************************************************
位带操作
******************************************************************************/
#define IIC_SCL PBout(6)
#define IIC_SDA PBout(7) //IIC发送数据用
#define IN_SDA PBin(7) //IIC读取数据用
/******************************************************************************
通讯频率延时函数
需要调整通讯频率的请修改此函数值即可
******************************************************************************/
#if _USER_DELAY_CLK==1 //定义了则使用
#define IIC_Delay() delay_us(2) //要改变请修改delay_us()中的数值即可
#endif
/******************************************************************************
外部功能函数
******************************************************************************/
void IIC_GPIO_Init(void); //GPIO初始化
void IIC_Start(void); //IIC启动
void IIC_Stop(void); //IIC停止
void IIC_Ack(u8 a); //主机向从机发送应答信号
u8 IIC_Write_Byte(u8 dat); //向IIC总线发送一个字节数据
u8 IIC_Read_Byte(void); //从IIC总线上读取一个字节数据
#endif /* end iic.h */
有一点需要注意的是,如果你想省事头里面包含的那两个头(一个是延时,一个是包含位带操作定义的103头文件),直接替换就好。
2.c文件
#include 'iic.h'
/******************************************************************************
* Function Name --> IIC_GPIO_Init
* Description --> GPIO初始化
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
IIC_SDA = 1; //置IIC总线空闲
IIC_SCL = 1;
}
/******************************************************************************
* Function Name --> SDA_OUT
* Description --> SDA输出配置
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
}
/******************************************************************************
* Function Name --> SDA_IN
* Description --> SDA输入配置
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
}
/******************************************************************************
* Function Name --> IIC启动
* Description --> SCL高电平期间,SDA由高电平突变到低电平时启动总线
* SCL: __________
* __________
* SDA: _____
* _______________
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_Start(void)
{
IIC_SDA_OUT(); //设置成输出
IIC_SDA = 1; //为SDA下降启动做准备
IIC_SCL = 1; //在SCL高电平时,SDA为下降沿时候总线启动
#if _USER_DELAY_CLK==1 /* 定义了则使用延时函数来改变通讯频率 */
IIC_Delay();
IIC_SDA = 0; //突变,总线启动
IIC_Delay();
IIC_SCL = 0;
IIC_Delay();
#else /* 否则不使用延时函数改变通讯频率 */
IIC_SDA = 0; //突变,总线启动
IIC_SCL = 0;
#endif /* end __USER_DELAY_CLK */
}
/******************************************************************************
* Function Name --> IIC停止
* Description --> SCL高电平期间,SDA由低电平突变到高电平时停止总线
* SCL: ____________________
* __________
* SDA: _________/
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_Stop(void)
{
IIC_SDA_OUT(); //设置成输出
IIC_SDA = 0; //为SDA上升做准备
#if _USER_DELAY_CLK==1 /* 定义了则使用延时函数来改变通讯频率 */
IIC_Delay();
IIC_SCL = 1; //在SCL高电平时,SDA为上升沿时候总线停止
IIC_Delay();
IIC_SDA = 1; //突变,总线停止
IIC_Delay();
#else /* 否则不使用延时函数改变通讯频率 */
IIC_SCL = 1; //在SCL高电平时,SDA为上升沿时候总线停止
IIC_SDA = 1; //突变,总线停止
#endif /* end __USER_DELAY_CLK */
}
/******************************************************************************
* Function Name --> 主机向从机发送应答信号
* Description --> none
* Input --> a:应答信号
* 0:应答信号
* 1:非应答信号
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_Ack(u8 a)
{
IIC_SDA_OUT(); //设置成输出
if(a) IIC_SDA = 1; //放上应答信号电平
else IIC_SDA = 0;
#if _USER_DELAY_CLK==1 /* 定义了则使用延时函数来改变通讯频率 */
IIC_Delay();
IIC_SCL = 1; //为SCL下降做准备
IIC_Delay();
IIC_SCL = 0; //突变,将应答信号发送过去
IIC_Delay();
#else /* 否则不使用延时函数改变通讯频率 */
IIC_SCL = 1; //为SCL下降做准备
IIC_SCL = 0; //突变,将应答信号发送过去
#endif /* end __USER_DELAY_CLK */
}
/******************************************************************************
* Function Name --> 向IIC总线发送一个字节数据
* Description --> none
* Input --> dat:要发送的数据
* Output --> none
* Reaturn --> ack:返回应答信号
******************************************************************************/
u8 IIC_Write_Byte(u8 dat)
{
u8 i;
u8 iic_ack=0; //iic应答标志
IIC_SDA_OUT(); //设置成输出
for(i = 0;i < 8;i++)
{
if(dat & 0x80) IIC_SDA = 1; //判断发送位,先发送高位
else IIC_SDA = 0;
#if _USER_DELAY_CLK==1 /* 定义了则使用延时函数来改变通讯频率 */
IIC_Delay();
IIC_SCL = 1; //为SCL下降做准备
IIC_Delay();
IIC_SCL = 0; //突变,将数据位发送过去
dat<<=1; //数据左移一位
} //字节发送完成,开始接收应答信号
IIC_SDA = 1; //释放数据线
IIC_SDA_IN(); //设置成输入
IIC_Delay();
IIC_SCL = 1; //为SCL下降做准备
IIC_Delay();
#else /* 否则不使用延时函数改变通讯频率 */
IIC_SCL = 1; //为SCL下降做准备
IIC_SCL = 0; //突变,将数据位发送过去
dat<<=1; //数据左移一位
} //字节发送完成,开始接收应答信号
IIC_SDA = 1; //释放数据线
IIC_SDA_IN(); //设置成输入
IIC_SCL = 1; //为SCL下降做准备
#endif /* end __USER_DELAY_CLK */
iic_ack |= IN_SDA; //读入应答位
IIC_SCL = 0;
return iic_ack; //返回应答信号
}
/******************************************************************************
* Function Name --> 从IIC总线上读取一个字节数据
* Description --> none
* Input --> none
* Output --> none
* Reaturn --> x:读取到的数据
******************************************************************************/
u8 IIC_Read_Byte(void)
{
u8 i;
u8 x=0;
IIC_SDA = 1; //首先置数据线为高电平
IIC_SDA_IN(); //设置成输入
for(i = 0;i < 8;i++)
{
x <<= 1; //读入数据,高位在前
#if _USER_DELAY_CLK==1 /* 定义了则使用延时函数来改变通讯频率 */
IIC_Delay();
IIC_SCL = 1; //突变
IIC_Delay();
if(IN_SDA) x |= 0x01; //收到高电平
IIC_SCL = 0;
IIC_Delay();
} //数据接收完成
#else /* 否则不使用延时函数改变通讯频率 */
IIC_SCL = 1; //突变
if(IN_SDA) x |= 0x01; //收到高电平
IIC_SCL = 0;
} //数据接收完成
#endif /* end __USER_DELAY_CLK */
IIC_SCL = 0;
return x; //返回读取到的数据
}
因为经常使用IIC所以,单独写成独立IIC驱动,写的是相当通俗易懂啦,不会的你直接复制粘贴就好,函数接口都放到头文件里面了,供其他函数调用。
三、好啦重点来了,下边就是8563啦,由于是第一次使用这个芯片所以多多少少还是遇到了点问题,好在问题都解决了。详细贴上自己调试通过代码,希望大家多多指正、斧正!
1.首先BIN转BCD功能:
static unsigned char RTC_BinToBcd2(unsigned char BINValue)
{
unsigned char bcdhigh = 0;
while (BINValue >= 10)
{
bcdhigh++;
BINValue -= 10;
}
return ((unsigned char)(bcdhigh << 4) | BINValue);
}
2.然后BCD转BIN功能:
static unsigned char RTC_Bcd2ToBin(unsigned char BCDValue)
{
unsigned char tmp = 0;
tmp = ((unsigned char)(BCDValue & (unsigned char)0xF0) >> (unsigned char)0x04) * 10;
return (tmp + (BCDValue & (unsigned char)0x0F));
}
3. 然后PCF8563某寄存器写入一个字节数据
void PCF8563_Write_Byte(unsigned char REG_ADD, unsigned char dat)
{
IIC_Start(); //启动IIC
if(!(IIC_Write_Byte(PCF8563_Write))) //发送写命令并检查应答位
{
IIC_Write_Byte(REG_ADD); //写入地址
IIC_Write_Byte(dat); //发送数据
}
IIC_Stop(); //关闭IIC
}
4.PCF8563某寄存器读取一个字节数据
unsigned char PCF8563_Read_Byte(unsigned char REG_ADD)
{
unsigned char ReData; //定义变量接收数据
IIC_Start(); //启动IIC
if(!(IIC_Write_Byte(PCF8563_Write))) //发送写命令并检查应答位
{
IIC_Write_Byte(REG_ADD); //确定要操作的寄存器
IIC_Start(); //重启总线
IIC_Write_Byte(PCF8563_Read); //发送读取命令
ReData = IIC_Read_Byte( ); //读取数据
IIC_Ack(1); //发送非应答信号结束数据传送
}
IIC_Stop(); //关闭IIC
return ReData;
}
5.PCF8563写入多组数据
void PCF8563_Write_nByte(unsigned char REG_ADD, unsigned char num, unsigned char *pBuff)
{
unsigned char i = 0; //定义i辅助循环发送
IIC_Start(); //启动IIC
if(!(IIC_Write_Byte(PCF8563_Write))) //发送写命令并检查应答位
{
IIC_Write_Byte(REG_ADD); //定位起始寄存器地址
for(i = 0;i < num;i++) //循环num次,达到多个数据写入
{
IIC_Write_Byte(*pBuff); //写入数据
pBuff++; //数据缓存地址增加
}
}
IIC_Stop(); //关闭IIC
}
6.PCF8563读取多组数据
void PCF8563_Read_nByte(unsigned char REG_ADD, unsigned char num, unsigned char *pBuff)
{
unsigned char i = 0; //定义变量i辅助多次读取
IIC_Start(); //启动IIC
if(!(IIC_Write_Byte(PCF8563_Write))) //发送写命令并检查应答位
{
IIC_Write_Byte(REG_ADD); //定位起始寄存器地址
IIC_Start(); //重启总线
IIC_Write_Byte(PCF8563_Read); //发送读取命令
for(i = 0;i < num;i++) //循环num次完成多次读取
{
*pBuff = IIC_Read_Byte(); //读取数据
if(i == (num - 1)) IIC_Ack(1);//发送非应答信号,知道完成数据量
else IIC_Ack(0); //发送应答信号
pBuff++; //读取缓冲区地址增加
}
}
IIC_Stop(); //关闭IIC
}
7.PCF8563检测是否存在
unsigned char PCF8563_Check(void)
{
unsigned char test_value = 0;
unsigned char Time_Count = 0; //定时器倒计时数据缓存
if(PCF8563_Read_Byte(PCF8563_Address_Timer) & 0x80) //如果打开了定时器,则先关闭
{
PCF8563_Write_Byte(PCF8563_Address_Timer, PCF_Timer_Close); //先关闭定时器
Time_Count = PCF8563_Read_Byte(PCF8563_Address_Timer_VAL); //先保存计数值
}
PCF8563_Write_Byte(PCF8563_Address_Timer_VAL, PCF8563_Check_Data); //写入检测值
for(test_value = 0;test_value < 50;test_value++) {} //延时一定时间再读取
test_value = PCF8563_Read_Byte(PCF8563_Address_Timer_VAL); //再读取回来
if(Time_Count != 0) //启动了定时器功能,则恢复
{
PCF8563_Write_Byte(PCF8563_Address_Timer_VAL, Time_Count); //恢复现场
PCF8563_Write_Byte(PCF8563_Address_Timer, PCF_Timer_Open); //启动定时器
}
if(test_value != PCF8563_Check_Data) return 1; //器件错误或者损坏
return 0; //正常
}
8.PCF8563启动
void PCF8563_Start(void)
{
unsigned char temp = 0;
temp = PCF8563_Read_Byte(PCF8563_Address_Control_Status_1); //读取控制/状态寄存器1
if (temp & PCF_Control_ChipStop)
{
temp &= PCF_Control_ChipRuns; //运行芯片
}
if ((temp & (1<<7)) == 0) //普通模式
{
temp &= PCF_Control_TestcClose; //电源复位模式失效
}
PCF8563_Write_Byte(PCF8563_Address_Control_Status_1, temp); //再写入数值
}
9.PCF8563停止
void PCF8563_Stop(void)
{
unsigned char temp = 0;
temp = PCF8563_Read_Byte(PCF8563_Address_Control_Status_1); //读取控制/状态寄存器1
temp |= PCF_Control_ChipStop; //停止运行
PCF8563_Write_Byte(PCF8563_Address_Control_Status_1, temp); //再写入数值
}
10.PCF8563设置运行模式
void PCF8563_SetMode(unsigned char Mode)
{
unsigned char temp = 0;
temp = PCF8563_Read_Byte(PCF8563_Address_Control_Status_1); //读取寄存器值
if (Mode == PCF_Mode_EXT_CLK) //EXT_CLK测试模式
{
temp |= PCF_Control_Status_EXT_CLKMode;
}
else if (Mode == PCF_Mode_Normal)
{
temp &= PCF_Control_Status_NormalMode;
temp &= ~(1<<3); //电源复位功能失效
}
PCF8563_Write_Byte(PCF8563_Address_Control_Status_1, temp);
}
11.PCF8563设置电源复位功能开启与关闭
void PCF8563_SetPowerReset(unsigned char NewState)
{
unsigned char TestC = 0;
TestC = PCF8563_Read_Byte(PCF8563_Address_Control_Status_1); //获取寄存器值
TestC &= ~(1<<3); //清除之前设置
if (NewState == PCF8563_PowerResetEnable) //复位功能有效
{
TestC |= PCF8563_PowerResetEnable;
}
else if (NewState == PCF8563_PowerResetDisable)
{
TestC &= ~PCF8563_PowerResetEnable; //失效,普通模式是值逻辑0,即失效
}
PCF8563_Write_Byte(PCF8563_Address_Control_Status_1, TestC); //写入数值
}
12.PCF8563设置输出频率
void PCF8563_SetCLKOUT(_PCF8563_CLKOUT_Typedef* PCF_CLKOUTStruct)
{
unsigned char tmp = 0;
tmp = PCF8563_Read_Byte(PCF8563_Address_CLKOUT); //读取寄存器值
tmp &= 0x7c; //清除之前设置
if (PCF_CLKOUTStruct->CLKOUT_NewState == PCF_CLKOUT_Open)
{
tmp |= PCF_CLKOUT_Open;
}
else
{
tmp &= PCF_CLKOUT_Close;
}
tmp |= PCF_CLKOUTStruct->CLKOUT_Frequency;
PCF8563_Write_Byte(PCF8563_Address_CLKOUT, tmp);
}
13.PCF8563设置定时器
void PCF8563_SetTimer(_PCF8563_Timer_Typedef* PCF_TimerStruct)
{
unsigned char Timer_Ctrl = 0;
unsigned char Timer_Value = 0;
Timer_Ctrl = PCF8563_Read_Byte(PCF8563_Address_Timer); //获的控制寄存器值
Timer_Value = PCF8563_Read_Byte(PCF8563_Address_Timer_VAL); //获取倒计时数值
//
//先停止定时器
//
Timer_Ctrl &= PCF_Timer_Close;
PCF8563_Write_Byte(PCF8563_Address_Timer, Timer_Ctrl);
Timer_Ctrl &= 0x7c; //清除定时器之前设置
if (PCF_TimerStruct->RTC_Timer_NewState == PCF_Timer_Open) //开启
{
Timer_Ctrl |= PCF_Timer_Open;
Timer_Ctrl |= PCF_TimerStruct->RTC_Timer_Frequency; //填上新的工作频率
if (PCF_TimerStruct->RTC_Timer_Value) //需要填上新的计数值
{
Timer_Value = PCF_TimerStruct->RTC_Timer_Value; //填上新的计数值
}
}
else
{
Timer_Ctrl &= PCF_Timer_Close;
}
PCF8563_Write_Byte(PCF8563_Address_Timer_VAL, Timer_Value); //写入倒计时数值
if (PCF_TimerStruct->RTC_Timer_Interrupt == PCF_Time_INT_Open) //开启了中断输出
{
Timer_Value = PCF8563_Read_Byte(PCF8563_Address_Control_Status_2); //获取控制/状态寄存器2数值
Timer_Value &= PCF_Time_INT_Close; //清除定时器中断使能
Timer_Value &= ~(1<<2); //清除定时器中断标志
Timer_Value &= ~(1<<4); //当 TF 有效时 INT 有效 (取决于 TIE 的状态)
Timer_Value |= PCF_Time_INT_Open; //开启定时器中断输出
PCF8563_Write_Byte(PCF8563_Address_Control_Status_2, Timer_Value);
}
else
{
Timer_Value = PCF8563_Read_Byte(PCF8563_Address_Control_Status_2); //获取控制/状态寄存器2数值
Timer_Value &= PCF_Time_INT_Close; //清除定时器中断使能
Timer_Value |= PCF_Time_INT_Open; //开启定时器中断输出
PCF8563_Write_Byte(PCF8563_Address_Control_Status_2, Timer_Value);
}
PCF8563_Write_Byte(PCF8563_Address_Timer, Timer_Ctrl); //设置定时器控制寄存器
}
14.设置时间,主要用于后台调用,或者初始化时间用
void PCF8563_Set_Times(unsigned char PCF_Format,
unsigned char PCF_Century,
unsigned char Year, unsigned char Month, unsigned char Date, unsigned char Week,
unsigned char Hour, unsigned char Minute)
{
_PCF8563_Time_Typedef Time_InitStructure;
_PCF8563_Date_Typedef Date_InitStructure;
if (PCF_Format == PCF_Format_BIN)
{
//
//判断数据是否符合范围
//
if (Year > 99) Year = 0; //恢复00年
if (Month > 12) Month = 1; //恢复1月
if (Date > 31) Date = 1; //恢复1日
if (Week > 6) Week = 1; //恢复星期一
if (Hour > 23) Hour = 0; //恢复0小时
if (Minute > 59) Minute = 0; //恢复0分钟
//
//转换一下
//
Date_InitStructure.RTC_Years = RTC_BinToBcd2(Year);
Date_InitStructure.RTC_Months = RTC_BinToBcd2(Month);
Date_InitStructure.RTC_Days = RTC_BinToBcd2(Date);
Date_InitStructure.RTC_WeekDays = RTC_BinToBcd2(Week);
Time_InitStructure.RTC_Hours = RTC_BinToBcd2(Hour);
Time_InitStructure.RTC_Minutes = RTC_BinToBcd2(Minute);
}
Time_InitStructure.RTC_Seconds = 0x00; //恢复0秒
Time_InitStructure.RTC_Seconds &= PCF_Accuracy_ClockYes; //保证准确的时间
//
//判断世纪位
//
if (PCF_Century == PCF_Century_19xx)
{
Date_InitStructure.RTC_Months |= PCF_Century_SetBitC;
}
else
{
Date_InitStructure.RTC_Months &= ~PCF_Century_SetBitC;
}
//
//写入信息到寄存器
//
buffer[0] = Time_InitStructure.RTC_Seconds;
buffer[1] = Time_InitStructure.RTC_Minutes;
buffer[2] = Time_InitStructure.RTC_Hours;
PCF8563_Write_nByte(PCF8563_Address_Seconds, 3, buffer); //写入时间信息
buffer[0] = Date_InitStructure.RTC_Days;
buffer[1] = Date_InitStructure.RTC_WeekDays;
buffer[2] = Date_InitStructure.RTC_Months;
buffer[3] = Date_InitStructure.RTC_Years;
PCF8563_Write_nByte(PCF8563_Address_Days, 4, buffer); //写入日期信息
}
15.PCF8563写入时间信息
void PCF8563_SetTime(unsigned char PCF_Format, _PCF8563_Time_Typedef* PCF_DataStruct)
{
if (PCF_Format == PCF_Format_BIN) //十进制格式,需要转换一下
{
//
//判断数值是否在范围之内
//
if (PCF_DataStruct->RTC_Hours > 23) PCF_DataStruct->RTC_Hours = 0; //恢复0小时
if (PCF_DataStruct->RTC_Minutes > 59) PCF_DataStruct->RTC_Minutes = 0; //恢复0分钟
if (PCF_DataStruct->RTC_Seconds > 59) PCF_DataStruct->RTC_Seconds = 0; //恢复0秒
//
//需要转换一下
//
PCF_DataStruct->RTC_Hours = RTC_BinToBcd2(PCF_DataStruct->RTC_Hours);
PCF_DataStruct->RTC_Minutes = RTC_BinToBcd2(PCF_DataStruct->RTC_Minutes);
PCF_DataStruct->RTC_Seconds = RTC_BinToBcd2(PCF_DataStruct->RTC_Seconds);
}
//
//拷贝数据
//
buffer[0] = PCF_DataStruct->RTC_Seconds;
buffer[1] = PCF_DataStruct->RTC_Minutes;
buffer[2] = PCF_DataStruct->RTC_Hours;
//
//写入数据到寄存器
//
PCF8563_Write_nByte(PCF8563_Address_Seconds, 3, buffer);
}
16. PCF8563读取时间信息
void PCF8563_GetTime(unsigned char PCF_Format, _PCF8563_Time_Typedef* PCF_DataStruct)
{
/* 读取寄存器数值 */
PCF8563_Read_nByte(PCF8563_Address_Seconds, 3, buffer); //调用读多为函数,起始地址为秒,长度3,存入buffer数组
/* 屏蔽无效位,将时分秒寄存器的值分别放入数组 */
buffer[0] &= PCF8563_Shield_Seconds;
buffer[1] &= PCF8563_Shield_Minutes;
buffer[2] &= PCF8563_Shield_Hours;
//判断需要的数据格式,
if (PCF_Format == PCF_Format_BIN)
{
PCF_DataStruct->RTC_Hours = RTC_Bcd2ToBin(buffer[2]);
PCF_DataStruct->RTC_Minutes = RTC_Bcd2ToBin(buffer[1]);
PCF_DataStruct->RTC_Seconds = RTC_Bcd2ToBin(buffer[0]);
}
else if (PCF_Format == PCF_Format_BCD)
{
//
//拷贝数据
//
PCF_DataStruct->RTC_Hours = buffer[2];
PCF_DataStruct->RTC_Minutes = buffer[1];
PCF_DataStruct->RTC_Seconds = buffer[0];
}
}
17.PCF8563写入日期信息
void PCF8563_SetDate(unsigned char PCF_Format, unsigned char PCF_Century, _PCF8563_Date_Typedef* PCF_DataStruct)
{
if (PCF_Format == PCF_Format_BIN) //十进制格式,需要转换一下
{
//
//判断数值是否在范围之内
//
if (PCF_DataStruct->RTC_Years > 99) PCF_DataStruct->RTC_Years = 0; //恢复00年
if (PCF_DataStruct->RTC_Months > 12) PCF_DataStruct->RTC_Months = 1; //恢复1月
if (PCF_DataStruct->RTC_Days > 31) PCF_DataStruct->RTC_Days = 1; //恢复1日
if (PCF_DataStruct->RTC_WeekDays > 6) PCF_DataStruct->RTC_WeekDays = 1; //恢复星期一
//
//需要转换一下
//
PCF_DataStruct->RTC_Years = RTC_BinToBcd2(PCF_DataStruct->RTC_Years);
PCF_DataStruct->RTC_Months = RTC_BinToBcd2(PCF_DataStruct->RTC_Months);
PCF_DataStruct->RTC_Days = RTC_BinToBcd2(PCF_DataStruct->RTC_Days);
PCF_DataStruct->RTC_WeekDays = RTC_BinToBcd2(PCF_DataStruct->RTC_WeekDays);
}
//
//判断世纪位
//
if (PCF_Century == PCF_Century_19xx)
{
PCF_DataStruct->RTC_Months |= PCF_Century_SetBitC;
}
else
{
PCF_DataStruct->RTC_Months &= ~PCF_Century_SetBitC;
}
//
//数据拷贝
//
buffer1[0] = PCF_DataStruct->RTC_Days;
buffer1[1] = PCF_DataStruct->RTC_WeekDays;
buffer1[2] = PCF_DataStruct->RTC_Months;
buffer1[3] = PCF_DataStruct->RTC_Years;
//
//写入数据到寄存器
//
PCF8563_Write_nByte(PCF8563_Address_Days, 4, buffer1);
}
18.PCF8563读取日期信息
void PCF8563_GetDate(unsigned char PCF_Format, unsigned char *PCF_Century, _PCF8563_Date_Typedef* PCF_DataStruct)
{
//
//读取全部寄存器数值
//
PCF8563_Read_nByte(PCF8563_Address_Days, 4, buffer1);
//
//判断世纪位数值
//
if (buffer1[2] & PCF_Century_SetBitC)
{
*PCF_Century = 1;
}
else
{
*PCF_Century = 0;
}
//
//屏蔽无效位
//
buffer1[0] &= PCF8563_Shield_Days;
buffer1[1] &= PCF8563_Shield_WeekDays;
buffer1[2] &= PCF8563_Shield_Months_Century;
buffer1[3] &= PCF8563_Shield_Years;
//
//判断需要的数据格式
//
if (PCF_Format == PCF_Format_BIN)
{
PCF_DataStruct->RTC_Years = RTC_Bcd2ToBin(buffer1[3]);
PCF_DataStruct->RTC_Months = RTC_Bcd2ToBin(buffer1[2]);
PCF_DataStruct->RTC_Days = RTC_Bcd2ToBin(buffer1[0]);
PCF_DataStruct->RTC_WeekDays = RTC_Bcd2ToBin(buffer1[1]);
}
else if (PCF_Format == PCF_Format_BCD)
{
//
//拷贝数据
//
PCF_DataStruct->RTC_Years = buffer1[3];
PCF_DataStruct->RTC_Months = buffer1[2];
PCF_DataStruct->RTC_Days = buffer1[0];
PCF_DataStruct->RTC_WeekDays = buffer1[1];
}
}
哎呀好啦好啦,贴了这么多代码也真是难为我啦,这里只贴了部分主要使用的函数,同时为了删减了空行一些占地方的备注;还有一些闹钟什么的用不到,我就没有贴出,如果想看的话我可以到下边找链接到我的资源里下载。
下边我把头文件也贴一下吧,真的希望可以帮到大家:
#ifndef _pcf8563_h_
#define _pcf8563_h_
/****************************** Support C++ **********************************
**/
#ifdef __cplusplus
extern 'C'{
#endif
/**
*****************************************************************************
**/
extern unsigned char buffer1[4];
extern unsigned char buffer[4];
/******************************************************************************
外部函数头文件
应用到不同的外设头文件请在这里修改即可
******************************************************************************/
#include 'iic.h'
/******************************************************************************
参数宏定义
******************************************************************************/
#define PCF8563_Check_Data (unsigned char)0x55 //检测用,可用其他数值
#define PCF8563_Write (unsigned char)0xa2 //写命令
#define PCF8563_Read (unsigned char)0xa3 //读命令,或者用(PCF8563_Write + 1)
//
//电源复位功能
//
#define PCF8563_PowerResetEnable (unsigned char)0x08
#define PCF8563_PowerResetDisable (unsigned char)0x09
//
//世纪位操作定义
//
#define PCF_Century_SetBitC (unsigned char)0x80
#define PCF_Century_19xx (unsigned char)0x03
#define PCF_Century_20xx (unsigned char)0x04
//
//数据格式
//
#define PCF_Format_BIN (unsigned char)0x01
#define PCF_Format_BCD (unsigned char)0x02
//
//设置PCF8563模式用
//
#define PCF_Mode_Normal (unsigned char)0x05
#define PCF_Mode_EXT_CLK (unsigned char)0x06
#define PCF_Mode_INT_Alarm (unsigned char)0x07
#define PCF_Mode_INT_Timer (unsigned char)0x08
/******************************************************************************
参数寄存器地址宏定义
******************************************************************************/
#define PCF8563_Address_Control_Status_1 (unsigned char)0x00 //控制/状态寄存器1
#define PCF8563_Address_Control_Status_2 (unsigned char)0x01 //控制/状态寄存器2
#define PCF8563_Address_CLKOUT (unsigned char)0x0d //CLKOUT频率寄存器
#define PCF8563_Address_Timer (unsigned char)0x0e //定时器控制寄存器
#define PCF8563_Address_Timer_VAL (unsigned char)0x0f //定时器倒计数寄存器
#define PCF8563_Address_Years (unsigned char)0x08 //年
#define PCF8563_Address_Months (unsigned char)0x07 //月
#define PCF8563_Address_Days (unsigned char)0x05 //日
#define PCF8563_Address_WeekDays (unsigned char)0x06 //星期
#define PCF8563_Address_Hours (unsigned char)0x04 //小时
#define PCF8563_Address_Minutes (unsigned char)0x03 //分钟
#define PCF8563_Address_Seconds (unsigned char)0x02 //秒
#define PCF8563_Alarm_Minutes (unsigned char)0x09 //分钟报警
#define PCF8563_Alarm_Hours (unsigned char)0x0a //小时报警
#define PCF8563_Alarm_Days (unsigned char)0x0b //日报警
#define PCF8563_Alarm_WeekDays (unsigned char)0x0c //星期报警
/******************************************************************************
参数屏蔽宏定义
******************************************************************************/
#define PCF8563_Shield_Control_Status_1 (unsigned char)0xa8
#define PCF8563_Shield_Control_Status_2 (unsigned char)0x1f
#define PCF8563_Shield_Seconds (unsigned char)0x7f
#define PCF8563_Shield_Minutes (unsigned char)0x7f
#define PCF8563_Shield_Hours (unsigned char)0x3f
#define PCF8563_Shield_Days (unsigned char)0x3f
#define PCF8563_Shield_WeekDays (unsigned char)0x07
#define PCF8563_Shield_Months_Century (unsigned char)0x1f
#define PCF8563_Shield_Years (unsigned char)0xff
#define PCF8563_Shield_Minute_Alarm (unsigned char)0x7f
#define PCF8563_Shield_Hour_Alarm (unsigned char)0x3f
#define PCF8563_Shield_Day_Alarm (unsigned char)0x3f
#define PCF8563_Shield_WeekDays_Alarm (unsigned char)0x07
#define PCF8563_Shield_CLKOUT_Frequency (unsigned char)0x03
#define PCF8563_Shield_Timer_Control (unsigned char)0x03
#define PCF8563_Shield_Timer_Countdown_Value (unsigned char)0xff
/******************************************************************************
PCF8563寄存器结构定义
******************************************************************************/
/**
==================================================================
全部寄存器结构
==================================================================
**/
typedef struct
{
unsigned char Control_Status_1; //控制寄存器1
unsigned char Control_Status_2; //控制寄存器2
unsigned char Seconds; //秒寄存器
unsigned char Minutes; //分钟寄存器
unsigned char Hours; //小时寄存器
unsigned char Days; //日期寄存器
unsigned char WeekDays; //星期寄存器,数值范围:0 ~ 6
unsigned char Months_Century; //月份寄存器,bit7为世纪位,0:指定世纪数为20xx;1:指定世纪数为19xx
unsigned char Years; //年寄存器
unsigned char Minute_Alarm; //分钟报警寄存器
unsigned char Hour_Alarm; //小时报警寄存器
unsigned char Day_Alarm; //日期报警寄存器
unsigned char WeekDays_Alarm; //星期报警寄存器,数值范围:0 ~ 6
unsigned char CLKOUT_Frequency; //频率管脚输出控制寄存器
unsigned char Timer_Control; //定时器控制寄存器
unsigned char Timer_Countdown_Value; //定时器计数寄存器
}_PCF8563_Register_Typedef;
/**
==================================================================
时间信息结构
==================================================================
**/
typedef struct
{
unsigned char RTC_Hours; //小时
unsigned char RTC_Minutes; //分钟
unsigned char RTC_Seconds; //秒钟
unsigned char Reseved; //保留
}_PCF8563_Time_Typedef;
/**
==================================================================
日期信息结构
==================================================================
**/
typedef struct
{
unsigned char RTC_Years; //年份
unsigned char RTC_Months; //月份
unsigned char RTC_Days; //日期
unsigned char RTC_WeekDays; //星期,数值范围:0 ~ 6
}_PCF8563_Date_Typedef;
/**
==================================================================
闹铃信息结构
==================================================================
**/
typedef struct
{
unsigned short Reseved; //保留
unsigned char RTC_AlarmDays; //日期闹铃
unsigned char RTC_AlarmWeekDays; //星期闹铃,数值范围:0 ~ 6
unsigned char RTC_AlarmHours; //小时闹铃
unsigned char RTC_AlarmMinutes; //分钟闹铃
unsigned char RTC_AlarmNewState; //闹铃开关
//其值有RTC_AlarmNewState_Open、RTC_AlarmNewState_Close、RTC_AlarmNewState_Open_INT_Enable
//只使用其中一个即可
unsigned char RTC_AlarmType; //报警类型,
//其值有RTC_AlarmType_Minutes、RTC_AlarmType_Hours、RTC_AlarmType_Days、RTC_AlarmType_WeekDays
//多个报警类型打开,请用或关系合并
}_PCF8563_Alarm_Typedef;
//
//闹铃开关
//
#define RTC_AlarmNewState_Open (u8)0x01
#define RTC_AlarmNewState_Close (u8)0x02 //闹铃关闭,并且关闭中断输出
#define RTC_AlarmNewState_Open_INT_Enable (u8)0x04 //闹铃开启并开启中断输出
//
//定义闹铃类型
//
#define RTC_AlarmType_Minutes (unsigned char)0x01
#define RTC_AlarmType_Hours (unsigned char)0x02
#define RTC_AlarmType_Days (unsigned char)0x04
#define RTC_AlarmType_WeekDays (unsigned char)0x08
/**
==================================================================
频率输出信息结构
==================================================================
**/
typedef struct
{
unsigned char CLKOUT_Frequency; //输出频率选择
//PCF_CLKOUT_F32768 --> 输出32.768KHz
//PCF_CLKOUT_F1024 --> 输出1024Hz
//PCF_CLKOUT_F32 --> 输出32Hz
//PCF_CLKOUT_F1 --> 输出1Hz
unsigned char CLKOUT_NewState; //输出状态
//PCF_CLKOUT_Close --> 输出被禁止并设成高阻抗
//PCF_CLKOUT_Open --> 输出有效
}_PCF8563_CLKOUT_Typedef;
//
//频率输出寄存器 --> 0x0d
//
#define PCF_CLKOUT_Open (unsigned char)(1<<7) //CLKOUT输出有效
#define PCF_CLKOUT_Close (unsigned char)(~(1<<7)) //CLKOUT输出被禁止并设成高阻抗
#define PCF_CLKOUT_F32768 (unsigned char)0x00 //输出32.768KHz
#define PCF_CLKOUT_F1024 (unsigned char)0x01 //输出1024Hz
#define PCF_CLKOUT_F32 (unsigned char)0x02 //输出32Hz
#define PCF_CLKOUT_F1 (unsigned char)0x03 //输出1Hz
/**
==================================================================
定时器信息结构
==================================================================
**/
typedef struct
{
unsigned char RTC_Timer_Value; //定时器计数器数值,设置定时时长,不需要的直接填0即可
unsigned char RTC_Timer_Frequency; //定时器工作频率
//PCF_Timer_F4096 --> 定时器时钟频率为4096Hz
//PCF_Timer_F64 --> 定时器时钟频率为64Hz
//PCF_Timer_F1 --> 定时器时钟频率为1Hz
//PCF_Timer_F160 --> 定时器时钟频率为1/60Hz
unsigned char RTC_Timer_NewState; //开启状态
//PCF_Timer_Close --> 关闭
//PCF_Timer_Open --> 开启
unsigned char RTC_Timer_Interrupt; //是否设置中断输出
//PCF_Time_INT_Close --> 关闭
//PCF_Time_INT_Open --> 开启
}_PCF8563_Timer_Typedef;
//
//定时器控制寄存器 --> 0x0e
//
#define PCF_Timer_Open (unsigned char)(1<<7) //定时器有效
#define PCF_Timer_Close (unsigned char)(~(1<<7)) //定时器无效
#define PCF_Timer_F4096 (unsigned char)0x00 //定时器时钟频率为4096Hz
#define PCF_Timer_F64 (unsigned char)0x01 //定时器时钟频率为64Hz
#define PCF_Timer_F1 (unsigned char)0x02 //定时器时钟频率为1Hz
#define PCF_Timer_F160 (unsigned char)0x03 //定时器时钟频率为1/60Hz
//
//中断输出开关
//
#define PCF_Time_INT_Open (unsigned char)(1<<0) //定时器中断有效
#define PCF_Time_INT_Close (unsigned char)(~(1<<0)) //定时器中断无效
/******************************************************************************
参数宏定义
******************************************************************************/
//
//控制/状态寄存器1 --> 0x00
//
#define PCF_Control_Status_NormalMode (unsigned char)(~(1<<7)) //普通模式
#define PCF_Control_Status_EXT_CLKMode (unsigned char)(1<<7) //EXT_CLK测试模式
#define PCF_Control_ChipRuns (unsigned char)(~(1<<5)) //芯片运行
#define PCF_Control_ChipStop (unsigned char)(1<<5) //芯片停止运行,所有芯片分频器异步置逻辑0
#define PCF_Control_TestcClose (unsigned char)(~(1<<3)) //电源复位功能失效(普通模式时置逻辑0)
#define PCF_Control_TestcOpen (unsigned char)(1<<3) //电源复位功能有效
//
//控制/状态寄存器2 --> 0x01
//
#define PCF_Control_TI_TF1 (unsigned char)(~(1<<4)) //当TF有效时INT有效,(取决于TIE的状态)
#define PCF_Control_TI_TF2 (unsigned char)(1<<4) //INT脉冲有效,(取决于TIE的状态)
//注意:若AF和AIE有有效时,则INT一直有效
#define PCF_Control_ClearAF (unsigned char)(~(1<<3)) //清除报警
#define PCF_Control_ClearTF (unsigned char)(~(1<<2))
//当报警发生时,AF被值逻辑1;在定时器倒计数结束时,
//TF被值逻辑1,他们在被软件重写前一直保持原有值,
//若定时器和报警中断都请求时,中断源有AF和TF决定,
//若要使清除一个标志位而防止另一标志位被重写,应运用逻辑
//指令AND
#define PCF_Alarm_INT_Open (unsigned char)(1<<1) //报警中断有效
#define PCF_Alarm_INT_Close (unsigned char)(~(1<<1)) //报警中断无效
//
//秒寄存器 --> 0x02
//
#define PCF_Accuracy_ClockNo (unsigned char)(1<<7) //不保证准确的时钟/日历数据
#define PCF_Accuracy_ClockYes (unsigned char)(~(1<<7)) //保证准确的时钟/日历数据
//
//分钟闹铃寄存器 --> 0x09
//
#define PCF_Alarm_MinutesOpen (unsigned char)(~(1<<7)) //分钟报警有效
#define PCF_Alarm_MinutesClose (unsigned char)(1<<7) //分钟报警无效
//
//小时闹铃寄存器 --> 0x0a
//
#define PCF_Alarm_HoursOpen (unsigned char)(~(1<<7)) //小时报警有效
#define PCF_Alarm_HoursClose (unsigned char)(1<<7) //小时报警无效
//
//日期闹铃寄存器 --> 0x0b
//
#define PCF_Alarm_DaysOpen (unsigned char)(~(1<<7)) //日报警有效
#define PCF_Alarm_DaysClose (unsigned char)(1<<7) //日报警无效
//
//星期闹铃寄存器 --> 0x0c
//
#define PCF_Alarm_WeekDaysOpen (unsigned char)(~(1<<7)) //星期报警有效
#define PCF_Alarm_WeekDaysClose (unsigned char)(1<<7) //星期报警无效
/******************************************************************************
外部功能函数
******************************************************************************/
void PCF8563_Write_Byte (unsigned char REG_ADD, unsigned char dat); //PCF8563某寄存器写入一个字节数据
unsigned char PCF8563_Read_Byte (unsigned char REG_ADD); //PCF8563某寄存器读取一个字节数据
void PCF8563_Write_nByte (unsigned char REG_ADD, unsigned char num, unsigned char *pBuff); //PCF8563写入多组数据
void PCF8563_Read_nByte (unsigned char REG_ADD, unsigned char num, unsigned char *pBuff); //PCF8563读取多组数据
unsigned char PCF8563_Check (void); //PCF8563检测是否存在
void PCF8563_Start (void); //PCF8563启动
void PCF8563_Stop (void); //PCF8563停止
void PCF8563_SetMode (unsigned char Mode); //PCF8563设置运行模式
void PCF8563_SetPowerReset (unsigned char NewState); //PCF8563设置电源复位功能开启与关闭
void PCF8563_SetCLKOUT (_PCF8563_CLKOUT_Typedef* PCF_CLKOUTStruct); //PCF8563设置输出频率
void PCF8563_SetTimer (_PCF8563_Timer_Typedef* PCF_TimerStruct); //PCF8563设置定时器
void PCF8563_Set_Times (unsigned char PCF_Format,
unsigned char PCF_Century,
unsigned char Year, unsigned char Month, unsigned char Date, unsigned char Week,
unsigned char Hour, unsigned char Minute); //设置时间,主要用于后台调用,或者初始化时间用
void PCF8563_SetRegister (unsigned char PCF_Format, unsigned char PCF_Century, _PCF8563_Register_Typedef* PCF_DataStruct); //PCF8563写入寄存器
void PCF8563_GetRegister (unsigned char PCF_Format, unsigned char *PCF_Century, _PCF8563_Register_Typedef* PCF_DataStruct); //PCF8563读取寄存器
void PCF8563_SetTime (unsigned char PCF_Format, _PCF8563_Time_Typedef* PCF_DataStruct); //PCF8563写入时间信息
void PCF8563_GetTime (unsigned char PCF_Format, _PCF8563_Time_Typedef* PCF_DataStruct); //PCF8563读取时间信息
void PCF8563_SetDate (unsigned char PCF_Format, unsigned char PCF_Century, _PCF8563_Date_Typedef* PCF_DataStruct); //PCF8563写入日期信息
void PCF8563_GetDate (unsigned char PCF_Format, unsigned char *PCF_Century, _PCF8563_Date_Typedef* PCF_DataStruct); //PCF8563读取日期信息
void PCF8563_SetAlarm (unsigned char PCF_Format, _PCF8563_Alarm_Typedef* PCF_DataStruct); //PCF8563写入闹铃信息
void PCF8563_GetAlarm (unsigned char PCF_Format, _PCF8563_Alarm_Typedef* PCF_DataStruct); //PCF8563读取闹铃信息
void PCF8563_SetDT( void );
void PF8563_GetFunc( _PCF8563_Time_Typedef* PCF_TimeStruct, _PCF8563_Date_Typedef* PCF_DataStruct );
/**
****************************** Support C++ **********************************
**/
#ifdef __cplusplus
}
#endif
/**
*****************************************************************************
**/
#endif /* end pcf8563.h */