305 lines
7.5 KiB
C
305 lines
7.5 KiB
C
#include "MAIN.H"
|
||
#include <stdio.h>
|
||
#include "RTC.H"
|
||
#include <string.h>
|
||
//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;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|