本文最后修改时间:2025年01月09日
一、本节简介
本文介绍如何使用MT32F006通过IIC与pcf8563通信。
二、实验平台
库版本:V1.0.0
编译软件:MDK5.37
硬件平台:MT32F006开发板(主芯片MT32F006)
仿真器:JLINK
三、版权声明
1)作者:甜甜的大香瓜
2)声明:喝水不忘挖井人,转载请注明出处。
3)纠错/业务合作:897503845@qq.com
4)香瓜嵌入式之STM8/STM32群:164311667
5)本文出处:原创连载资料《简单粗暴学MT32F006》
6)完整开源资料下载地址(电脑端打开):opengua.taobao.com
四、实验前提
1、在进行本文步骤前,请先阅读以下章节:
1)《简单粗暴学MT32F006》的“第一章和第二章”章节。
暂无
2、在进行本文步骤前,请先实现以下章节:
1)《简单粗暴学MT32F006》的《MT32F006之IIC》。
五、基础知识
1、pcf8563是什么?如何使用?
答:PCF8563 是一款由恩智浦(NXP)生产的低功耗实时时钟(RTC)芯片。
它可以通过iic来设置时间、闹钟。但要注意闹钟只能设置日、时、分,所以只能设置一个月以内的。
举例:如果想设置一年的闹钟,但RTC只允许设置一个月内的,所以在每次闹钟到时间后读出RTC的时间,判断当前年和月是否是我们想要的。
六、硬件原理
Pcf8563引脚 |
Mt006引脚 |
高电平时 |
低电平时 |
SDA |
PIO1_7 |
||
SCL |
PIO2_0 |
||
INT |
PIO0_2 |
没有闹钟 |
闹钟到时间 |
注:INT是根据设置的不同而不同,本文中将INT作为闹钟的中断脚
七、实验步骤
1、编写并添加驱动
1)编写驱动GUA_Pcf8563.c(存放在“……\Projects\MT006_StdPeriph_Templates\GUA”)
//********************************************************************** //name: GUA_Pcf8563.c //introduce: Pcf8563驱动 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** #include "GUA_Pcf8563.h" #include "string.h" #include "mt006.h" #include "stdio.h" #include "GUA_IIC.h" /*********************宏定义************************/ //默认设备地址是7位地址,左移1位为8位地址,最低位将用于读写标志 #define GUA_PCF8563_ADDR (0x51<<1) //控制寄存器 #define GUA_PCF8563_REG_CONTROL_STATUS_1 0x00 //控制寄存器1 #define GUA_PCF8563_REG_CONTROL_STATUS_2 0x01 //控制寄存器2 状态寄存器 //时间寄存器 #define GUA_PCF8563_REG_VL_SECONDS 0x02 //第7位VL(0表示数据可靠,1表示掉电过数据不可靠) 其他位秒00~59秒 #define GUA_PCF8563_REG_MINUTES 0x03 //分 00~59分 #define GUA_PCF8563_REG_HOURS 0x04 //小时 00~23小时 #define GUA_PCF8563_REG_DAYS 0x05 //日 01~31天 #define GUA_PCF8563_REG_WEEKS 0x06 //星期 0~6 #define GUA_PCF8563_REG_CENTURY_MONTHS 0x07 //第7位世纪标志C(0表示世纪为x,1表示世纪为x+1) 0~4位月份 0~12 #define GUA_PCF8563_REG_YEARS 0x08 //年份 00~99 //闹钟寄存器 #define GUA_PCF8563_REG_MINUTE_ALARM 0x09 //闹钟,分钟 minute alarm 00 to 59 coded in BCD #define GUA_PCF8563_REG_HOUR_ALARM 0x0A //闹钟,小时 hour alarm 00 to 23 coded in BCD #define GUA_PCF8563_REG_DAY_ALARM 0x0B //闹钟,日 day alarm 01 to 31 coded in BCD #define GUA_PCF8563_REG_WEEKDAY_ALARM 0x0C //闹钟,星期 weekday alarm 0 to 6 in BCD #define GUA_PCF8563_REG_CLKOUT_CONTROL 0x0D //时钟输出设置 #define GUA_PCF8563_REG_TIMER_CONTROL 0x0E //定时器设置 #define GUA_PCF8563_REG_TIMER 0x0F //定时器倒计数值
/*********************变量************************/ GUA_PCF8563_TIME stGUA_Pcf8563_BCDTime = {0}; //寄存器读出来的BCD时间 GUA_PCF8563_TIME stGUA_Pcf8563_AlarmBCDTime = {0}; //报警时间 /*********************内部函数************************/ static bool GUA_PCF8563_WriteOneByte(uint8_t addr, uint8_t data); static uint8_t GUA_Pcf8563_GetWeek(uint16_t year, uint8_t month, uint8_t day); static bool GUA_Pcf8563_IsLeapYear(uint16_t year); //********************************************************************** //name: GUA_PCF8563_WriteOneByte //introduce: 写1个字节寄存器 //parameter: addr:寄存器地址 // data:要写入寄存器的数值 //return: false:0错误;true:1正常 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** static bool GUA_PCF8563_WriteOneByte(uint8_t addr, uint8_t data) { return GUA_IIC_SendBytes(addr, 1, &data, GUA_PCF8563_ADDR); } //********************************************************************** //name: GUA_Pcf8563_GetWeek //introduce: 通过Zeller's Congruence算法,将年月日计算出星期几 //parameter: year:年 // month:月 // day:日 //return: 星期数(0:周日 1:周一 …… 6:周六) //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** static uint8_t GUA_Pcf8563_GetWeek(uint16_t year, uint8_t month, uint8_t day) { if(month < 3) { month += 12; year -= 1; }
int8_t century = year/100; int8_t year_of_century = year%100; int8_t week_day = century/4 + year_of_century + year_of_century/4 + 13*(month+1)/5 + day - 2*century - 1; week_day = week_day > 0 ? (week_day % 7):((week_day % 7) + 7);
return week_day; } //********************************************************************** //name: GUA_Pcf8563_IsLeapYear //introduce: 判断输入的年份是不是闰年 //parameter: year要判断的年份 //return: true:是闰年;false:不是闰年 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** static bool GUA_Pcf8563_IsLeapYear(uint16_t year) { //闰年条件:1.能被4整除但不能被100整除;2.能被400整除 if(((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) return true; else return false; } //********************************************************************** //name: GUA_Pcf8563_DaysOfCurrentMonth //introduce: 计算当月的天数 //parameter: month:月份,year:年份 //return: 返回该月份的天数 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** static uint8_t GUA_Pcf8563_DaysOfCurrentMonth(uint8_t month, uint16_t year) { //每个月的天数 uint8_t days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//2月要根据闰年计算 if(month == 2) return days[1] + GUA_Pcf8563_IsLeapYear(year); //其他月份正常返回 return days[month - 1]; } //********************************************************************** //name: GUA_Pcf8563_SetAlarmTime //introduce: 设置报警时间 //parameter: minutes:分,hours:时,days:日 //return: false:0错误;true:1正常 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** bool GUA_Pcf8563_SetAlarmTime(uint8_t minutes, uint8_t hours, uint8_t days) { uint8_t data[4];
//调整有效数据 data[0] = minutes & 0x7F; data[1] = hours & 0x3F; data[2] = days & 0x3F; data[3] = 0x80;//weekdays & 0x07;
//写入分、时、天、周 return GUA_IIC_SendBytes(GUA_PCF8563_REG_MINUTE_ALARM, 4, data, GUA_PCF8563_ADDR); } //********************************************************************** //name: GUA_Pcf8563_EnableAlarm //introduce: 开或关报警 //parameter: enable:true开 false关 //return: false:0错误;true:1正常 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** bool GUA_Pcf8563_EnableAlarm(bool enable) { uint8_t status;
//读寄存器 if(GUA_IIC_ReadBytes(GUA_PCF8563_REG_CONTROL_STATUS_2, 1, &status, GUA_PCF8563_ADDR) == false) return false;
//设置或清除报警使能位(bit 1: AIE) if(enable == true) status |= (1 << 1); //开启报警 else status &= ~(1 << 1); //关闭报警
//写寄存器 return GUA_IIC_SendBytes(GUA_PCF8563_REG_CONTROL_STATUS_2, 1, &status, GUA_PCF8563_ADDR); } //********************************************************************** //name: GUA_Pcf8563_GetAlarmFlag //introduce: 获取报警中断标志位AF //parameter: none //return: false:0无报警;true:1报警发生了 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** bool GUA_Pcf8563_GetAlarmFlag(void) { uint8_t status;
//读寄存器 GUA_IIC_ReadBytes(GUA_PCF8563_REG_CONTROL_STATUS_2, 1, &status, GUA_PCF8563_ADDR); //检查AF标志位(第3位) if(status & (1 << 3)) return true; // 报警发生 else return false; // 无报警 } //********************************************************************** //name: GUA_Pcf8563_ClearAlarmFlag //introduce: 清除报警中断标志位AF //parameter: none //return: false:0错误;true:1正常 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** bool GUA_Pcf8563_ClearAlarmFlag(void) { uint8_t status;
//读寄存器 if(GUA_IIC_ReadBytes(GUA_PCF8563_REG_CONTROL_STATUS_2, 1, &status, GUA_PCF8563_ADDR) == false) return false; //清除AF位(bit 3) status &= ~(1 << 3);
//写寄存器 return GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_CONTROL_STATUS_2, status); } //********************************************************************** //name: GUA_Pcf8563_DisableAlarm //introduce: 关闭报警功能 //parameter: none //return: false:0错误;true:1正常 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** bool GUA_Pcf8563_DisableAlarm(void) { uint8_t status; //读寄存器 if(GUA_IIC_ReadBytes(GUA_PCF8563_REG_CONTROL_STATUS_2, 1, &status, GUA_PCF8563_ADDR) == false) return false;
//禁用报警中断(清除AIE位) status &= ~(1 << 1); //写寄存器 return GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_CONTROL_STATUS_2, status); } //********************************************************************** //name: GUA_Pcf8563_GPIOInit //introduce: 初始化 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** static void GUA_Pcf8563_GPIOInit(void) { GPIO_InitTypeDef GPIO_InitStructure; //p02 上拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIO0, &GPIO_InitStructure);
//清除标志、开中断 GPIO_ClearITPendingBit(GPIO0, GPIO_Pin_2); NVIC_EnableIRQ(GPIO_IRQn); GPIO_ITConfig(GPIO0, GPIO_Pin_2, GPIO_IT_EDGE_FALLING, ENABLE); } //********************************************************************** //name: GUA_Pcf8563_SetTime //introduce: 修改时间 //parameter: none //return: false:0错误;true:1正常 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** bool GUA_Pcf8563_SetTime(void) { //获取有效位 stGUA_Pcf8563_BCDTime.seconds &= 0x7F; //seconds: [0-59] 确保VL标志位为0 stGUA_Pcf8563_BCDTime.minutes &= 0x7F; //minutes: [0-59] stGUA_Pcf8563_BCDTime.hours &= 0x3F; //hours: [0-23] stGUA_Pcf8563_BCDTime.days &= 0x3F; //days: [1-31] stGUA_Pcf8563_BCDTime.weeks &= 0x07; //weeks: [1-7] stGUA_Pcf8563_BCDTime.months &= 0x1F; //months: [1-12] stGUA_Pcf8563_BCDTime.years &= 0xFF; //years //写入 return GUA_IIC_SendBytes(GUA_PCF8563_REG_VL_SECONDS, 7, &stGUA_Pcf8563_BCDTime.seconds, GUA_PCF8563_ADDR); } //********************************************************************** //name: GUA_Pcf8563_ReadTime //introduce: 读取rtc时间 //parameter: none //return: false:0错误;true:1正常 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** bool GUA_Pcf8563_ReadTime(void) { //读出寄存器数据 if(GUA_IIC_ReadBytes(GUA_PCF8563_REG_VL_SECONDS, 7, &stGUA_Pcf8563_BCDTime.seconds, GUA_PCF8563_ADDR) == false) return false;
//获取有效位 stGUA_Pcf8563_BCDTime.seconds &= 0x7F; //seconds: [0-59] 确保VL标志位为0 stGUA_Pcf8563_BCDTime.minutes &= 0x7F; //minutes: [0-59] stGUA_Pcf8563_BCDTime.hours &= 0x3F; //hours: [0-23] stGUA_Pcf8563_BCDTime.days &= 0x3F; //days: [1-31] stGUA_Pcf8563_BCDTime.weeks &= 0x07; //weeks: [1-7] stGUA_Pcf8563_BCDTime.months &= 0x1F; //months: [1-12] stGUA_Pcf8563_BCDTime.years &= 0xFF; //years
return true; } //********************************************************************** //name: GUA_Pcf8563_Init //introduce: 初始化 //parameter: none //return: none //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** void GUA_Pcf8563_Init(void) { uint8_t reg;
//初始化int引脚 GUA_Pcf8563_GPIOInit();
//读出VL if(GUA_IIC_ReadBytes(GUA_PCF8563_REG_VL_SECONDS, 1, ®, GUA_PCF8563_ADDR) == true) { //如果VL为高说明掉电过、数据不可靠,要重写 if((reg&0x80) == 0x80) { //清零 memset(&stGUA_Pcf8563_BCDTime, 0, sizeof(stGUA_Pcf8563_BCDTime)); memset(&stGUA_Pcf8563_AlarmBCDTime, 0, sizeof(stGUA_Pcf8563_AlarmBCDTime));
//配置寄存器 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_CONTROL_STATUS_1, 0x00); //启动PCF8563 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_CONTROL_STATUS_2, 0x00); //清中断标志和禁止中断 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_CLKOUT_CONTROL, 0x00); //CLKOUT禁止 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_TIMER_CONTROL, 0x00); //定时器禁止 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_MINUTE_ALARM, 0x80); //分钟报警配置 每小时报警一次 0x80是暂停 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_HOUR_ALARM, 0x80); //小时报警配置 每天报警一次 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_DAY_ALARM, 0x80); //日报警配置 每月报警一次 GUA_PCF8563_WriteOneByte(GUA_PCF8563_REG_WEEKDAY_ALARM, 0x80); //星期报警配置 每周报警一次 } } } |
2)编写驱动GUA_Pcf8563.h(存放在“……\Projects\MT006_StdPeriph_Templates\GUA”)
//********************************************************************** //name: GUA_Pcf8563.h //introduce: Pcf8563驱动的头文件 //author: opengua //email: 897503845@qq.com //QQ group: 香瓜单片机之STM8/STM32(164311667) //shop: opengua.taobao.com //changetime: 2024.12.11 //********************************************************************** #ifndef _GUA_PCF8563_H_ #define _GUA_PCF8563_H_ /*********************头文件************************/ #include "stdbool.h" #include "stdint.h" /*********************变量************************/ //时间结构体 typedef struct { uint8_t seconds; // 秒 uint8_t minutes; // 分钟 uint8_t hours; // 小时 uint8_t days; // 日 uint8_t weeks; // 星期 uint8_t months; // 月/世纪 uint8_t years; // 年 }GUA_PCF8563_TIME; extern GUA_PCF8563_TIME stGUA_Pcf8563_BCDTime; //寄存器读出来的BCD时间 extern GUA_PCF8563_TIME stGUA_Pcf8563_AlarmBCDTime; //报警时间 /*********************外部函数************************/ extern bool GUA_Pcf8563_SetTime(void); extern bool GUA_Pcf8563_SetAlarmTime(uint8_t minutes, uint8_t hours, uint8_t days); extern bool GUA_Pcf8563_EnableAlarm(bool enable); extern bool GUA_Pcf8563_GetAlarmFlag(void); extern bool GUA_Pcf8563_ClearAlarmFlag(void); extern bool GUA_Pcf8563_DisableAlarm(void); extern bool GUA_Pcf8563_ReadTime(void); extern void GUA_Pcf8563_Init(void); #endif |
3)工程中添加驱动文件
4)在MDK设置中添加驱动源文件路径
2、添加库的驱动
1)添加库的驱动文件(为了方便一次性都添加进来,已有则不用添加)
2)添加库的驱动头文件(mt006_conf.h 中)(为了方便一次性都添加进来,已有则不用添加)
3、在应用层中调用
1)添加驱动头文件(main.c中)
#include “GUA_Pcf8563.h” |
2)添加驱动初始化代码(main.c的main函数中)
//rtc初始化 GUA_Pcf8563_Init(); |
3)举例添加中断处理代码(mt006_it.c的GPIO_IRQHandler函数中)
//RTC的报警中断唤醒 if(GPIO_GetITStatus(GPIO0, GPIO_Pin_2) != RESET) { // 清除已处理的中断标志位 GPIO_ClearITPendingBit(GPIO0, GPIO_Pin_2); //处理RTC事件 gnGUA_Function = FUNC_GUA_PCF8563_ALARM_EVENT; } |
4)举例添加闹钟处理代码(main.c的main函数中)
//rtc报警处理事件 需判断 case FUNC_GUA_PCF8563_ALARM_EVENT: { //清除报警标志位AF(只清除AF,但不关闭中断,下次还会进来,一直到当前时间完全对上报警时间) GUA_Pcf8563_ClearAlarmFlag();
//运行模式 gnGUA_Function = FUNC_GUA_ACTIVE_EVENT;
//读出rtc最新的时间 GUA_Pcf8563_ReadTime();
//报警功能只能一个月内的,判断是否到实际要报警的时间 if((stGUA_Pcf8563_AlarmBCDTime.years == stGUA_Pcf8563_BCDTime.years) && (stGUA_Pcf8563_AlarmBCDTime.months == stGUA_Pcf8563_BCDTime.months) && (stGUA_Pcf8563_AlarmBCDTime.days == stGUA_Pcf8563_BCDTime.days) && (stGUA_Pcf8563_AlarmBCDTime.hours == stGUA_Pcf8563_BCDTime.hours) && (stGUA_Pcf8563_AlarmBCDTime.minutes == stGUA_Pcf8563_BCDTime.minutes)) { //关闭报警中断 GUA_Pcf8563_EnableAlarm(false);
//清闹钟 memset(&stGUA_Pcf8563_AlarmBCDTime, 0, sizeof(stGUA_Pcf8563_AlarmBCDTime));
//如果usb输出口有设备,要发指令判断树莓派是否在线(发、收一次指令则表示在线) if(GUA_HUSB363_CHECK_USBC == GUA_HUSB363_DEVICE_ON) { //开始计时等待树莓派应答 gnGUA_WaitingPiCommand = GUA_PI_COMMAND_WAITING; //先按不在线来打标记 gnGUA_CheckPiOnline = GUA_PI_OFFLINE;
uint8_t nGUA_Func = 0x08; //功能码 uint8_t nGUA_Len = 0x00; //有效数据的长度
//数据发送 GUA_Communication_DataPackage_Send(nGUA_Func, 0, nGUA_Len); } } break; } |
根据代码增删减改,有香瓜项目中的代码,否则会报错
八、注意事项
暂无
九、实验结果
暂无