#include "MAIN.H" #include #include "RTC.H" #include //unsigned char bySta = 0; 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; } /** * @brief 检查报警标志AF是否置位(Bit3) * @retval true-报警已触发,false-无报警 */ bool bm8563CheckAlarmFlag(void) { ubyte reg_val = BM8563_ReadReg(BM8563_CSR2); return (reg_val & BM8563_AF_BIT) != 0; // 检查Bit3,如果为0的话,那就 } // 限制值在最小值和最大值之间 ubyte constrain(ubyte value, ubyte min_val, ubyte max_val) { if (value < min_val) { return min_val; } else if (value > max_val) { return max_val; } else { return value; } } /** * @brief 设置BM8563当前时间(整合世纪位到月份寄存器) * @param pTime: 时间结构体指针(年份需为完整四位数,如1984、2024) * @retval 无 */ void bm8563SetTime(UnTimeOutput *pTime) { ubyte reg_sec = 0; UnTimeOutput time_temp = {0}; if (pTime == NULL) { return; // 错误处理可扩展 } memcpy(&time_temp,pTime,sizeof(UnTimeOutput));//先拷贝 time_temp.bit_data.year = constrain(time_temp.bit_data.year,0,99);//限制值范围 time_temp.bit_data.month = constrain(time_temp.bit_data.month,1,12);//限制值范围 time_temp.bit_data.day = constrain(time_temp.bit_data.day,1,31);//限制值范围 time_temp.bit_data.hour = constrain(time_temp.bit_data.hour,0,23);//限制值范围 time_temp.bit_data.week = constrain(time_temp.bit_data.week,0,6);//限制值范围 time_temp.bit_data.minute = constrain(time_temp.bit_data.minute,0,59);//限制值范围 time_temp.bit_data.second = constrain(time_temp.bit_data.second,0,59);//限制值范围 BM8563_WriteReg( BM8563_YEAR, DecToBcd(pTime->bit_data.year) );//写年,还得转换为BCD码 BM8563_WriteReg( BM8563_MONTH, DecToBcd(pTime->bit_data.month)&0x1F);//写月,还得转换为BCD码 BM8563_WriteReg( BM8563_DAY, DecToBcd(pTime->bit_data.day)&0x3F);//写日,还得转换为BCD码 BM8563_WriteReg( BM8563_HOUR, DecToBcd(pTime->bit_data.hour)&0x3F);//写小时,还得转换为BCD码 BM8563_WriteReg( BM8563_WEEK, pTime->bit_data.week&0x07 );//写周,不需要转 BM8563_WriteReg( BM8563_MIN, DecToBcd( pTime->bit_data.minute)&0x7F);//写分钟,还得转换为BCD码 // 秒(地址0x02):保留Bit7(CH时钟停止位) reg_sec = BM8563_ReadReg(BM8563_SEC) & 0x80;// BM8563_WriteReg(BM8563_SEC, reg_sec | (DecToBcd(pTime->bit_data.second) & 0x7F));//注意高位为掉电指示 } /** * @brief 读取BM8563当前时间到联合体 * @param pTime: UnTimeOutput联合体指针(用于存储读取到的时间数据) * @retval 无 */ void bm8563GetTime(UnTimeOutput *pTime) { pTime->bit_data.year = BcdToDec(BM8563_ReadReg(BM8563_YEAR) );//先去除多余位,在转换10进制 pTime->bit_data.month = BcdToDec(BM8563_ReadReg(BM8563_MONTH)&0x1F); pTime->bit_data.day = BcdToDec(BM8563_ReadReg(BM8563_DAY)&0x3F); pTime->bit_data.hour = BcdToDec(BM8563_ReadReg(BM8563_HOUR)&0x3F); pTime->bit_data.week = BM8563_ReadReg(BM8563_WEEK)&0x07; pTime->bit_data.minute = BcdToDec(BM8563_ReadReg(BM8563_MIN)&0x7F); pTime->bit_data.second = BcdToDec(BM8563_ReadReg(BM8563_SEC)&0x7F); } /** * @brief 设置BM8563闹钟(字段为0时禁用对应报警) * @param pTime: UnTimeOutput联合体指针,包含闹钟时间参数 * @retval 无 */ ubyte bm8563SetAlarm(UnTimeOutput *pTime) { UnTimeOutput current_time_temp = {0}; UnTimeOutput output_time_temp = {0}; ubyte carry_hour = 0; ubyte carry_day = 0; // 检查指针有效性 if( (pTime == NULL) || ( (0 == pTime->bit_data.minute) && (0 == pTime->bit_data.hour) && (0 == pTime->bit_data.day) ) )//数据都为0或者指针都为0 { // 可选:添加错误处理(如日志输出) return 1; } bm8563GetTime(¤t_time_temp);//先获取当前时间 //计算分 output_time_temp.bit_data.minute = current_time_temp.bit_data.minute + pTime->bit_data.minute; if( output_time_temp.bit_data.minute >= 60 )//超过需要进位 { output_time_temp.bit_data.minute = output_time_temp.bit_data.minute - 60; carry_hour = 1; } //计算小时 output_time_temp.bit_data.hour = current_time_temp.bit_data.hour + pTime->bit_data.hour + carry_hour; if( output_time_temp.bit_data.hour >= 24 )//超过需要进位 { output_time_temp.bit_data.hour = output_time_temp.bit_data.hour - 24; carry_day = 1; } output_time_temp.bit_data.day = current_time_temp.bit_data.day + pTime->bit_data.day + carry_day; if( output_time_temp.bit_data.day >= 31 )//超过需要进位 { output_time_temp.bit_data.day = 31; } output_time_temp.bit_data.week = 0; BM8563_WriteReg( BM8563_ALARM_DAY, DecToBcd(output_time_temp.bit_data.day)&0x3F);//写日,还得转换为BCD码 BM8563_WriteReg( BM8563_ALARM_HOUR, DecToBcd(output_time_temp.bit_data.hour)&0x3F);//写小时,还得转换为BCD码 BM8563_WriteReg( BM8563_ALARM_WEEK, 0x80 );//写周,会和日冲突,所以不需要闹钟 BM8563_WriteReg( BM8563_ALARM_MIN, DecToBcd(output_time_temp.bit_data.minute)&0x7F);//写分钟,还得转换为BCD码 // 秒(地址0x02):保留Bit7(CH时钟停止位) // 使能闹钟中断(地址0x01,AIE=1,AF=0) BM8563_WriteReg(BM8563_CSR2, 0x02); return 0; }