下面是一开始写程序时,配置过程:
    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;//配置成功
   
   }
  
 
