亲测实验,RTC使用内部低速时钟LSI时,对RTC的配置过程

  • Post author:
  • Post category:其他


下面是一开始写程序时,配置过程:

char RTCInit()

{



char count = 0;



StartTime.year = 16;



StartTime.month = 3;





StartTime.day = 5;



StartTime.hour = 20;



StartTime.min = 41;



StartTime.sec = 0;






RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR , ENABLE);








PWR_BackupAccessCmd(ENABLE);//打开后备域电源,可以访问后备域寄存器




//(由于RTC的配置数据在后备域BKP中,所以只要Vbat或者VDD不丢电就不丢失(即使复位了也不丢失),故可通过读BKP某个值来判断是否丢电,进而判断RTC是否需要初始化配置)



if(BKP_ReadBackupRegister(BKP_DR1) != 0xAA00)//Vbat且VDD掉电



{




BKP_DeInit();


//复位备份区域,将BKP寄存器清空




/(时钟配置部分)



//RCC_LSEConfig(RCC_LSE_ON);//开启外部低速晶振


LSE





RCC_LSICmd(ENABLE);//开启内部低速晶振LSI






while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0 && count<11)



//while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == 0 && count<11)  //等待LSE启振,判断在2S内配置是否成功,不成功返回0



{




count++;



delay_ms(200);



}






if(count == 10)



{




return 0;//LSI启振失败



}






RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);



//RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//使用外部低速晶振LSE为RTC时钟源






RCC_RTCCLKCmd(ENABLE);//选择使能RTC时钟



RTC_WaitForLastTask();//等待上一次写RTC任务完成(常用,只要涉及对RTC里值的修改,都需要在修改后加上此函数)



RTC_WaitForSynchro();//等待与APB1的同步,才能读RTC寄存器







/ (寄存器配置部分)






RTC_EnterConfigMode();//允许RTC配置



RTC_WaitForLastTask();//等待上一次写RTC任务完成



RTC_SetPrescaler(40000);//分频后为1HZ



//RTC_SetPrescaler(32767);//分频后为1HZ



RTC_WaitForLastTask();//等待上一次写RTC任务完成




//


RTC_ClearITPendingBit(RTC_IT_ALR);

//


RTC_WaitForLastTask();






RTC_ITConfig(RTC_IT_ALR , DISABLE);//使能闹钟中断.  秒中断RTC_IT_SEC






RTC_WaitForLastTask();//等待上一次写RTC任务完成









SetWriteTime(&StartTime);//写入起始日历转变给RTC



RTC_WaitForLastTask();//等待上一次写RTC任务完成






RTC_ExitConfigMode(); //退出RTC配置模式



BKP_WriteBackupRegister(BKP_DR1, 0xAA00);//写入想要的丢电判断数据



GPIOInit(GPIOA ,GPIO_Pin_2, GPIO_Mode_Out_PP);//  LED   PA2






}






else//已经初始化过一次且没掉电



{



RTC_WaitForSynchro();//等待与APB1的同步,才能读RTC寄存器





RTC_EnterConfigMode();//允许RTC配置






RTC_ITConfig(RTC_IT_ALR, DISABLE);


//使能闹钟中断.  秒中断RTC_IT_SEC






RTC_WaitForLastTask();//等待上一次写RTC任务完成






RTC_ExitConfigMode(); //退出RTC配置模式



RTC_WaitForLastTask();//等待上一次写RTC任务完成






GPIOInit(GPIOA ,GPIO_Pin_6, GPIO_Mode_Out_PP);//  LED   PA6



}



return 1;//配置成功

}

实验结果,单片机刚上电PA2的LED灯可以亮,但按下复位时,PA6的LED灯不工作,按正常来说RTC在不掉电情况只要配置一次即可,按复位后应该进入else语句,进而点亮PA6的LED,但实际不然。通过在线调试,发现程序死在了RTC_WaitForSynchro();的同步函数里。

通过各种调试,程序还是卡死,因此怀疑是不是使用内部低速时钟LSI不稳定引起?(具体原因还不是很清楚??),不过当我把RTC的时钟配置部分复制到else语句里,奇迹出现了,复位后PA6的LED可以点亮。因此不管是上电还是复位,都需要对RST的时钟重新配置。于是有了下面正确的配置函数:

char RTCInit()

{



char count = 0;



StartTime.year = 16;



StartTime.month = 3;





StartTime.day = 5;



StartTime.hour = 20;



StartTime.min = 41;



StartTime.sec = 0;






RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR , ENABLE);








PWR_BackupAccessCmd(ENABLE);//打开后备域电源,可以访问后备域寄存器



//(由于RTC的配置数据在后备域BKP中,所以只要Vbat或者VDD不丢电就不丢失(即使复位了也不丢失),故可通过读BKP某个值来判断是否丢电,进而判断RTC是否需要初始化配置)



if(BKP_ReadBackupRegister(BKP_DR1) != 0xAA00)//Vbat且VDD掉电



{



BKP_DeInit();


//复位备份区域,将BKP寄存器清空


/(时钟配置部分)



RCC_LSICmd(ENABLE);//开启内部低速晶振LSI






while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0 && count<11) //等待LSI启振,判断在2S内配置是否成功,不成功返回0



{



count++;



delay_ms(200);



}






if(count == 10)



{



return 0;//LSI启振失败



}






RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);






RCC_RTCCLKCmd(ENABLE);//选择使能RTC时钟



RTC_WaitForLastTask();//等待上一次写RTC任务完成(常用,只要涉及对RTC里值的修改,都需要在修改后加上此函数)



RTC_WaitForSynchro();//等待与APB1的同步,才能读RTC寄存器







/ (寄存器配置部分)






RTC_EnterConfigMode();//允许RTC配置



RTC_WaitForLastTask();//等待上一次写RTC任务完成



RTC_SetPrescaler(40000);//分频后为1HZ



//RTC_SetPrescaler(32767);//分频后为1HZ



RTC_WaitForLastTask();//等待上一次写RTC任务完成









RTC_ITConfig(RTC_IT_ALR , DISABLE);//使能闹钟中断.  秒中断RTC_IT_SEC






RTC_WaitForLastTask();//等待上一次写RTC任务完成









SetWriteTime(&StartTime);//写入起始日历转变给RTC



RTC_WaitForLastTask();//等待上一次写RTC任务完成






RTC_ExitConfigMode(); //退出RTC配置模式



BKP_WriteBackupRegister(BKP_DR1, 0xAA00);//写入想要的丢电判断数据



GPIOInit(GPIOA ,GPIO_Pin_2, GPIO_Mode_Out_PP);//  LED   PA2






}






else//已经初始化过一次且没掉电



{

/(时钟配置部分)



RCC_LSICmd(ENABLE);//开启内部低速晶振LSI






while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0 && count<11)



{



count++;



delay_ms(200);



}






if(count == 10)



{



return 0;//LSI启振失败



}






RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);






RCC_RTCCLKCmd(ENABLE);//选择使能RTC时钟



RTC_WaitForLastTask();//等待上一次写RTC任务完成(常用,只要涉及对RTC里值的修改,都需要在修改后加上此函数)



RTC_WaitForSynchro();//等待与APB1的同步,才能读RTC寄存器






/ (寄存器配置部分)






RTC_EnterConfigMode();//允许RTC配置






RTC_ITConfig(RTC_IT_ALR, DISABLE);


//使能闹钟中断.  秒中断RTC_IT_SEC






RTC_WaitForLastTask();//等待上一次写RTC任务完成






RTC_ExitConfigMode(); //退出RTC配置模式



RTC_WaitForLastTask();//等待上一次写RTC任务完成






GPIOInit(GPIOA ,GPIO_Pin_6, GPIO_Mode_Out_PP);//  LED   PA6



}



return 1;//配置成功

}



版权声明:本文为ludaoyi88原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。