【MT32F006】MT32F006之pcf8563(IIC通信)

发布于:2025-02-10 ⋅ 阅读:(45) ⋅ 点赞:(0)

本文最后修改时间: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》的《MT32F006IIC》。

五、基础知识

1pcf8563是什么?如何使用?

答: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, &reg, 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;

           }  

根据代码增删减改,有香瓜项目中的代码,否则会报错

八、注意事项

暂无

九、实验结果

暂无