#include "MAIN.H" #include #include "RTC.H" unsigned char bySta = 0; // 静态月份天数表(平年,索引1~12对应1月~12月) ubyte days_in_month[12] = { 31, // 1月 28, // 2月(平年) 31, // 3月 30, // 4月 31, // 5月 30, // 6月 31, // 7月 31, // 8月 30, // 9月 31, // 10月 30, // 11月 31 // 12月 }; void SDAOut(bit c) { SFR_PAGE(_pp0, noSST); // switch to page 0 P0_DIR = P0_DIR | 0x08;//修改P0.3为输出 P0_3 = c; } void SCLOut(bit c) { P0_2 = c; } void iic_start(void) { SDAOut(1); _nop_(); SCLOut(1); somenop; SDAOut(0); somenop; SCLOut(0); } void iic_stop(void) { SDAOut(0); _nop_(); SCLOut(1); somenop; SDAOut(1); } void iic_ack(bit ackbit) { if(ackbit) SDAOut(0); else SDAOut(1); somenop; SCLOut(1); somenop; SCLOut(0); SDAOut(1); somenop; } bit iic_waitack(void) { SDAOut(1); somenop; SCLOut(1); SFR_PAGE(_pp0, noSST); // switch to page 0 P0_DIR = P0_DIR & 0xF7;//修改P4.3为输入 somenop; if(P0_3) { SCLOut(0); iic_stop(); return 0; } else { SCLOut(0); return 1; } } void iic_sendbyte(unsigned char byt) { unsigned char i; for(i=0;i<8;i++) { if(byt&0x80) SDAOut(1); else SDAOut(0); somenop; SCLOut(1); byt <<= 1; somenop; SCLOut(0); } } unsigned char iic_recbyte(void) { unsigned char da; unsigned char i; SFR_PAGE(_pp0, noSST); // switch to page 0 P0_DIR = P0_DIR & 0xF7;//修改P4.3为输入 for(i=0;i<8;i++) { SCLOut(1); somenop; da <<= 1; // P1_IOCR01 = 0x0020; // load port control register 1 if(P0_3) da |= 0x01; SCLOut(0); somenop; } return da; } // 十进制转 BCD 码 unsigned char DecToBcd(unsigned char dec) { return ((dec / 10) << 4) | (dec % 10); } // BCD 码转十进制 unsigned char BcdToDec(unsigned char bcd) { return ((bcd >> 4) * 10) + (bcd & 0x0F); } // BM8563 写寄存器函数 void BM8563_WriteReg(unsigned char reg, unsigned char rdata) { iic_start(); iic_sendbyte(BM8563_ADDR); // 发送 BM8563 的 I2C 地址,写操作 iic_waitack(); iic_sendbyte(reg); // 发送寄存器地址 iic_waitack(); iic_sendbyte(rdata); // 发送数据 iic_waitack(); iic_stop(); } // BM8563 读寄存器函数 unsigned char BM8563_ReadReg(unsigned char reg) { unsigned char rdata; iic_start(); iic_sendbyte(BM8563_ADDR); // 发送 BM8563 的 I2C 地址,写操作 iic_waitack(); iic_sendbyte(reg); // 发送寄存器地址 iic_waitack(); iic_start(); iic_sendbyte(BM8563_ADDR | 0x01); // 发送 BM8563 的 I2C 地址,读操作 iic_waitack(); rdata = iic_recbyte(); iic_ack(0); iic_stop(); return rdata; } // 判断闰年 ubyte leapYear(uword year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; } /** * @brief 获取指定年份和月份的天数(自动处理闰年) * @param year: 年份(四位数,如2024) * @param month: 月份(1-12) * @retval 该月天数(若参数非法返回0) */ ubyte getMonthDays(uword year, ubyte month) { // 静态月份天数表(平年,索引1~12对应1月~12月) ubyte days_in_month[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // 参数校验 if (month < 1 || month > 12) return 0; // 处理闰年2月 if (month == 2 && leapYear(year)) { return 29; } // 返回常规天数 return days_in_month[month]; } /** * @brief 检查报警标志AF是否置位(Bit3) * @retval true-报警已触发,false-无报警 */ bool bm8563CheckAlarmFlag(void) { ubyte reg_val = BM8563_ReadReg(BM8563_CSR2); return (reg_val & BM8563_AF_BIT) != 0; // 检查Bit3 } /** * @brief 清除报警标志AF(Bit3) * @note 保留其他位(如Bit1 AIE标志)状态 */ void bm8563ClearAlarmFlag(void) { ubyte reg_val = BM8563_ReadReg(BM8563_CSR2); reg_val &= ~BM8563_AF_BIT; // 仅清除Bit3 BM8563_WriteReg(BM8563_CSR2, reg_val); } /** * @brief 设置BM8563当前时间(整合世纪位到月份寄存器) * @param pTime: 时间结构体指针(年份需为完整四位数,如1984、2024) * @retval 无 */ void bm8563SetTime(UnTimeOutput *pTime) { ubyte century_bit = 0; // 完整四位数年份 ubyte reg_sec = 0; ubyte month_bcd = 0; if (pTime == NULL) return; // --- 世纪位计算 --- // 根据年份设置世纪标志(0:20世纪及之后,1:19世纪) // uint8_t century_bit = (pTime->bit_data.year >= 2000) ? 0 : 1; // 完整四位数年份 // --- 寄存器写入(带掩码)--- // 秒(地址0x02):保留Bit7(CH时钟停止位) reg_sec = BM8563_ReadReg(BM8563_SEC) & 0x80; BM8563_WriteReg(BM8563_SEC, reg_sec | (DecToBcd(pTime->bit_data.second) & 0x7F)); // 分(地址0x03) BM8563_WriteReg(BM8563_MIN, DecToBcd(pTime->bit_data.minute) & 0x7F); // 小时(地址0x04):24小时制 BM8563_WriteReg(BM8563_HOUR, DecToBcd(pTime->bit_data.hour) & 0x3F); // 日(地址0x05):屏蔽闹钟使能位 BM8563_WriteReg(BM8563_DAY, DecToBcd(pTime->bit_data.day) & 0x3F); // 周(地址0x06):值范围1-7 BM8563_WriteReg(BM8563_WEEK, pTime->bit_data.week & 0x07); // 月(地址0x07):世纪位写入Bit7,月份占低5位 month_bcd = DecToBcd(pTime->bit_data.month); BM8563_WriteReg(BM8563_MONTH, (century_bit << 7) | (month_bcd & 0x1F)); // 年(地址0x08):存储后两位(如2024→0x24) BM8563_WriteReg(BM8563_YEAR, DecToBcd(pTime->bit_data.year)); } /** * @brief 读取BM8563当前时间到联合体 * @param pTime: UnTimeOutput联合体指针(用于存储读取到的时间数据) * @retval 无 */ void bm8563GetTime(UnTimeOutput *pTime) { if (pTime == NULL) { return; // 错误处理可扩展 } // 读取秒(地址0x02) pTime->bit_data.second = BcdToDec(BM8563_ReadReg(BM8563_SEC) & 0x7F); // 屏蔽无效位 // 读取分钟(地址0x03) pTime->bit_data.minute = BcdToDec(BM8563_ReadReg(BM8563_MIN) & 0x7F); // 读取小时(地址0x04) pTime->bit_data.hour = BcdToDec(BM8563_ReadReg(BM8563_HOUR) & 0x3F); // 24小时制需屏蔽Bit6-7 // 读取日(地址0x05) pTime->bit_data.day = BcdToDec(BM8563_ReadReg(BM8563_DAY) & 0x3F); // 屏蔽控制位 // 读取周(地址0x06,BM8563周值为0x01-0x07,无需BCD转换) pTime->bit_data.week = BM8563_ReadReg(BM8563_WEEK) & 0x07; // 仅保留低3位 // 读取月(地址0x07) pTime->bit_data.month = BcdToDec(BM8563_ReadReg(BM8563_MONTH) & 0x1F); // 屏蔽Bit5-7 // 读取年(地址0x08,假设为2000+年) pTime->bit_data.year = BcdToDec(BM8563_ReadReg(BM8563_YEAR)); } /** * @brief 设置BM8563闹钟(字段为0时禁用对应报警) * @param pTime: UnTimeOutput联合体指针,包含闹钟时间参数 * @retval 无 */ ubyte bm8563SetAlarm(UnTimeOutput *pTime) { UnTimeOutput un_temp_output = {0};//接收设定时间 ubyte carry_hour = 0; ubyte carry_day = 0; ubyte month_days = 0; //------------------------------------------------- // 检查指针有效性 if( (pTime == NULL) || ( (0 == pTime->bit_data.minute) && (0 == pTime->bit_data.hour) && (0 == pTime->bit_data.day) ) )//数据都为0或者指针都为0 { // 可选:添加错误处理(如日志输出) return 1; } bm8563GetTime(¤ttime); // 分钟溢出处理(0-59) un_temp_output.bit_data.minute = currenttime.bit_data.minute + pTime->bit_data.minute; if (un_temp_output.bit_data.minute >= 60) { un_temp_output.bit_data.minute -= 60; carry_hour = 1; // 向小时进位 } // 小时溢出处理(0-23) un_temp_output.bit_data.hour = currenttime.bit_data.hour + pTime->bit_data.hour + carry_hour; if (un_temp_output.bit_data.hour >= 24) { un_temp_output.bit_data.hour -= 24; carry_day = 1; // 向天进位 } // 天溢出处理(需考虑月份最大天数) un_temp_output.bit_data.day = currenttime.bit_data.day + pTime->bit_data.day + carry_day; //2月考虑平年和闰年 month_days = getMonthDays( (currenttime.bit_data.year+2000),currenttime.bit_data.month); // 天溢出处理(需考虑月份最大天数) if (un_temp_output.bit_data.day > month_days) { un_temp_output.bit_data.day -= month_days; //最大限制,如果超过1个月,就少一天,BM8563最大只支持这么大 if(un_temp_output.bit_data.day == currenttime.bit_data.day) { un_temp_output.bit_data.day = (currenttime.bit_data.day - 1); } } un_temp_output.bit_data.week = 0;//不需要周报警 // 报警分钟设置(地址0x09) BM8563_WriteReg(BM8563_ALARM_MIN, DecToBcd(un_temp_output.bit_data.minute) & 0x7F); // AE_M=0(启用) // 报警小时设置(地址0x0A) BM8563_WriteReg(BM8563_ALARM_HOUR, DecToBcd(un_temp_output.bit_data.hour) & 0x7F); // AE_H=0(启用) // 日报警/周报警互斥设置 BM8563_WriteReg(BM8563_ALARM_DAY, DecToBcd(un_temp_output.bit_data.day) & 0x7F); // AE_D=0(启用日) BM8563_WriteReg(BM8563_ALARM_WEEK, 0x80); // AE_W=1(禁用周) // 使能闹钟中断(地址0x01,AIE=1,AF=0) BM8563_WriteReg(BM8563_CSR2, 0x02); return 0; } //// 配置 BM8563 的闹钟,实现间隔 4 小时的唤醒 //void BM8563_Set4HourAlarm() //{ // unsigned char alarmMin = BcdToDec( BM8563_ReadReg(BM8563_MIN) ); // unsigned char alarmMinBcd = 0; ////------------------------------------------------------------ // alarmMin = (alarmMin + 2) % 60;//计算 4 小时后的小时数 // alarmMinBcd = DecToBcd(alarmMin); // BM8563_WriteReg(BM8563_ALARM_MIN,alarmMinBcd&0x7F);// 闹钟分钟设置 // BM8563_WriteReg(BM8563_ALARM_HOUR, 0x80); // 无效 // BM8563_WriteReg(BM8563_ALARM_DAY , 0x80); // 无效 // BM8563_WriteReg(BM8563_ALARM_WEEK, 0x80); // 无效 // // // 配置闹钟控制寄存器,使能闹钟中断 // BM8563_WriteReg(BM8563_CSR2, 0x02); //}