求助解决正点原子RTC实时时钟例程,发现BUG,某些年份和月份会增加1,如下:
当我在初始化为:
BSP_RTC_Set(2012,12,31,23,59,57); //设置时间
通过串口打印出:
RTC Time:23:59:57
RTC Date:2013/13/1
RTC Time:23:59:58
RTC Date:2013/13/1
RTC Time:23:59:59
RTC Date:2013/1/1
RTC Time:0:0:0
RTC Date:2013/1/1
RTC Time:0:0:1
RTC Date:2013/1/1
或者:
BSP_RTC_Set(2016,12,31,23,59,50); //设置时间
通过串口打印出:2017/13/1 //..........同样出问题
初始化函数如下:
/*******************************************************************************
* 功 能: 初始化RTC时钟,同时检测时钟是否工作正常
* 参 数: void
* 返回值: 0 正常
其他 错误代码
*******************************************************************************/
CPU_INT08U BSP_RTC_Init(void)
{
OS_ERR err;
CPU_INT08U temp = 0; //检查是不是第一次配置时钟
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A2) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
BKP_DeInit(); //复位备份区域
RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //检查指定的RCC标志位设置与否,等待低速晶振就绪
{
temp++;
OSTimeDly((OS_TICK )10,
(OS_OPT )OS_OPT_TIME_DLY,
(OS_ERR *)&err);
}
if(temp >= 250)
{
return 1; //初始化时钟失败,晶振有问题
}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_WaitForSynchro(); //等待RTC寄存器同步
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_EnterConfigMode(); //允许配置
RTC_SetPrescaler(32767); //设置RTC预分频的值
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
BSP_RTC_Set(2012,12,31,23,59,57); //设置时间
RTC_ExitConfigMode(); //退出配置模式
BKP_WriteBackupRegister(BKP_DR1, 0XA5A5); //向指定的后备寄存器中写入用户程序数据
}
else //系统继续计时
{
RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
}
BSP_IntVectSet(BSP_INT_ID_RTC, BSP_RTC_IRQ_Handler); //RTC中断分组设置 // RTC_NVIC_Config();
BSP_IntPrioSet(BSP_INT_ID_RTC, 5);
BSP_IntEn(BSP_INT_ID_RTC);
BSP_RTC_Get(); //更新时间
return 0; //ok
}
分析认为在润平年之间的判断出问题,设置的函数如下:
/*******************************************************************************
* 功 能: 设置时钟,把输入的时钟转换为秒钟,以1970年1月1日为基准,1970~2099年为合法年份
* 参 数: year 年份
* 返回值: 0 成功;
其他 错误代码
*******************************************************************************/
CPU_INT08U BSP_RTC_Set(CPU_INT16U syear, CPU_INT08U smon, CPU_INT08U sday, CPU_INT08U hour, CPU_INT08U min, CPU_INT08U sec)
{
CPU_INT16U t;
CPU_INT32U seccount = 0;
if(syear < 1970 || syear > 2099)
{
return 1;
}
for(t = 1970; t < syear; t++) //把所有年份的秒钟相加
{
if(BSP_RTC_Is_Leap_Year(t))
{
seccount += 31622400; //闰年的秒钟数
}
else
{
seccount += 31536000; //平年的秒钟数
}
}
smon -= 1;
for(t = 0; t < smon; t++) //把前面月份的秒钟数相加
{
seccount += (CPU_INT32U)mon_table[t] * 86400; //月份秒钟数相加
if(BSP_RTC_Is_Leap_Year(syear) && (t == 1))
{
seccount += 86400; //闰年2月份增加一天的秒钟数
}
}
seccount += (CPU_INT32U)(sday - 1) * 86400; //把前面日期的秒钟数相加
seccount += (CPU_INT32U)hour * 3600; //小时秒钟数
seccount += (CPU_INT32U)min * 60; //分钟秒钟数
seccount += sec; //最后的秒钟加上去
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问
RTC_SetCounter(seccount); //设置RTC计数器的值
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
return 0;
}
获得时间的函数如下:
/*******************************************************************************
* 功 能: RTC时钟得到当前的时间
* 参 数: void
* 返回值: 0 成功
其他 错误代码
*******************************************************************************/
CPU_INT08U BSP_RTC_Get(void)
{
static CPU_INT16U daycnt = 0;
CPU_INT32U timecount = 0;
CPU_INT32U temp = 0;
CPU_INT16U temp1 = 0;
timecount = RTC->CNTH; //得到计数器中的值(秒钟数)
timecount <<= 16;
timecount += RTC->CNTL;
temp = timecount / 86400; //得到天数(秒钟数对应的)
if(daycnt != temp) //超过一天了
{
daycnt = temp;
temp1 = 1970; //从1970年开始
while(temp >= 365)
{
if(BSP_RTC_Is_Leap_Year(temp1)) //是闰年
{
if(temp >= 366)
{
temp -= 366; //闰年的秒钟数
}
else
{
temp1++;
break;
}
}
else
{
temp -= 365; //平年
}
temp1++;
}
calendar.w_year = temp1; //得到年份
temp1 = 0;
while(temp >= 28) //超过了一个月
{
if(BSP_RTC_Is_Leap_Year(calendar.w_year) && (temp1 == 1)) //当年是不是闰年/2月份
{
if(temp >= 29)
{
temp -= 29; //闰年的秒钟数
}
else
{
break;
}
}
else
{
if(temp >= mon_table[temp1])
{
temp -= mon_table[temp1]; //平年
}
else
{
break;
}
}
temp1++;
}
calendar.w_month = temp1+1; //得到月份
calendar.w_date = temp+1; //得到日期
}
temp = timecount % 86400; //得到秒钟数
calendar.hour = temp / 3600; //小时
calendar.min = (temp % 3600) / 60; //分钟
calendar.sec = (temp % 3600) % 60; //秒钟
calendar.week = BSP_RTC_Get_Week(calendar.w_year, calendar.w_month, calendar.w_date); //获取星期
return 0;
}
测试的函数如下:
/*******************************************************************************
* 功 能: 测试RTC
* 参 数: void
* 返回值: None
*******************************************************************************/
void BSP_RTC_Test(void)
{
OS_ERR err;
CPU_INT08U t = 0;
BSP_RTC_Init();
while(1)
{
if (t != calendar.sec)
{
t = calendar.sec;
BSP_Ser_Printf("RTC Date:%d/%d/%d
",calendar.w_year, calendar.w_month, calendar.w_date);
BSP_Ser_Printf("RTC Time:%d:%d:%d
",calendar.hour, calendar.min, calendar.sec);
OSTimeDly((OS_TICK )30,
(OS_OPT )OS_OPT_TIME_DLY,
(OS_ERR *)&err);
}
}
}
其它函数体没有变化,请教高手指出BUG,请作者修正BUG。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
while(temp >= 365)
{
if(BSP_RTC_Is_Leap_Year(temp1)) //是闰年
{
if(temp >= 366)
{
temp -= 366; //闰年的秒钟数
}
else
{
// temp1++;
break;
}
}
else
{
temp -= 365; //平年
}
temp1++;
}
谢谢原子。
一周热门 更多>