416 lines
9.8 KiB
C
416 lines
9.8 KiB
C
#include "MAIN.H"
|
||
#include <stdio.h>
|
||
#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);
|
||
//}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|