你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F103内外部时钟切换问题

[复制链接]
wildeer 提问时间:2016-7-14 10:29 /
产品设计方案:在HSE故障时切换至HSI,2分频后给PLL再16倍频(手册说可以到64M),在LSE故障时优先切换至HSE时钟,HSE故障时切换至LSI,暂时只考虑故障后复位重启,未修改CSS中断代码,可实际代码怎么也调不通(有晶振时可以),始终卡在“等待RTC寄存器同步”位置,大伙帮我看看问题在哪:(硬件:先加上HSE和LSE晶振,后都取消)

代码如下:
void RCC_Configuration(void)
{   
//复位RCC外部设备寄存器到默认值
  RCC_DeInit();

  //打开外部高速晶振
  RCC_HSEConfig(RCC_HSE_ON);

   //等待外部高速时钟准备好
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)   //外部高速时钟已经准别好
  {                                                                       
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //开启FLASH的预取功能

    FLASH_SetLatency(FLASH_Latency_2);        //FLASH延迟2个周期         

    RCC_HCLKConfig(RCC_SYSCLK_Div1);  //配置AHB(HCLK)时钟=SYSCLK  

    RCC_PCLK2Config(RCC_HCLK_Div1);  //配置APB2(PCLK2)钟=AHB时钟

    RCC_PCLK1Config(RCC_HCLK_Div2);        //配置APB1(PCLK1)钟=AHB 1/2时钟

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);        //配置PLL时钟 == 外部高速晶体时钟*9  PLLCLK = 8MHz * 9 = 72 MHz

    RCC_PLLCmd(ENABLE);        //使能PLL时钟

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}        //等待PLL时钟就绪

    //配置系统时钟 = PLL时钟
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

   //检查PLL时钟是否作为系统时钟
    while(RCC_GetSYSCLKSource() != 0x08){}// 0x00:HSI 作为系统时钟,0x04:HSE作为系统时钟,0x08:PLL作为系统时钟
  }
        else        //如果外部时钟不成功
        {
                RCC_HSICmd(ENABLE);        //

                while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET){        }
               
                FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

                FLASH_SetLatency(FLASH_Latency_2);

                RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB时钟为系统时钟SYSCLK

                RCC_PCLK2Config(RCC_HCLK_Div1);  //APB1时钟为HCLK/2,其中HCLK为AHB时钟

                RCC_PCLK1Config(RCC_HCLK_Div2);  //APB2时钟为HCLK                 

                RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);        //设置 PLL 时钟源=HSI2分频,及倍频系数16倍

                RCC_PLLCmd(ENABLE);//如果PLL被用于系统时钟,那么它不能被失能  
                  
                while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}        //等待指定的 RCC 标志位设置成功 等待PLL初始化成功
               
                RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);        //设置系统时钟(SYSCLK) 设置PLL为系统时钟源  
                     
                while(RCC_GetSYSCLKSource() != 0x08){ }    //等待PLL成功用作于系统时钟的时钟源
        }
        
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD
                                                | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG | RCC_APB2Periph_AFIO, ENABLE);
        
}


//如果外部低速晶振失效,则使用外部HSE128分频后作为RTC时钟,如果也没有HSE,则使用LSI时钟,不能使用HSI作为RTC时钟
u8 RTC_Init(void)
{
        u8 temp=0;        
        RCC->APB1ENR |= 3<<27;     //使能电源时钟和备份时钟   
        PWR->CR |=1<<8;           //取消备份区写保护
        RCC->BDCR|=1<<15;                                //RTC时钟使能,取消该句无影响
        
        //检查是否首次配置RTC
        if(BKP->DR1!=0x5AA5)//第一次配置
        {         
                RCC->BDCR|=1<<16;        //备份区域软复位           
                RCC->BDCR&=~(1<<16);     //备份区域软复位结束                  
               RCC->BDCR|=1<<0;         //开启外部低速振荡器
               while((!(RCC->BDCR&0X02))&&temp<250)//等待外部时钟就绪         
                {
                        temp++;
                        msDelay(10);
                };
               
                if(temp>=250)                //LSE故障,切换至HSE或LSI
                {
                        RCC->BDCR &= ~(1<<0);                //关闭LSE
                        
                        if( RCC->CR & 0x20000)        //如果HSE准备就绪
                        {
                                RCC->BDCR |=3<<8;                        //HSE/128作为RTC时钟 8M/128=62.5Khz        
                        }
                        else
                        {                                
                                RCC->BDCR &= ~(3<<8);        //RTC时钟选择清零
                                RCC->BDCR |= 2<<8;        //使用LSI作为RTC时钟,40KHz
                        }
                }
          else
                {
                        RCC->BDCR &= ~(3<<8);        //RTC时钟选择清零
                        RCC->BDCR|=1<<8;                  //LSE作为RTC时钟           
                }
               
                RCC->BDCR|=1<<15;                        //RTC时钟使能         
          while(!(RTC->CRL&(1<<5))){};        //等待RTC寄存器操作完成
         
          while(!(RTC->CRL&(1<<3)));          //等待RTC寄存器同步,总是死在此处
                        
                        
                RTC->CRL|=1<<4;             //允许配置                        
                if(temp>=250)
                {
                        if( RCC->CR & 0x20000)        //如果HSE正常工作,则使用HSE/128作为RTC时钟
                        {
                                RTC->PRLH=0X0000;
                                RTC->PRLL=62500-1;                //HSE/128=62500,取62500-1
                        }
                        else        //使用LSI作为RTC时钟
                        {
                                RTC->PRLH=0X0000;
                                RTC->PRLL=40000-1;      //时钟周期设置,内部LSI时钟偏差很大,需要经常校准,理论值:40K                                                                        
                        }                                
                }
                else
                {
                        RTC->PRLH=0X0000;
                        RTC->PRLL=32768-1;      //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767                                                                                 
                }        
               
                RTC_Set(2016,8,8,8,8,8); //设置时间         
                RTC->CRL&=~(1<<4);          //配置更新
                while(!(RTC->CRL&(1<<5)));  //等待RTC寄存器操作完成                                                                                          
                BKP->DR1=0x5AA5;  
        }
        else//系统继续计时
        {
            //while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步  
        }        
        
//         RTC->CRH |=0X01;                            //允许秒中断
//         while(!(RTC->CRL&(1<<5)));        //等待RTC寄存器操作完成         
//        RTC_NVIC_Config();//RTC中断分组设置,使用秒中断时需要                                                         
        
        RTC_Get();//更新时间,填写calendar结构体初始值
        return 0; //ok
}


调试读取的寄存器值如下:
RCC->CR = 0x03015083
RCC->CFGR = 0x0038840A
RCC->BDCR = 0x00008201
RCC->APB1ENR = 0x38064036
RCC->CIR = 0x00000000
RTC->CRL = 0x0020
BKP->DR1 = 0x0000

收藏 评论5 发布时间:2016-7-14 10:29

举报

5个回答
wildeer 回答时间:2016-7-17 10:39:02
没人回复,这个问题困扰了我很久,难道这样不行吗?
回答时间:2016-7-18 11:46:09
楼主是否要用到RTC,如果用到RTC,是用外部的晶振还是用的内部的?
wildeer 回答时间:2016-7-18 12:24:15
用到RTC,优先用外部晶振,如果外部晶振故障,则切换至内部LSI。HSE也是类似要求
领导要求如此实现,因为原来产品多次出现过仅外部晶振故障导致产品不能使用的问题,所以要寻求软件解决方案,可怎么都实现不了呢,理论上应该可以啊,难道从来没人这么做过吗?
回答时间:2016-8-16 09:30:54
我们在103上有做过类似的功能,通过配置RTC的时钟源检测完成标志位,如果没有配置成功,就切换到内部。
涉及到以下函数:
RTC_LSE_Check、RTC_LSI_Check、RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE)、RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
ql1000 回答时间:2016-8-17 22:33:42
学习学习!

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版