** PCF8563 是低功耗的CMOS 实时时钟/日历芯片,它提供一个可编程时钟输出,一个
中断输出和掉电检测器,所有的地址和数据通过I2C 总线接口串行传递。最大总线速度为
400Kbits/s,每次读写数据后,内嵌的字地址寄存器会自动产生增量。**
本次开发时基于STM32407上的项目,使用过程如下:
(1)初始化I2C,
在main中加入初始化
/* I2C1 init function */
void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 100000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c3) ;
// if (HAL_I2C_Init(&hi2c2) != HAL_OK)
// {
// _Error_Handler(__FILE__, __LINE__);
// }
}
在stm32f2xx_hal_msp.c中添加i2c引脚定义
else if(hi2c->Instance==I2C3)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PA8 ------> I2C2_SCL
PC9 ------> I2C2_SDA
*/
// GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2); //GPIOA2???¡§???aUSART2
// GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2); //GPIOA3???¡§???aUSART2
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Peripheral clock enable */
__I2C3_CLK_ENABLE();
/* Peripheral interrupt init*/
HAL_NVIC_SetPriority(I2C3_EV_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
HAL_NVIC_SetPriority(I2C3_ER_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
与:
else if(hi2c->Instance==I2C3) //2117.11013
{
/* USER CODE BEGIN I2C1_MspDeInit 0 */
/* USER CODE END I2C1_MspDeInit 0 */
/* Peripheral clock disable */
__I2C3_CLK_DISABLE();
/**I2C3 GPIO Configuration
PC9 ------> I2C3_SDA
PA8 ------> I2C3_SCL
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8);
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_9);
/* Peripheral interrupt DeInit*/
HAL_NVIC_DisableIRQ(I2C3_EV_IRQn);
HAL_NVIC_DisableIRQ(I2C3_ER_IRQn);
}
在stm32f2xx_it.c中添加中断函数
void I2C1_ER_IRQHandler(void)
{
/* USER CODE BEGIN I2C1_ER_IRQn 0 */
/* USER CODE END I2C1_ER_IRQn 0 */
HAL_I2C_ER_IRQHandler(&hi2c1);
/* USER CODE BEGIN I2C1_ER_IRQn 1 */
/* USER CODE END I2C1_ER_IRQn 1 */
}
/**
* @brief This function handles I2C3 event interrupt.
*/
void I2C3_EV_IRQHandler(void)
{
/* USER CODE BEGIN I2C3_EV_IRQn 0 */
/* USER CODE END I2C3_EV_IRQn 0 */
HAL_I2C_EV_IRQHandler(&hi2c3);
/* USER CODE BEGIN I2C3_EV_IRQn 1 */
/* USER CODE END I2C3_EV_IRQn 1 */
}
/**
* @brief This function handles I2C3 error interrupt.
*/
void I2C3_ER_IRQHandler(void)
{
/* USER CODE BEGIN I2C3_ER_IRQn 0 */
/* USER CODE END I2C3_ER_IRQn 0 */
HAL_I2C_ER_IRQHandler(&hi2c3);
/* USER CODE BEGIN I2C3_ER_IRQn 1 */
/* USER CODE END I2C3_ER_IRQn 1 */
}
i2C初始化完成后,开始写 pcf8563的驱动程序
(1)
添加结构体,用于存放时间
struct PCF8563_Time
{
unsigned char Year; // 年
unsigned char Month; //月
unsigned char Day; //日
unsigned char WeekDay; //星期
unsigned char Hours; //小时
unsigned char Minutes; //分钟
unsigned char Seconds; //秒
};
(2)添加 驱动代码
/********************************************************************************
* File Name : PCF8563.c
* Author : TLS
* Date : 2017.11.15
* Description : pcf8563驱动程序,使用硬件I2C3,在mian 中初始化 i2c,
通过I2C 读写PCF8563 相关寄存器地址 完成时间的读写
********************************************************************************/
#include "main.h"
#define PCF8563_Write (unsigned char)0xa2 //写命令
#define PCF8563_Read (unsigned char)0xa3 //读命令
#define PCF8563_SUCCESS 0
#define PCF8563_FAIL 1
/******************************************************************************
参数寄存器地址宏定义
******************************************************************************/
#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 //星期报警
//PCF8563_TimeTypeDef PCF8563_Time;
extern I2C_HandleTypeDef hi2c3;
/*
//时间:2017.10.26
//作者:tls
//功能:实现向16进制到 bcd码转换
//参数:BINValue 需要转换的 16进制数值
//返回:转换后的 bcd码
*/
unsigned char BinToBcd2(unsigned char BINValue)
{
unsigned char bcdhigh = 0;
while (BINValue >= 10)
{
bcdhigh++;
BINValue -= 10;
}
return ((unsigned char)(bcdhigh << 4) | BINValue);
}
/*
//时间:2017.10.26
//作者:tls
//功能:实现向BCD码到16进制转换
//参数:BINValue 需要转换的 BCD码
//返回:转换后的 16进制数
*/
unsigned char 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));
}
/*
//时间:2017.10.26
//作者:tls
//功能:实现向pcf8563中写入一个时间值
//参数:add 写入地址
// data 写入数据
// size 数据大小
//返回:0-> 失败 1-> 成功
*/
char PCF8563_Write_Time(unsigned char add,unsigned char data,uint16_t size )
{
HAL_StatusTypeDef sta;
sta=HAL_I2C_Mem_Write_IT(&hi2c3, PCF8563_Write, add,I2C_MEMADD_SIZE_8BIT, &data, size);
osDelay(20);
if(sta!=HAL_OK)
{
return 0; //发送失败
}
else
{
return 1; //发送成功
}
}
/*
//时间:2017.10.26
//作者:tls
//功能:实现向pcf8563中写入一个时间值
//参数:add 读取寄存器地址
// data 读取缓存区
// size 数据大小
//返回:0-> 失败 1-> 成功
*/
char PCF8563_Read_Time(unsigned char add,uint8_t * pdata,uint16_t size )
{
HAL_StatusTypeDef sta;
sta=HAL_I2C_Mem_Read_IT(&hi2c3, PCF8563_Read, add,I2C_MEMADD_SIZE_8BIT, pdata, size);
osDelay(10);
if(sta!=HAL_OK)
{
return 0; //发送失败
}
else
{
return 1; //发送成功
}
}
//设置相应时间
/******************************************************************/
char PCF8563_Set_Years(char Years) //写入 年
{
char Time_data = 0;
if(Years>99)
{
return PCF8563_FAIL ;
}
Time_data = BinToBcd2(Years)&0x7f;
if(PCF8563_Write_Time(PCF8563_Address_Years,Time_data,1 ))
{
return PCF8563_SUCCESS;
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Set_Months(char Months) //写入 月
{
char Time_data = 0;
if(Months < 1 || Months > 12)
{
return PCF8563_FAIL;
}
Time_data= BinToBcd2(Months);
if( PCF8563_Write_Time(PCF8563_Address_Months,Time_data,1 ) )
{
return PCF8563_SUCCESS;
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Set_Days(char Days) //写入 日
{
char Time_data = 0;
if( Days > 31)
{
return PCF8563_FAIL;
}
Time_data= BinToBcd2(Days );
if( PCF8563_Write_Time(PCF8563_Address_Days,Time_data,1 ) )
{
return PCF8563_SUCCESS;
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Set_WeekDays(char WeekDays) //写入 星期
{
char Time_data = 0;
if( WeekDays > 6)
{
return PCF8563_FAIL;
}
Time_data= BinToBcd2(WeekDays );
if( PCF8563_Write_Time(PCF8563_Address_WeekDays,Time_data,1 ) )
{
return PCF8563_SUCCESS;
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Set_Hours(char Hours) //写入 时
{
char Time_data = 0;
if( Hours> 23)
{
return PCF8563_FAIL;
}
Time_data= BinToBcd2(Hours);
if( PCF8563_Write_Time(PCF8563_Address_Hours,Time_data,1 ) )
{
return PCF8563_SUCCESS;
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Set_Minutes(char Minutes) //写入 分
{
char Time_data = 0;
if( Minutes > 59)
{
return PCF8563_FAIL;
}
Time_data= BinToBcd2(Minutes);
if( PCF8563_Write_Time(PCF8563_Address_Minutes,Time_data,1 ) )
{
return PCF8563_SUCCESS;
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Set_Seconds(char Seconds) //写入 秒
{
char Time_data = 0;
if(Seconds > 59)
{
return PCF8563_FAIL;
}
Time_data= BinToBcd2(Seconds );
if( PCF8563_Write_Time(PCF8563_Address_Seconds,Time_data,1 ) )
{
return PCF8563_SUCCESS;
}
else
{
return PCF8563_FAIL ;
}
}
//读出相应时间
/**************************************************************************/
//用于存放 读取出来的数据
char PCF8563_Read_Years(uint8_t *Years) //读出 年
{
uint8_t tmep_year = 0;
if(PCF8563_Read_Time(PCF8563_Address_Years,&tmep_year,1 ) )
{
tmep_year &= 0x7F;
tmep_year= Bcd2ToBin(tmep_year);
if(tmep_year>99)
{
return PCF8563_FAIL;
}
else
{
*Years = tmep_year;
return PCF8563_SUCCESS;
}
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Read_Months(uint8_t *Months) //读出 月
{
uint8_t temp_month =0 ;
if(PCF8563_Read_Time(PCF8563_Address_Months,&temp_month,1 ) )
{
temp_month &= 0x1F;
temp_month= Bcd2ToBin(temp_month);
if(temp_month<1||temp_month>12)
{
return PCF8563_FAIL;
}
else
{
*Months = temp_month ;
return PCF8563_SUCCESS;
}
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Read_Days(uint8_t * Days) //读出 日
{
uint8_t Time_data = 0;
if(PCF8563_Read_Time(PCF8563_Address_Days,&Time_data,1 ) )
{
Time_data&= 0x3F;
Time_data= Bcd2ToBin(Time_data);
if(Time_data<1||Time_data>31)
{
return PCF8563_FAIL;
}
else
{
* Days = Time_data ;
return PCF8563_SUCCESS;
}
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Read_WeekDays(uint8_t * WeekDays) //读出 星期
{
uint8_t Time_data = 0;
if(PCF8563_Read_Time(PCF8563_Address_WeekDays,&Time_data,1 ) )
{
Time_data &= 0x07;
Time_data= Bcd2ToBin(Time_data); //****
if(Time_data>6)
{
return PCF8563_FAIL;
}
else
{
* WeekDays = Time_data;
return PCF8563_SUCCESS;
}
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Read_Hours(uint8_t * Hours) //读出 时
{
uint8_t Time_data = 0;
if(PCF8563_Read_Time(PCF8563_Address_Hours,&Time_data,1 ) )
{
Time_data &= 0x3F;
Time_data= Bcd2ToBin(Time_data);
if(Time_data>23)
{
return PCF8563_FAIL;
}
else
{
* Hours = Time_data ;
return PCF8563_SUCCESS;
}
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Read_Minutes(uint8_t * Minutes) //读出 分
{
uint8_t Time_data = 0;
if(PCF8563_Read_Time(PCF8563_Address_Minutes,&Time_data,1 ) )
{
Time_data &= 0x7F;
Time_data = Bcd2ToBin(Time_data);
if(Time_data>59)
{
return PCF8563_FAIL;
}
else
{
* Minutes = Time_data;
return PCF8563_SUCCESS;
}
}
else
{
return PCF8563_FAIL ;
}
}
char PCF8563_Read_Seconds(uint8_t * Seconds) //读出 秒
{
uint8_t Time_data = 0;
if(PCF8563_Read_Time(PCF8563_Address_Seconds,&Time_data,1 ) )
{
Time_data &= 0x7F;
Time_data= Bcd2ToBin(Time_data);
if(Time_data>59)
{
return PCF8563_FAIL;
}
else
{
* Seconds = Time_data ;
return PCF8563_SUCCESS;
}
}
else
{
return PCF8563_FAIL ;
}
}
char set_err =0 ;
char System_set_times(struct PCF8563_Time *PCF8563_Time) //设置系统时钟
{
uint8_t Error =0 ;
if(PCF8563_Set_Years(PCF8563_Time->Year))
{
Error++;
}
if(PCF8563_Set_Months(PCF8563_Time->Month))
{
Error++;
}
if(PCF8563_Set_Days(PCF8563_Time->Day))
{
Error++;
}
if(PCF8563_Set_WeekDays(PCF8563_Time->WeekDay))
{
Error++;
}
if(PCF8563_Set_Hours(PCF8563_Time->Hours))
{
Error++;
}
if(PCF8563_Set_Minutes(PCF8563_Time->Minutes))
{
Error++;
}
if(PCF8563_Set_Seconds(PCF8563_Time->Seconds))
{
Error++;
}
set_err = Error ;
if(Error==0)
{
return 1;
}
else
{
return 0;
}
}
char read_err = 0;
uint8_t Seconds,Minutes,Hours,Days,Months,Years,Weekdays;
char System_Read_times(struct PCF8563_Time *PCF8563_Time) //读取系统时间
{
uint8_t Error = 0;
if(PCF8563_Read_Years(&Years))
{
Error++;
}
if(PCF8563_Read_Months(&Months))
{
Error++;
}
if(PCF8563_Read_Days(&Days))
{
Error++;
}
if(PCF8563_Read_WeekDays(&Weekdays))
{
Error++;
}
if(PCF8563_Read_Hours(&Hours))
{
Error++;
}
if(PCF8563_Read_Minutes(&Minutes))
{
Error++;
}
if(PCF8563_Read_Seconds(&Seconds))
{
Error++;
}
read_err = Error;
if(Error==0)
{
PCF8563_Time->Year =Years;
PCF8563_Time->Month =Months;
PCF8563_Time->Day =Days;
PCF8563_Time->WeekDay =Weekdays;
PCF8563_Time->Hours =Hours;
PCF8563_Time->Minutes =Minutes;
PCF8563_Time->Seconds =Seconds;
Error = 0;
return 1;
}
else
{
Error = 0;
return 0;
}
}