【模块系列】STM32&PCF8563

前言

看着网上的PCF8563例程,挺乱的,我就照着中文手册自己写了个。主要还是基于STM32的HAL库,下的硬件I2C写的。I2C的接口层是用HAL库的,不过只用到了两个关键接口,I2C的连续发和连续收,所以要移植到如模拟I2C上,只需要更换为自己的I2C接口即可。

代码流程,主要是基于器件对象化,编写调用。函数已经包括完了芯片寄存器的4个功能模块,状态、时间、警报(闹钟)、计时。只是没有对所有细致功能方向,进行分离出来单独编写,如警报(闹钟)设置触发清除的全流程等等,就没有独立出来,要使用的话,还是要在器件对象类进行配置。

环境

开发板:自制STM32RET6开发板

案例的代码环境:Keil5+STM32CubeMX生成的HAL库,硬件I2C+FreeRTOS

注意事项:购买PCF8563模块,有些是没有上拉电阻的,需要自己加的,这个坑我在调试的时候遇到了。

手册

下述介绍参考数据手册,让大家对PCF8563有个基本的了解。

简介

PCF8563 是一款低功耗的 CMOS1实时时钟/日历芯片,支持可编程时钟输出、中断输出 和低压检测。所有地址和数据通过双线双向 I 2C 总线串联传输,最高速率:400 kbps。每 次读写数据字节后,寄存器地址自动累加。

特点

  • 基于 32.768kHz 的晶振,提供年、月、日、星期、时、分和秒计时
  • 世纪标志位
  • 时钟工作电压:1.0 - 5.5 V(室温)
  • 低备用电流;典型值为 0.25 μA(VDD = 3.0 V,Tamb =25 °C)
  • 400 kHz 双线 I 2C 总线接口(VDD = 1.8 - 5.5 V)
  • 可编程时钟输出(32.768 kHz、1.024 kHz、32 Hz 和 1Hz)
  • 报警和定时器功能
  • 集成晶振电容器
  • 内部上电复位(POR)
  • I2C总线从机地址:读:A3h;写:A2h
  • 开漏中断管脚

代码

下面仅展示PCF8563库,完整的工程文件会放在末尾。该库对基本操作,设置获取时间,设置获取状态,设置警报时间等常规操作,都是支持的,都验证过,至于其它的还没做验证或者扩写,如果有错误的地方,也欢迎大家提出来!

PCF8563.H

c 复制代码
#ifndef __PCF8563_H__
#define __PCF8563_H__

// PCF8563对象结构
typedef struct{
	/* 控制(原始数据) */
	uint8_t status1;		// 状态1
	uint8_t status2;		// 状态2
	uint8_t clkout;		// 时钟输出
	/* 时间(10进制) */
	uint8_t seconds;		// 秒
  uint8_t minutes;		// 分钟
  uint8_t hours;			// 小时
  uint8_t days;			// 天
  uint8_t weekdays;	// 周天(星期几)
  uint8_t months;		// 月
  uint8_t years;			// 年
	/* 报警功能(10进制) */
	uint8_t Minute_alarm;		// 分钟报警
	uint8_t Minute_alarm_en;	// 分钟报警是否启用
	uint8_t Hour_alarm;			// 小时报警
	uint8_t Hour_alarm_en;		// 小时报警是否启用
	uint8_t Day_alarm;				// 天数报警
	uint8_t Day_alarm_en;		// 天数报警是否启用
	uint8_t Weekday_alarm;		// 周数报警
	uint8_t Weekday_alarm_en;// 周数报警是否启用
	/* 定时器功能(原始数据) */
	uint8_t Timer_control;		// 定时器控制
	uint8_t Timer_en;				// 定时器是否启用
	uint8_t Timer;						// 定时器
	/* 其它标志位 */
	uint8_t vl;							// 时钟信息是否完整
}PCF8563_Obj;

typedef enum {
	Hz4K 		= 0x00,	// 4.096 KHz
	Hz64 		= 0x01,	// 64 		Hz
	Hz1	 		= 0x02,	// 1 			Hz
	Hz1d60	= 0x03	// 1/60		Hz
}PCF8563_TimerFrequency;

typedef enum {
	Disenabled 		= 0x00,	// 禁用
	Enabled 			= 0x01,	// 启用
}PCF8563_TimerEn;

// PCF8563下定时器对象结构
typedef struct {
	PCF8563_TimerEn timerEn;								// 定时器是否启用
	uint8_t value;													// 定时器值
	PCF8563_TimerFrequency frequency;				// 定时器频率选择
}PCF8563_Timer_Obj;

void PCF8563_Init(void);		// PCF8563初始化

/* 全部配置 */
void PCF8563_GetStatus(PCF8563_Obj *obj);							// 获取状态数据
void PCF8563_GetClkout(PCF8563_Obj *obj);							// 获取输出数据
void PCF8563_GetTimeData(PCF8563_Obj *obj);						// 获取时间数据
void PCF8563_GetAlarmFunction(PCF8563_Obj *obj);			// 获取报警数据
void PCF8563_GetTimerFunction(PCF8563_Obj *obj);			// 获取定时器数据

void PCF8563_SetStatus(PCF8563_Obj *obj);							// 设置状态数据
void PCF8563_SetClkout(PCF8563_Obj *obj);							// 设置输出数据
void PCF8563_SetTimeData(PCF8563_Obj *obj);						// 设置时间数据
void PCF8563_SetAlarmFunction(PCF8563_Obj *obj);			// 设置报警数据
void PCF8563_SetTimerFunction(PCF8563_Obj *obj);			// 设置定时器数据

void PCF8563_GetVL(PCF8563_Obj *obj);									// 获取 VL 标志符

/* 细化配置 */
void PCF8563_ControlTimer(PCF8563_Timer_Obj *timer);	// 控制定时器

#endif

PCF8563.C

c 复制代码
#include "main.h"
#include "cmsis_os.h"
#include "i2c.h"

#include "PCF8563.h"

#define  PCF8563_7BitAddress  0x51
#define  PCF8563_8BitAddress_Read		(PCF8563_7BitAddress << 1) | 0x01
#define  PCF8563_8BitAddress_Write	(PCF8563_7BitAddress << 1)

#define  PCF8563_Delay(ms)  osDelay(ms)
// #define  PCF8563_BcdToTen(data, ) 

// PCF8563初始化
void PCF8563_Init()
{
	
}

// 获取状态
void PCF8563_GetStatus(PCF8563_Obj *obj)
{
	uint8_t pData_GetStatus1[] = { 0x00 };	// 写入指针命令	
	uint8_t pData_Receive[2];	// 接受数据
	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_GetStatus1, 1, 100);
	HAL_I2C_Master_Receive(&hi2c2, PCF8563_8BitAddress_Read, pData_Receive, 2, 100);
	obj->status1 = pData_Receive[0];
	obj->status2 = pData_Receive[1];
}

// 获取输出数据
void PCF8563_GetClkout(PCF8563_Obj *obj)
{
	uint8_t pData_GetClkout[] = { 0x0D };	// 写入指针命令	
	uint8_t pData_Receive[1];	// 接受数据
	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_GetClkout, 1, 100);
	HAL_I2C_Master_Receive(&hi2c2, PCF8563_8BitAddress_Read, pData_Receive, 1, 100);
	
	obj->clkout = pData_Receive[0];
}	

// 获取时间数据
void PCF8563_GetTimeData(PCF8563_Obj *obj)
{
	uint8_t pData_PointerReset[] = { 0x02 };	// 写入指针命令	
	uint8_t pData_Receive[7];	// 接受数据
	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_PointerReset, 1, 100);
	HAL_I2C_Master_Receive(&hi2c2, PCF8563_8BitAddress_Read, pData_Receive, 7, 100);
	
	// 数据稳定下读取秒(BCD转10进制)
	// if(pData_Receive[0] >> 7 == 0x01) obj->seconds = (pData_Receive[0] & 0x0F) + ((pData_Receive[0] & 0x70 ) >> 4) * 10;
	obj->seconds = (pData_Receive[0] & 0x0F) + ((pData_Receive[0] & 0x70 ) >> 4) * 10;
	obj->minutes = (pData_Receive[1] & 0x0F) + ((pData_Receive[1] & 0x70 ) >> 4) * 10;	// 分钟
	obj->hours = (pData_Receive[2] & 0x0F) + ((pData_Receive[2] & 0x30 ) >> 4) * 10;		// 小时
	obj->days = (pData_Receive[3] & 0x0F) + ((pData_Receive[3] & 0x30 ) >> 4) * 10;			// 天
	obj->weekdays = (pData_Receive[4] & 0x07);																					// 周
	obj->months = (pData_Receive[5] & 0x0F) + ((pData_Receive[5] & 0x10 ) >> 4) * 10;		// 月(世纪未加入计算)
	obj->years = (pData_Receive[6] & 0x0F) + ((pData_Receive[6] & 0xF0 ) >> 4) * 10;		// 年
}

// 获取报警数据
void PCF8563_GetAlarmFunction(PCF8563_Obj *obj)
{
	uint8_t pData_AlarmFunction[] = { 0x09 };	// 写入指针命令	
	uint8_t pData_Receive[4];	// 接受数据
	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_AlarmFunction, 1, 100);
	HAL_I2C_Master_Receive(&hi2c2, PCF8563_8BitAddress_Read, pData_Receive, 4, 100);
	
	obj->Minute_alarm 		= (pData_Receive[0] & 0x0F) + ((pData_Receive[0] & 0x70 ) >> 4) * 10;
	obj->Minute_alarm_en 	= (pData_Receive[0] >> 7);
	obj->Hour_alarm 			= (pData_Receive[1] & 0x0F) + ((pData_Receive[1] & 0x30 ) >> 4) * 10;
	obj->Hour_alarm_en 		= (pData_Receive[1] >> 7);
	obj->Day_alarm 				= (pData_Receive[2] & 0x0F) + ((pData_Receive[2] & 0x30 ) >> 4) * 10;
	obj->Day_alarm_en 		= (pData_Receive[2] >> 7);
	obj->Weekday_alarm 		= (pData_Receive[3] & 0x07);
	obj->Weekday_alarm_en = (pData_Receive[3] >> 7);
}

// 获取定时器数据
void PCF8563_GetTimerFunction(PCF8563_Obj *obj)
{
	uint8_t pData_TimerFunction[] = { 0x0E };	// 写入指针命令	
	uint8_t pData_Receive[2];	// 接受数据
	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_TimerFunction, 1, 100);
	HAL_I2C_Master_Receive(&hi2c2, PCF8563_8BitAddress_Read, pData_Receive, 2, 100);
	
	obj->Timer_control = pData_Receive[0];
	obj->Timer = pData_Receive[1];
}

// 设置状态数据
void PCF8563_SetStatus(PCF8563_Obj *obj)
{
	uint8_t pData_SetStatus[] = { 0x00, obj->status1, obj->status2};	// 写入状态命令	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_SetStatus, 1 + 2, 100);
}

// 设置输出数据
void PCF8563_SetClkout(PCF8563_Obj *obj)
{
	uint8_t pData_GetClkout[] = { 0x0D, obj->clkout};	// 写入指针命令	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_GetClkout, 1 + 1, 100);
}

// 设置时间数据
void PCF8563_SetTimeData(PCF8563_Obj *obj)
{
	// 写入指针命令	
	uint8_t pData_PointerReset[] = { 
		0x02,
		((obj->seconds / 10) << 4)  | (obj->seconds % 10),
		((obj->minutes / 10) << 4)  | (obj->minutes % 10),
		((obj->hours / 10) << 4)  	| (obj->hours % 10),
		((obj->days / 10) << 4)  		| (obj->days % 10),
		(obj->weekdays % 10),
		((obj->months / 10) << 4)  	| (obj->months % 10),
		((obj->years / 10) << 4)  	| (obj->years % 10),
	};	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_PointerReset, 1 + 7, 100);
}

// 设置报警数据
void PCF8563_SetAlarmFunction(PCF8563_Obj *obj)
{
	// 写入指针命令	
	uint8_t pData_AlarmFunction[1 + 4] = { 
		0x09,
		(obj->Minute_alarm_en << 7) 	| ((obj->Minute_alarm % 10) + ((obj->Minute_alarm / 10) << 4)),
		(obj->Hour_alarm_en << 7) 		| ((obj->Hour_alarm % 10) + ((obj->Hour_alarm / 10) << 4)),
		(obj->Day_alarm_en << 7) 			| ((obj->Day_alarm % 10) + ((obj->Day_alarm / 10) << 4)),
		(obj->Weekday_alarm_en << 7) 	| ((obj->Weekday_alarm % 10) + ((obj->Weekday_alarm / 10) << 4)),
	};	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_AlarmFunction, 1 + 4, 100);
}

// 设置定时器数据
void PCF8563_SetTimerFunction(PCF8563_Obj *obj)
{
	// 写入指针命令
	uint8_t pData_TimerFunction[1 + 2] = { 
		0x0E,
		obj->Timer_control,
		obj->Timer
	};
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_TimerFunction, 1 + 2, 100);
}

// 获取 VL 标志符
// 描述:当时钟信息的完整性得不到保障时,如VDD掉到Vlow以下时,VL被置'1',必需手动清除
void PCF8563_GetVL(PCF8563_Obj *obj)
{
	uint8_t pData_GetVL[] = { 0x00 };	// 写入指针命令	
	uint8_t pData_Receive[1];	// 接受数据
	
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_GetVL, 1, 100);
	HAL_I2C_Master_Receive(&hi2c2, PCF8563_8BitAddress_Read, pData_Receive, 1, 100);
	obj->vl = pData_Receive[0] >> 7;
}

// 控制定时器
void PCF8563_ControlTimer(PCF8563_Timer_Obj *timer)
{
	// 写入指针命令
	uint8_t pData_TimerFunction[1 + 2] = { 
		0x0E,
		(timer->timerEn << 7) | (timer->frequency),
		timer->value
	};
	HAL_I2C_Master_Transmit(&hi2c2, PCF8563_8BitAddress_Write, pData_TimerFunction, 1 + 2, 100);
}

main.c(节选)

c 复制代码
void Task1_PCF8563(void *argument)
{
	PCF8563_Obj PCF8563 = {0};
	printf("Task1_PCF8563();\r\n");
	
	// 设置时间数据(测试)
	PCF8563.seconds = 50;		// 秒
	PCF8563.minutes = 59;		// 分钟
	PCF8563.hours		= 23;		// 小时
	PCF8563.days		=	31;		// 天
	PCF8563.weekdays= 00;		// 周数
	PCF8563.months  = 12;		// 月
	PCF8563.years		= 24;		// 年
	PCF8563_SetTimeData(&PCF8563);
	// 设置状态数据(测试)
	PCF8563.status1 = 0x00;	// 状态1
	PCF8563.status2 = 0x00; // 状态2
	PCF8563_SetStatus(&PCF8563);
	// 设置报警数据(测试)
	PCF8563.Minute_alarm = 00;			// 分钟报警
	PCF8563.Minute_alarm_en = 0;		// 分钟报警是否启用
	PCF8563.Hour_alarm = 20;				// 小时报警
	PCF8563.Hour_alarm_en = 1;			// 小时报警是否启用
	PCF8563.Day_alarm = 30;					// 天数报警
	PCF8563.Day_alarm_en = 1;				// 天数报警是否启用
	PCF8563.Weekday_alarm = 6;			// 周数报警
	PCF8563.Weekday_alarm_en = 1;		// 周数报警是否启用
	PCF8563_SetAlarmFunction(&PCF8563);
	
	for(;;)
	{
		taskENTER_CRITICAL();		//任务级进入临界段
		// 获取状态(测试)
		PCF8563_GetStatus(&PCF8563);
		// 获取时间数据(测试)
		PCF8563_GetTimeData(&PCF8563);
		// 报警功能(测试)
		PCF8563_GetAlarmFunction(&PCF8563);
		taskEXIT_CRITICAL();		//任务级退出临界段
		
		// 状态1 2
		printf("PCF8563Status:%x %x\r\n",PCF8563.status1,PCF8563.status2);
		// 报警功能
		printf("PCF8563Alarm:%d %d %d %d %d %d %d %d\r\n",PCF8563.Minute_alarm,PCF8563.Minute_alarm_en,PCF8563.Hour_alarm,PCF8563.Hour_alarm_en,PCF8563.Day_alarm,PCF8563.Day_alarm_en,PCF8563.Weekday_alarm,PCF8563.Weekday_alarm_en);
		// 年 月 周天(星期几) 天 时 分 秒
		printf("PCF8563Time:%d %d %d %d %d %d %d\r\n",PCF8563.years,PCF8563.months,PCF8563.weekdays,PCF8563.days,PCF8563.hours,PCF8563.minutes,PCF8563.seconds);
		osDelay(1000);
	}
}

现象

工程

PCF8563中文手册*1 , Keil5工程代码*1

链接: https://pan.baidu.com/s/1V9BH01WMhuAOnOhM0ywZew  提取码: fy7x

相关推荐
Be Legendary-CGK1 小时前
有源模拟滤波器的快速设计
嵌入式硬件·硬件工程
M-x_y1 小时前
排序算法--C语言
c语言·算法·排序算法·设计语言
五味香1 小时前
Java学习,字符串搜索
java·c语言·开发语言·python·学习·golang·kotlin
Anin蓝天(北京太速科技-陈)1 小时前
204-基于Xilinx Virtex-6 XC6VLX240T 和TI DSP TMS320C6678的信号处理板
嵌入式硬件·fpga开发·信号处理
Jack电子实验室2 小时前
STM32 出租车计价器系统设计(一) 江科大源码改写
c语言·stm32·单片机·嵌入式硬件·嵌入式
Coding~2 小时前
逆向攻防世界CTF系列56-easy_Maze
c语言·汇编·算法·安全·网络安全
腾飞的信仰2 小时前
51单片机 串口UART
单片机·嵌入式硬件·51单片机
PluviophileDD2 小时前
【笔记】C语言转C++
c语言·c++
电子科技圈2 小时前
XMOS将在CES 2025上展出多款由边缘AI驱动的创新音效、音频、识别和处理解决方案
人工智能·科技·嵌入式硬件·mcu·物联网·音视频·iot
绿白尼3 小时前
Linux C所有预定义的宏
linux·c语言