Files
acquisition_module/RTC.c
2025-07-05 07:57:10 +08:00

416 lines
9.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 清除报警标志AFBit3
* @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保留Bit7CH时钟停止位
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);
// 小时地址0x0424小时制
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); // 屏蔽控制位
// 读取周地址0x06BM8563周值为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(&currenttime);
// 分钟溢出处理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禁用周
// 使能闹钟中断地址0x01AIE=1AF=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);
//}