- /*
- * calendar.c
- *
- * Created: 2018/3/30 9:08:12
- * Author: blust
- */
- #include "calendar.h"
- PCF8563_Time_Buff real_time_buff;
- PCF8563_Time_Buff pcf8563_time_buff;
- /*
- main函数初始化时调用如下函数即可,其余函数在该使用时调用即可。
- iic_pin_Init();
- pcf8563_init();
- pcf8563_clear_alarm_flag();
- */
- //引脚初始化程序需按照对应单片机和硬件引脚连接做响应调整
- void iic_pin_Init(void)
- {
- struct port_config pin_conf;
- port_get_config_defaults(&pin_conf);
-
- pin_conf.direction = PORT_PIN_DIR_OUTPUT;
- port_pin_set_config(SCL_PIN, &pin_conf);
- port_pin_set_output_level(SCL_PIN, true); // 时钟信号SCL配置为输出口
- pin_conf.input_pull =PORT_PIN_PULL_UP;
- pin_conf.direction = PORT_PIN_DIR_OUTPUT_WTH_READBACK;
- port_pin_set_config(SDA_PIN, &pin_conf);
- port_pin_set_output_level(SDA_PIN, true); // 数据信号SDA配置为双向口
- }
- /****************************************************************************
- FUNCTION : iic_start
- DESCRIPTION : IIC通讯起始位(专用函数)
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void iic_start(void)
- { //时钟保持高,数据线从高到低一次跳变,I2C通信开始
- SDA_PIN_High();
- SCL_PIN_High();
- delay_us(5); // 延时5us
- SDA_PIN_Low();
- delay_us(5);
- SCL_PIN_Low();
- }
- /****************************************************************************
- FUNCTION : iic_stop
- DESCRIPTION : IIC通讯停止位(专用函数)
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void iic_stop(void)
- {
- SDA_PIN_Low(); //时钟保持高,数据线从低到高一次跳变,I2C通信停止
- SCL_PIN_High();
- delay_us(5);
- SDA_PIN_High();
- delay_us(5);
- SCL_PIN_Low();
- }
- /****************************************************************************
- FUNCTION : slave_ACK
- DESCRIPTION : 从机发送应答位子程序(专用函数)
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void slave_ACK(void)
- {
- SDA_PIN_Low();
- SCL_PIN_High();
- delay_us(5);
- SCL_PIN_Low();
- SDA_PIN_High();
- }
- /****************************************************************************
- FUNCTION : slave_NOACK
- DESCRIPTION : 从机发送非应答位子程序,迫使数据传输过程结束(专用函数)
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void slave_NOACK(void)
- {
- SDA_PIN_High();
- SCL_PIN_High();
- delay_us(5);
- SDA_PIN_Low();
- SCL_PIN_Low();
- }
- /****************************************************************************
- FUNCTION : check_ACK
- DESCRIPTION : 主机应答位检查子程序,迫使数据传输过程结束(专用函数)
- INPUT : None
- OUTPUT : 非应答标志位
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- bool check_ACK(void)
- {
- bool err = false;
- uint8_t i = 100;
- //SDA_PIN_High(); // 将SDA设置成输入,必须先向端口写1
- SCL_PIN_High();
- err = false;
- while(i--)
- {
- if(SDA_Read()==0) // 若SDA=0表明有应答
- {
- break;
- }
- }
- if(SDA_Read() == 1) // 若SDA=1表明非应答,置位非应答标志
- err = true;
- SCL_PIN_Low();
-
- return err;
- }
- /****************************************************************************
- FUNCTION : iic_send_byte
- DESCRIPTION : 发送一个字节(专用函数)
- INPUT : para
- OUTPUT :
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void iic_send_byte(uint8_t para)
- {
- uint8_t n=8; // 向SDA上发送一位数据字节,共八位
- while(n--)
- {
- if((para&0x80) == 0x80) // 若要发送的数据最高位为1则发送位1
- {
- SDA_PIN_High(); // 传送位1
- SCL_PIN_High();
- delay_us(5);
- SCL_PIN_Low();
- delay_us(1);
- }
- else
- {
- SDA_PIN_Low(); // 否则传送位0
- SCL_PIN_High();
- delay_us(5);
- SCL_PIN_Low();
- delay_us(1);
- }
- para = para << 1; // 数据左移一位
- }
- }
- /****************************************************************************
- FUNCTION : iic_receive_byte
- DESCRIPTION : 接收一字节子程序(专用函数)
- INPUT : None
- OUTPUT : 接收到的数据
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- uint8_t iic_receive_byte(void)
- {
- uint8_t i; // 从SDA线上读取一上数据字节,共八位
- uint8_t rdata = 0;
- //SDA_PIN_High();
- for(i=0;i<8;i++)
- {
- delay_us(5);
- SCL_PIN_High();
- rdata = rdata<<1; // 左移一位,或_crol_(temp,1)
- delay_us(5);
- if(SDA_Read() == 1)
- rdata |= 0x01; // 若接收到的位为1,则数据的最后一位置1
- else
- rdata &= 0xfe; // 否则数据的最后一位置0
- SCL_PIN_Low();
- }
- return rdata;
- }
- /****************************************************************************
- FUNCTION : write_CFGbyte
- DESCRIPTION : 写PCF8563寄存器配置(专用函数)
- INPUT : CFG_add寄存器地址,CFG_data要写入寄存器的数值
- OUTPUT : 成功返回0 失败返回1
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- uint8_t write_CFGbyte(uint8_t CFG_add, uint8_t CFG_data)
- {
- iic_start(); // 启动I2C
- iic_send_byte(PCF8563_WRITE_ADDR); // 发送器件写地址
- if(check_ACK() == 1) // 检查应答位
- {
- iic_stop();
- return 1; // 若非应答表明器件错误或已坏,置错误标志位SystemError
- }
- iic_send_byte(CFG_add); // 发送寄存器地址
- if(check_ACK() == 1) // 检查应答位
- {
- iic_stop();
- return 1; // 若非应答表明器件错误或已坏,置错误标志位SystemError
- }
- iic_send_byte(CFG_data); // 发送寄存器数据
- if(check_ACK() == 1) // 检查应答位
- {
- iic_stop();
- return 1; // 若非应答表明器件错误或已坏,置错误标志位SystemError
- }
- iic_stop(); // 全部发完则停止
- return 0;
- }
- /****************************************************************************
- FUNCTION : receive_CFGbyte
- DESCRIPTION : 读取某个寄存器数据(专用函数)
- INPUT : CFG_add寄存器地址,* CFG_data读取到的寄存器值存放位置
- OUTPUT : 成功返回0 失败返回1
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- uint8_t receive_CFGbyte(uint8_t CFG_add, uint8_t * CFG_data)
- {
- uint8_t receive_da;
- iic_start();
- iic_send_byte(PCF8563_WRITE_ADDR); //器件写地址
- if(check_ACK() == 1)
- {
- iic_stop();
- return 1;
- }
- iic_send_byte(CFG_add); //寄存器地址
- if(check_ACK() == 1)
- {
- iic_stop();
- return 1;
- }
- iic_start();
- iic_send_byte(PCF8563_READ_ADDR); //器件读地址
- if(check_ACK() == 1)
- {
- iic_stop();
- return 1;
- }
- receive_da=iic_receive_byte();
- slave_NOACK(); // 收到最后一个字节后发送一个非应答位
- iic_stop();
- *CFG_data = receive_da;
- return 0;
- }
- /****************************************************************************
- FUNCTION : receive_CFGNbyte
- DESCRIPTION : 读取n个寄存器数据(专用函数)
- INPUT : CFG_add寄存器地址地址,n连续读数位,* buff存储区地址
- OUTPUT : 成功返回0 失败返回1
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- uint8_t receive_CFGNbyte(uint8_t CFG_add, uint8_t n, uint8_t * buff)
- {
- uint8_t i=0;
- iic_start();
- iic_send_byte(PCF8563_WRITE_ADDR); //器件写地址
- if(check_ACK() == 1)
- {
- iic_stop();
- return 1;
- }
- //check_ACK();
- iic_send_byte(CFG_add); //寄存器地址
- if(check_ACK() == 1)
- {
- iic_stop();
- return 1;
- }
- //check_ACK();
- iic_start();
- iic_send_byte(PCF8563_READ_ADDR); //器件读地址
- if(check_ACK() == 1)
- {
- iic_stop();
- return 1;
- }
- //check_ACK();
- for(i=0;i<n;i++)
- {
- buff[i]=iic_receive_byte();
- if(i < n-1)
- slave_ACK(); // 收到一个字节后发送一个应答位
- }
- slave_NOACK(); // 收到最后一个字节后发送一个非应答位
- iic_stop();
- return 0;
- }
- /****************************************************************************
- FUNCTION : reset_pcf8563_time
- DESCRIPTION : 复位时钟时间值,用以初次配置时钟
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void reset_pcf8563_time(void)
- {
- pcf8563_time_buff.val.seconds = 0x00;
- pcf8563_time_buff.val.minutes = 0x00;
- pcf8563_time_buff.val.hours = 0x00;
- pcf8563_time_buff.val.days = 0x30;
- pcf8563_time_buff.val.weeks = 0x05;
- pcf8563_time_buff.val.months = 0x03;
- pcf8563_time_buff.val.years = 0x18;
- }
- /****************************************************************************
- FUNCTION : pcf8563_read_time
- DESCRIPTION : 读出时间信息
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void pcf8563_read_time(void)
- {
- receive_CFGNbyte(PCF8563_TIME_ADD,7,pcf8563_time_buff.data);
-
- pcf8563_time_buff.val.seconds &= 0x7F;
- pcf8563_time_buff.val.minutes &= 0x7F;
- pcf8563_time_buff.val.hours &= 0x3F;
- pcf8563_time_buff.val.days &= 0x3F;
- pcf8563_time_buff.val.weeks &= 0x07;
- pcf8563_time_buff.val.months &= 0x1F;
- pcf8563_time_buff.val.years &= 0xFF;
- }
- /****************************************************************************
- FUNCTION : pcf8563_set_time
- DESCRIPTION : 写时间修改值
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void pcf8563_set_time(void)
- {
- uint8_t i;
- for(i=0;i<7;i++)
- {
- write_CFGbyte(PCF8563_TIME_ADD+i,pcf8563_time_buff.data[i]);
- }
- }
- /****************************************************************************
- FUNCTION : pcf8563_alarm_set
- DESCRIPTION : 设置报警时间
- INPUT : min_alarm报警分,hour_alarm报警时,day_alarm报警日,week_alarm报警周
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void pcf8563_alarm_set(uint8_t min_alarm, uint8_t hour_alarm, uint8_t day_alarm, uint8_t week_alarm)
- {
- write_CFGbyte(PCF8563_MIN_ALARM_ADD,min_alarm); // 分钟报警配置 每小时报警一次
- write_CFGbyte(PCF8563_HOUR_ALARM_ADD,hour_alarm); // 小时报警配置 每天报警一次
- write_CFGbyte(PCF8563_DAY_ALARM_ADD,day_alarm); // 日报警配置 每月报警一次
- write_CFGbyte(PCF8563_WEEK_ALARM_ADD,week_alarm); // 星期报警配置 每周报警一次
- }
- /****************************************************************************
- FUNCTION : pcf8563_clear_alarm_flag
- DESCRIPTION : 清除报警时间
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/04/02
- *****************************************************************************/
- void pcf8563_clear_alarm_flag(void)
- {
- write_CFGbyte(PCF8563_CTRL2_ADD,0x12); // 清除报警标志位
- }
- /****************************************************************************
- FUNCTION : pcf8563_init
- DESCRIPTION : PCF8563初始化
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void pcf8563_init(void)
- {
- uint8_t temp;
- if(receive_CFGbyte(PCF8563_TIME_ADD, &temp)==0)
- {
- if((temp&0x80) == 0x80) /*检查是否第一次启动,是则初始化时间*/
- {
- reset_pcf8563_time();
- pcf8563_set_time();
- write_CFGbyte(PCF8563_CTRL1_ADD,0x00); // 启动PCF8563
- write_CFGbyte(PCF8563_CTRL2_ADD,0x12); // 报警允许中断输出
- write_CFGbyte(PCF8563_CLKOUT_ADD,0x00); // CLKOUT输出禁止
- write_CFGbyte(PCF8563_TIMER_CTRL_ADD,0x00); // 定时器禁止
- write_CFGbyte(PCF8563_MIN_ALARM_ADD,0x80); // 分钟报警配置 每小时报警一次
- write_CFGbyte(PCF8563_HOUR_ALARM_ADD,0x80); // 小时报警配置 每天报警一次
- write_CFGbyte(PCF8563_DAY_ALARM_ADD,0x80); // 日报警配置 每月报警一次
- write_CFGbyte(PCF8563_WEEK_ALARM_ADD,0x80); // 星期报警配置 每周报警一次
- }
- }
- }
- /****************************************************************************
- FUNCTION : ymd_to_week
- DESCRIPTION : 通过年月日计算出当天的星期数(专用函数)
- INPUT : year:年份,month:月份,day:日期
- OUTPUT : 星期数(0:周日 1:周一 …… 6:周六)
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- uint8_t ymd_to_week(uint16_t year,uint8_t month,uint8_t day)
- {
- int8_t week;
- int8_t c, y;
- if (month <= 2)
- {
- month += 12;
- year -= 1;
- }
- c = year/100;
- y = year%100;
- week = c/4 + y + y/4 + 13*(month+1)/5 + day - 2*c - 1;
- week = week > 0 ? (week % 7):((week % 7) + 7);
-
- return week;
- }
- /****************************************************************************
- FUNCTION : time_to_real
- DESCRIPTION : 将PCF8563读取的寄存器值转换为实时时间
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void time_to_real(void)
- {
- real_time_buff.val.seconds = ((pcf8563_time_buff.val.seconds)/16)*10 + pcf8563_time_buff.val.seconds % 16;
- real_time_buff.val.minutes = ((pcf8563_time_buff.val.minutes)/16)*10 + pcf8563_time_buff.val.minutes % 16;
- real_time_buff.val.hours = ((pcf8563_time_buff.val.hours)/16)*10 + pcf8563_time_buff.val.hours % 16;
- real_time_buff.val.days = ((pcf8563_time_buff.val.days)/16)*10 + pcf8563_time_buff.val.days % 16;
- real_time_buff.val.months = ((pcf8563_time_buff.val.months)/16)*10 + pcf8563_time_buff.val.months % 16;
- real_time_buff.val.years = ((pcf8563_time_buff.val.years)/16)*10 + pcf8563_time_buff.val.years % 16;
-
- real_time_buff.val.weeks = ymd_to_week(real_time_buff.val.years+2000,real_time_buff.val.months,real_time_buff.val.days);
- }
- /****************************************************************************
- FUNCTION : time_to_pcf8563
- DESCRIPTION : 将实时时间转换为PCF8563读取的寄存器值
- INPUT : None
- OUTPUT : None
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void time_to_pcf8563(void)
- {
- real_time_buff.val.weeks = ymd_to_week(real_time_buff.val.years+2000,real_time_buff.val.months,real_time_buff.val.days);
-
- pcf8563_time_buff.val.seconds = (real_time_buff.val.seconds/10)*16 + real_time_buff.val.seconds%10;
- pcf8563_time_buff.val.minutes = (real_time_buff.val.minutes/10)*16 + real_time_buff.val.minutes%10;
- pcf8563_time_buff.val.hours = (real_time_buff.val.hours/10)*16 + real_time_buff.val.hours%10;
- pcf8563_time_buff.val.days = (real_time_buff.val.days/10)*16 + real_time_buff.val.days%10;
- pcf8563_time_buff.val.months = (real_time_buff.val.months/10)*16 + real_time_buff.val.months%10;
- pcf8563_time_buff.val.years = (real_time_buff.val.years/10)*16 + real_time_buff.val.years%10;
- pcf8563_time_buff.val.weeks = real_time_buff.val.weeks;
- }
- /****************************************************************************
- FUNCTION : leap_year
- DESCRIPTION : 判断是否是闰年(专用函数)
- INPUT : year:需要判断的年份数
- OUTPUT : 闰年返回1,否则返回0
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- uint8_t leap_year(uint16_t year)
- {
- if ((year % 400) == 0)
- {
- return 1;
- }
- else if ((year % 100) == 0)
- {
- return 0;
- }
- else if ((year % 4) == 0)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- /*
- * 功能:
- * 得到每个月有多少天
- * 参数:
- * month:需要得到天数的月份数
- * year:该月所对应的年份数
- *
- * 返回值:
- * 该月有多少天
- *
- */
- /****************************************************************************
- FUNCTION : days_of_month
- DESCRIPTION : 计算每月的天数(专用函数)
- INPUT : month:月份,year:年份
- OUTPUT : 返回该月份的天数
- UPDATE :
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- uint8_t days_of_month(uint8_t month, uint16_t year)
- {
- const uint8_t day_per_month[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- if ((month == 0) || (month > 12))
- {
- return day_per_month[1] + leap_year(year);
- }
- if (month != 2)
- {
- return day_per_month[month - 1];
- }
- else
- {
- return day_per_month[1] + leap_year(year);
- }
- }
- /****************************************************************************
- FUNCTION : ymd_to_week
- DESCRIPTION : UNIX时间戳转换为实时时间(只适用于20xx年)
- INPUT : UNIX时间戳
- OUTPUT : 无(转换结果存储在 real_time_buff )
- UPDATE : 如果需要扩大年份包含范围,需要将年份定义为U16,并将 “real_time_buff.val.years = y % 100”的“% 100”删掉
- AUTHOR : blust
- DATE : 2018/03/30
- *****************************************************************************/
- void unix_to_realtime(uint32_t utc_sec)
- {
- uint32_t temp;
- uint16_t y, d;
- uint8_t m;
- utc_sec += SEC_PER_HOUR*8; // 时区调整
- /* 小时 */
- temp = utc_sec % SEC_PER_DAY;
- real_time_buff.val.hours = temp / SEC_PER_HOUR;
- /* 分钟 */
- temp %= SEC_PER_HOUR;
- real_time_buff.val.minutes = temp / SEC_PER_MIN;
- /* 秒 */
- real_time_buff.val.seconds = temp % SEC_PER_MIN;
-
- /* 年 */
- temp = utc_sec / SEC_PER_DAY;
- for (y = UTC_BASE_YEAR; temp > 0; y++)
- {
- d = (DAY_PER_YEAR + leap_year(y));
- if (temp >= d)
- {
- temp -= d;
- }
- else
- {
- break;
- }
- }
- real_time_buff.val.years = y % 100;
- /* 月 */
- for (m = 1; m < MONTH_PER_YEAR; m++)
- {
- d = days_of_month(m, y);
- if (temp >= d)
- {
- temp -= d;
- }
- else
- {
- break;
- }
- }
- real_time_buff.val.months = m;
- /* 日 */
- real_time_buff.val.days = (uint8_t)(temp + 1);
- real_time_buff.val.weeks = ymd_to_week(y, m, real_time_buff.val.days);
- }