关于调试RTC时钟出现的问题

     此次做一个项目出现了一个令我很不解的问题,就是RTC时钟,代码是提前写好的,当时是用的STM32F103ZET6最小系统板,所有功能都是没有问题的。但是最终我画好的PCB芯片用的是STM32F103C8T6为了节省成本嘛,经过不断的移植和调试过后,到了RTC这一步,外部低速晶振怎么都不起振,由于没有示波器没法测试晶振是否起振,我只能用万用表来测,测不出来啥,但是使用外部高速晶振就没有问题,当时以为是代码写错了,但是经过不断的检查发现没问题,难道是晶振坏了?于是就买的一个新的晶振,等换好晶振好发现还是不行,用debug调试的时候发现代码死在了   while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)这里,真是见鬼了,一头雾水啊,最后在网上查找,说电容问题,最后我又换了电容,还是不行,最后我发现我的电路图好像有问题,PC15和PC14这两个引脚连接了晶振

 

      但是PC15被我用到ESP8266的复位引脚上了,然后我修改代码,直接把ESP8266的代码给屏蔽了,经过测试发现还是不行,还是死在了RTC初始化,最后我把代码下载到了其他的板子上,发现RTC正常了,看来我的最小系统也是没问题的,到这里我就明白了,好家伙PC15引脚就算你不去用不初始化它,也不能接其他的模块引脚,如果接了,晶振就会不起振。我不知到这个引脚是不是可以用其他的办法可以使用。

另外你改了时间发现没有修改成功,这时你把 BKP_ReadBackupRegister(BKP_DR1)这个改成不一致就可以了,仔细看代码就明白了

RTC代码

#include "rtc.h"
#include "sys.h"
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
_calendar_obj calendar; //时钟结构体

static void RTC_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;            
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           
    NVIC_Init(&NVIC_InitStructure);                           
}
u8 RTC_initConfig(void)
{
   //检查是不是第一次配置时钟
   u8 temp=0;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟   
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问   
	if (BKP_ReadBackupRegister(BKP_DR1) != 0x5053)		//从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
		{	 			

		BKP_DeInit();	//复位备份区域 	
		RCC_LSEConfig(RCC_LSE_ON);	//设置外部低速晶振(LSE),使用外设低速晶振
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET && temp<250)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
			{
				temp++;
				delay_ms(10);
			}
		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寄存器的写操作完成
		RTC_Set(2023,4,4,9,14,55);  //设置时间	
		RTC_ExitConfigMode(); //退出配置模式  
		BKP_WriteBackupRegister(BKP_DR1, 0X5050);	//向指定的后备寄存器中写入用户程序数据
		}
	else//系统继续计时
		{

		RTC_WaitForSynchro();	//等待最近一次对RTC寄存器的写操作完成
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能RTC秒中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		}
	RTC_NVIC_Config();//RCT中断分组设置		    				     
	RTC_Get();//更新时间	
  return 0; //ok
}

// RTC时钟中断
//每秒触发一次
// extern u16 tcnt;
void RTC_IRQHandler(void)
{
    if (RTC_GetITStatus(RTC_IT_SEC) != RESET) //秒钟中断
    {
        RTC_Get(); //更新时间
    }
    if (RTC_GetITStatus(RTC_IT_ALR) != RESET) //闹钟中断
    {
        RTC_ClearITPendingBit(RTC_IT_ALR);                                                                                                       //清闹钟中断
        RTC_Get();                                                                                                                               //更新时间
        printf("Alarm Time:%d-%d-%d %d:%d:%d\n", calendar.w_year, calendar.w_month, calendar.w_date, calendar.hour, calendar.min, calendar.sec); //输出闹铃时间
    }
    RTC_ClearITPendingBit(RTC_IT_SEC | RTC_IT_OW); //清闹钟中断
    RTC_WaitForLastTask();
}
//判断是否是闰年函数
//月份   1  2  3  4  5  6  7  8  9  10 11 12
//闰年   31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 Is_Leap_Year(u16 year)
{
    if (year % 4 == 0) //必须能被4整除
    {
        if (year % 100 == 0)
        {
            if (year % 400 == 0)
                return 1; //如果以00结尾,还要能被400整除
            else
                return 0;
        }
        else
            return 1;
    }
    else
        return 0;
}
//设置时钟
//把输入的时钟转换为秒钟
//以1970年1月1日为基准
// 1970~2099年为合法年份
//返回值:0,成功;其他:错误代码.
//月份数据表
u8 const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; //月修正数据表
//平年的月份日期表
const u8 mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
u8 RTC_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec)
{
    u16 t;
    u32 seccount = 0;
    if (syear < 1970 || syear > 2099)
        return 1;
    for (t = 1970; t < syear; t++) //把所有年份的秒钟相加
    {
        if (Is_Leap_Year(t))
            seccount += 31622400; //闰年的秒钟数
        else
            seccount += 31536000; //平年的秒钟数
    }
    smon -= 1;
    for (t = 0; t < smon; t++) //把前面月份的秒钟数相加
    {
        seccount += (u32)mon_table[t] * 86400; //月份秒钟数相加
        if (Is_Leap_Year(syear) && t == 1)
            seccount += 86400; //闰年2月份增加一天的秒钟数
    }
    seccount += (u32)(sday - 1) * 86400; //把前面日期的秒钟数相加
    seccount += (u32)hour * 3600;        //小时秒钟数
    seccount += (u32)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;
}

//初始化闹钟
//以1970年1月1日为基准
// 1970~2099年为合法年份
// syear,smon,sday,hour,min,sec:闹钟的年月日时分秒
//返回值:0,成功;其他:错误代码.
u8 RTC_Alarm_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec)
{
    u16 t;
    u32 seccount = 0;
    if (syear < 1970 || syear > 2099)
        return 1;
    for (t = 1970; t < syear; t++) //把所有年份的秒钟相加
    {
        if (Is_Leap_Year(t))
            seccount += 31622400; //闰年的秒钟数
        else
            seccount += 31536000; //平年的秒钟数
    }
    smon -= 1;
    for (t = 0; t < smon; t++) //把前面月份的秒钟数相加
    {
        seccount += (u32)mon_table[t] * 86400; //月份秒钟数相加
        if (Is_Leap_Year(syear) && t == 1)
            seccount += 86400; //闰年2月份增加一天的秒钟数
    }
    seccount += (u32)(sday - 1) * 86400; //把前面日期的秒钟数相加
    seccount += (u32)hour * 3600;        //小时秒钟数
    seccount += (u32)min * 60;           //分钟秒钟数
    seccount += sec;                     //最后的秒钟加上去
    //设置时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
    PWR_BackupAccessCmd(ENABLE);                                             //使能后备寄存器访问
    //上面三步是必须的!

    RTC_SetAlarm(seccount);

    RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成

    return 0;
}

//得到当前的时间
//返回值:0,成功;其他:错误代码.
u8 RTC_Get(void)
{
    static u16 daycnt = 0;
    u32 timecount = 0;
    u32 temp = 0;
    u16 temp1 = 0;
    timecount = RTC_GetCounter();
    temp = timecount / 86400; //得到天数(秒钟数对应的)
    if (daycnt != temp)       //超过一天了
    {
        daycnt = temp;
        temp1 = 1970; //从1970年开始
        while (temp >= 365)
        {
            if (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 (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 = RTC_Get_Week(calendar.w_year, calendar.w_month, calendar.w_date); //获取星期
    return 0;
}
//获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//输入参数:公历年月日
//返回值:星期号
u8 RTC_Get_Week(u16 year, u8 month, u8 day)
{
    u16 temp2;
    u8 yearH, yearL;

    yearH = year / 100;
    yearL = year % 100;
    // 如果为21世纪,年份数加100
    if (yearH > 19)
        yearL += 100;
    // 所过闰年数只算1900年之后的
    temp2 = yearL + yearL / 4;
    temp2 = temp2 % 7;
    temp2 = temp2 + day + table_week[month - 1];
    if (yearL % 4 == 0 && month < 3)
        temp2--;
    return (temp2 % 7);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值