OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4527|回复: 10

STM32的RTC时间跳秒问题,用的UCOSII 2.86

[复制链接]

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
发表于 2016-3-9 08:40:14 | 显示全部楼层 |阅读模式
1金钱
STM32的RTC时间跳秒问题,用的UCOSII 2.86
实际使用过程中,发现RTC会跳秒,具体表现就是32分钟34秒左右,偶尔会发生一次,比如:1,2,3,4,下一秒应该是5,结果就成了6,然后下一秒还是6,最后是7。
代码如下:
初始化代码:
u8 RTC_Init(void)
{
     //检查是不是第一次配置时钟
     u8 temp = 0;
     //使能电源和后备接口时钟
     RCC->APB1ENR |= 1<<28;     //使能电源时钟
     RCC->APB1ENR |= 1<<27;    //使能备份时钟
     //使能对后备寄存器和RTC的访问      
     PWR->CR |= 1<<8;          //取消备份区写保护

     if(BKP->DR1 != 0XA5A5)    //第一次配置
     {     
          RCC->BDCR |= 1<<16;    //备份区域软复位     
          RCC->BDCR &= ~(1<<16);//备份区域软复位结束      
          RCC->BDCR |= 1<<0;    //开启外部低速振荡器  
          while((!(RCC->BDCR&0X02)) && temp<250)//等待外部时钟就绪   
          {
               temp++;
               delay_ms(10);
          };
          if(temp>=250) return 1;    //初始化时钟失败,晶振有问题               
          RCC->BDCR |= 1<<8;     //LSE作为 RTC 时钟      
          RCC->BDCR |= 1<<15;    //RTC 时钟使能   
          RTC->PRLH = 0X0000;
          RTC->PRLL = 32774;    //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767  ---32770         
          while(!(RTC->CRL&(1<<5)));//等待 RTC 寄存器操作完成   
          while(!(RTC->CRL&(1<<3)));//等待 RTC 寄存器同步   
          RTC->CRH|=0X01;    //允许秒中断
          while(!(RTC->CRL&(1<<5)));//等待 RTC 寄存器操作完成   
          //RTC->CRL|=1<<4;    //允许配置   
          RTC_Set(2000,10,1,10,39,30);//设置时间   
          //RTC->CRL&=~(1<<4);//配置更新
         // while(!(RTC->CRL&(1<<5)));//等待RTC 寄存器操作完成   
          BKP->DR1 = 0XA5A5;
//          BKP->DR4 = 0;    ////里程统计临时存储器
//          BKP->DR5 = 0;
     }
     else//系统继续计时
     {
           while(!(RTC->CRL&(1<<3)));//等待 RTC 寄存器同步   
           RTC->CRH|=0X01;      //允许秒中断
           while(!(RTC->CRL&(1<<5)));//等待 RTC 寄存器操作完成
     }
     MY_NVIC_Init(0,0,RTC_IRQn,2);//RTC,G2,P2,S2.优先级最低  
     RTC_Get();//更新时间  
     return 0; //ok
}

这个:   RTC->PRLL = 32774;    //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767  ---32770        我是参考http://www.openedv.com/posts/list/162.htm修改的,分别是32767  32770 32774都会出现这样的问题。
void RTC_IRQHandler(void)
{            
//    u16 temp = 0;
    u8 Tmp[25];
    OSIntEnter();

    if(RTC -> CRL & 0x0001)//秒钟中断
    {        
        RTC_Get();//更新时间
        DT_HexToBCD(DateTimeBCD,DateTimeHex);   
        Strncpy_u8(&Tmp[0],"time200ms=",10);
        Tmp[10]=asc(time200ms);
        Tmp[11] = ',';
        rcdtime = ((u32)DateTimeBCD[2]<<24) + ((u32)DateTimeBCD[3]<<16) + ((u32)DateTimeBCD[4]<<8) + (u32)DateTimeBCD[5];  
        LongToAsc(rcdtime    ,&Tmp[12],1);  
        Tmp[20] = 'B';
        Tmp[21] = '\n';
        Print_Debug(Tmp,22);  
    }
    if(RTC -> CRL & 0x0002)//闹钟中断
    {  
        RTC->CRL &= ~(0x0002);//清闹钟中断
     
        Strncpy_u8(&Tmp[0],"time200ms=",10);
        Tmp[10]=asc(time200ms);
        Tmp[11] = ',';
        rcdtime = ((u32)DateTimeBCD[2]<<24) + ((u32)DateTimeBCD[3]<<16) + ((u32)DateTimeBCD[4]<<8) + (u32)DateTimeBCD[5];  
        LongToAsc(rcdtime    ,&Tmp[12],1);  
        Tmp[20] = 'A';
        Tmp[21] = '\n';
        Print_Debug(Tmp,22);
    }                 
    RTC -> CRL &= 0X0FFA;         //清除溢出,秒钟中断标志

    while(!(RTC -> CRL & (1 << 5)));//等待 RTC 寄存器操作完成  
    if(m_time200ms!=time200ms)
    {
        m_time200ms=time200ms;
        Strncpy_u8(&Tmp[0],"time200ms=",10);
        Tmp[10]=asc(time200ms);
        Tmp[11] = ',';
        rcdtime = ((u32)DateTimeBCD[2]<<24) + ((u32)DateTimeBCD[3]<<16) + ((u32)DateTimeBCD[4]<<8) + (u32)DateTimeBCD[5];  
        LongToAsc(rcdtime    ,&Tmp[12],1);  
        Tmp[20] = '\n';
        Print_Debug(Tmp,21);
    }
    OSIntExit();        
}      
以上是中断服务函数中,我加入了调试信息,time200ms是Timer4_Init中的时钟200毫秒触发一次,timer200ms++,到5赋值为0。Timer4_Init(1999,7199)。
//1999,7199
void Timer4_Init(u16 arr,u16 psc)
{
    RCC->APB1ENR |= 1<<2;//TIM3时钟使能   
     TIM4->ARR = arr;  //设定计数器自动重装值   
    TIM4->PSC = psc;  //预分频器72,得到1Mhz的计数时钟
    //这两个东东要同时设置才可以使用中断
    TIM4->DIER |= 1<<0;   //允许更新中断               
    TIM4->DIER |= 1<<6;   //允许触发中断
                                          
    TIM4->CR1 |= 0x01;    //使能定时器3
      MY_NVIC_Init(1,2,TIM4_IRQn,2);//抢占2,子优先级3,组2                                    
}

打印出来的调试信息,我进行了整理如下:
[00:56:06.834] time200ms=3,09005606B
[00:56:07.834] time200ms=3,09005608B
[00:56:08.816] t~ime200ms=2,09005608B
[00:56:08.835] time200ms=2,09005608
[00:56:09.835] time200ms=2,09005609B
[00:56:10.835] time200ms=2,09005610B
  

[02:33:57.398] time200ms=0,09023357B
[02:33:58.398] ime200ms=0,09023359B
[02:33:59.400] time200ms=4,09023359B
[02:33:59.400] time200ms=4,09023359
[02:34:00.397] time200ms=4,09023400B
[02:34:01.397] ime200ms=4,09023401B


  [03:39:08.107] time200ms=3,09033908B
[03:39:09.107] time200ms=3,09033910B
[03:39:10.109] time200ms=2,09033910B
[03:39:10.109] time200ms=2,09033910
[03:39:11.107] time200ms=2,09033911B
  

[04:11:42.962] time200ms=2,09041143B
[04:11:43.962] time200ms=2,09041145B
[04:11:44.964] time200ms=1,09041145B
[04:11:44.964] time200ms=1,09041145
[04:11:45.962] time200ms=1,09041146B
[04:11:46.962] time200ms=1,09041147B

  
[04:44:17.816] time200ms=1,09044418B
[04:44:18.816] time200ms=1,09044420B
[04:44:19.816] time200ms=0,09044420B
[04:44:19.816] time200ms=0,09044420
[04:44:20.819] time200ms=0,09044421B
  
  
[05:16:51.670] time200ms=0,09051652B
[05:16:52.669] time200ms=0,09051654B
[05:16:53.671] time200ms=4,09051654B
[05:16:53.671] time200ms=4,09051654
[05:16:54.669] time200ms=4,09051655B
  
[06:21:59.378] ime200ms=3,09062200B
[06:22:00.378] ime200ms=3,09062202B
[06:22:01.380] ime200ms=2,09062202B
[06:22:01.380] time200ms=2,09062202
[06:22:02.378] ime200ms=2,09062203B

  
[06:54:33.233] ime200ms=2,09065434B
[06:54:34.233] ime200ms=2,09065436B
[06:54:35.235] ime200ms=1,09065436B
[06:54:35.235] time200ms=1,09065436
[06:54:36.232] ime200ms=1,09065437B
  

[07:27:06.086] time200ms=1,09072707B
[07:27:07.086] time200ms=1,09072709B
[07:27:08.088] time200ms=0,09072709B
[07:27:08.088] time200ms=0,09072709
[07:27:09.086] time200ms=0,09072710B


time200ms=3,09002329
time200ms=2,09005608----32 39
time200ms=1,09012845    32  37
time200ms=0,09020122    32  37
time200ms=4,09023359--- 32  37
time200ms=3,09030634    32  35
time200ms=2,09033910--- 32  36
time200ms=1,09041145--- 32  35
time200ms=0,09044420----32  35
time200ms=4,09051654--- 32  34
time200ms=3,09054928    32  34
time200ms=2,09062202--- 32  34
time200ms=1,09065436--- 32  34
time200ms=0,09072709--- 32  33

带---地方是发生跳秒的时间点,后面的32 34是遇上一个点间隔是32分34秒。跳秒基本上都会发生在200ms错位的地方。
希望大侠给分析下,看看有可能是哪里的问题?

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-9 08:41:12 | 显示全部楼层
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-9 08:45:32 | 显示全部楼层
u8 RTC_Get(void)
{
        u32 TimeVar = 0;  
        u16 TY = 0;
        u8 TM = 1, TD = 0;
    u16 Num4Y = 0,NumY = 0, Off4Y = 0;
    u8 i = 0;
    u32 NumDay = 0,OffSec = 0;
    u8 THH = 0, TMM = 0, TSS = 0;
                     
        TimeVar = RTC -> CNTH;//得到计数器中的值(秒钟数)
        TimeVar <<= 16;
        TimeVar += RTC -> CNTL;  
       
        curRTC_DateTime = TimeVar;            //当前秒数
          
        Num4Y = TimeVar / SecsPerFourYear;
    OffSec = TimeVar % SecsPerFourYear;

    i = 1;
    while(OffSec > Year_Secs_Accu[i++])
    {
        Off4Y++;
    }
  
    /* Numer of Complete Year */
    NumY = Num4Y * 4 + Off4Y;
      /* 2000,2001,...~2000+NumY-1 complete year before, so this year is 2000+NumY*/
    TY = NumY; //+ 2000
   
    OffSec = OffSec - Year_Secs_Accu[i-2];
   
    /* Month (TBD with OffSec)*/
    i = 0;
    if(TY % 4)
    {// common year
            while(OffSec > Month_Secs_Accu_C[i++]);
            TM = i - 1;
            OffSec = OffSec - Month_Secs_Accu_C[i-2];
    }
    else
    {// leap year
            while(OffSec > Month_Secs_Accu_L[i++]);
            TM = i - 1;
            OffSec = OffSec - Month_Secs_Accu_L[i-2];
    }
   
    /* Date (TBD with OffSec) */
    NumDay = OffSec / SecsPerDay;
    OffSec = OffSec % SecsPerDay;
    TD = NumDay + 1;

      /* Compute  hours */
          THH = OffSec / 3600;
  /* Compute minutes */
          TMM = (OffSec % 3600) / 60;
  /* Compute seconds */
          TSS = (OffSec % 3600) % 60;
   
        DateTimeHex[0] = TY;
        DateTimeHex[1] = TM;
        DateTimeHex[2] = TD;      
        DateTimeHex[3] = THH;     //小时
        DateTimeHex[4] = TMM; //分钟
         
        DateTimeHex[5]  = TSS; //秒钟
        return 0;
}
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-9 18:43:50 | 显示全部楼层
又重新测试一遍,这次是200MS打印加上了。这次没发现跳秒,但是有2秒是重复的。
1.png
回复

使用道具 举报

10

主题

561

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1837
金钱
1837
注册时间
2014-6-27
在线时间
981 小时
发表于 2016-3-9 20:00:40 | 显示全部楼层
你做个任务,设置个节拍来扫描,比如就1个节拍时间,任务里面判断秒有没有变化,如果有,就显示出来,就算RTC晶振快了或者慢了,你读的速度一定比它秒的变化要快,这样一定可以保证及时读出时间来,无论快了还是慢了,问题点也就知道了。你这种情况,都不知道是RTC问题,还是UCOS问题。
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-9 20:13:13 | 显示全部楼层
我已经用200MS一次,打印了,还是32分钟出现一次重秒的问题。发现是RTC的CNTH和CTNL没有变化。
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-10 08:55:32 | 显示全部楼层
昨晚把 RTC->PRLL = 32756;发现还是32分钟一次重秒问题,而且发现时间还是走快了,设置32774的时候时间还是走快。
回复

使用道具 举报

25

主题

683

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1351
金钱
1351
注册时间
2012-4-25
在线时间
195 小时
发表于 2016-3-10 09:35:12 | 显示全部楼层
既然用了OS 还在中断里面处理这么复杂的数据。中断的意思就是个通知,数据处理放在任务中。
1-1
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-10 14:00:31 | 显示全部楼层
在中断里计算下时间,也算复杂任务吗?
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-10 14:19:49 | 显示全部楼层
[14:11:57.510] time200ms=2,10141156,1E743D2CB
[14:11:57.510] time200ms=3,10141156,1E743D2CHH
[14:11:57.708] time200ms=4,10141156,1E743D2CHH
[14:11:57.907] time200ms=5,10141156,1E743D2CHH
[14:11:58.110] time200ms=0,10141156Q1E743D2CQQ
[14:11:58.110] time200ms=1,10141156,1E743D2CHH
[14:11:58.307] time200ms=2,10141156,1E743D2CHH
[14:11:58.510] time200ms=2,10141158,1E743D2EB
[14:11:58.510] ~ime200ms=3,10141158,1E743D2EHH

[14:11:58.714] ime200ms=4,10141158,1E743D2EHH
[14:11:58.907] time200ms=5,10141158,1E743D2EHH
[14:11:59.110] time200ms=0,10141158Q1E743D2EQQ
[14:11:59.110] time200ms=1,10141158,1E743D2EHH
[14:11:59.307] time200ms=2,10141158,1E743D2EHH
[14:11:59.512] time200ms=2,10141159,1E743D2FB
回复

使用道具 举报

1

主题

9

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2016-3-9
在线时间
2 小时
 楼主| 发表于 2016-3-10 14:20:28 | 显示全部楼层
丢了一秒,确实是计数器多加了一个数,为什么?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-20 06:15

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表