0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

RTC實(shí)驗(yàn)

汽車電子技術(shù) ? 來源:滑小稽筆記 ? 作者:電子技術(shù)園地 ? 2023-03-01 15:46 ? 次閱讀

12.1 概述

實(shí)時(shí)時(shí)鐘Real TimeClock(簡(jiǎn)稱RTC),實(shí)時(shí)時(shí)鐘芯片是日常生活中應(yīng)用最為廣泛的消費(fèi)類電子產(chǎn)品之一。它為人們提供精確的實(shí)時(shí)時(shí)間,或者為電子系統(tǒng)提供精確的時(shí)間基準(zhǔn),目前實(shí)時(shí)時(shí)鐘芯片大多采用精度較高的晶體振蕩器作為時(shí)鐘源。有些時(shí)鐘芯片為了在主電源掉電時(shí),還可以工作,需要外加電池供電。

現(xiàn)在的ARM體系處理器基本都會(huì)內(nèi)置RTC模塊,STM32也不例外。STM32內(nèi)部RTC結(jié)構(gòu)如下圖所示。

poYBAGP_An-AXUzUAAGljwT34VQ575.png

RTC主要有兩個(gè)部分組成,第一部分的APB1接口用來和APB1總線相連,此單元還包含一組16位寄存器,可通過APB1總線對(duì)其進(jìn)行讀寫操作。另一部分由一組可編程計(jì)數(shù)器組成,分成兩個(gè)主要模塊。第一個(gè)模塊是RTC的預(yù)分頻模塊,它可編程產(chǎn)生最長(zhǎng)為1秒的RTC時(shí)間基準(zhǔn)TR_CLK。RTC的預(yù)分頻模塊包含了一個(gè)20位的可編程分頻器。如果在RTC_CR寄存器中設(shè)置了相應(yīng)的允許位,則在每個(gè)TR_CLK周期中RTC產(chǎn)生一個(gè)中斷。第二個(gè)模塊是一個(gè)32位的可編程計(jì)數(shù)器,可被初始化為當(dāng)前的系統(tǒng)時(shí)間。系統(tǒng)時(shí)間按TR_CLK周期累加并與存儲(chǔ)在RTC_ALR寄存器中的可編程時(shí)間相比較,如果RTC_CR控制寄存器中設(shè)置了相應(yīng)允許位,比較匹配時(shí)將產(chǎn)生一個(gè)鬧鐘中斷。

RTC模塊和時(shí)鐘配置系統(tǒng)是在后備區(qū)域,即在系統(tǒng)復(fù)位或從待機(jī)模式喚醒后RTC的設(shè)置和時(shí)間維持不變。但是在系統(tǒng)復(fù)位后,會(huì)自動(dòng)禁止訪問后備寄存器和RTC,以防止對(duì)后備區(qū)域的意外寫操作。所以在要設(shè)置時(shí)間之前,先要取消備份區(qū)域?qū)懕Wo(hù)。

12.2 相關(guān)寄存器

12.2.1 控制寄存器1:RTC_CRH

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

-

OWIE

ALRIE

SECIE

Bit 2:允許溢出中斷位

0:屏蔽溢出中斷

1:允許溢出中斷

Bit 1:允許鬧鐘中斷

0:屏蔽鬧鐘中斷
1:允許鬧鐘中斷

Bit 0:允許秒中斷

0:屏蔽秒中斷

1:允許秒中斷

12.2.2 控制寄存器2:RTC_CRL

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

-

RTOFF

CNF

RSF

OWF

ALRF

SECF

Bit 5:RTC操作關(guān)閉

0:寫操作未完成

1:操作已完成

Bit 4:配置標(biāo)志

0:退出配置模式

1:進(jìn)入配置模式

Bit 3:RTC同步標(biāo)志

RTC_CNT寄存器和RTC_DIV寄存器由軟件更新或清0時(shí),此位由硬件置1。在APB1復(fù)位后,或APB1時(shí)鐘停止后,此位必須由軟件清0。要進(jìn)行任何的讀操作之前,用戶程序必須等待這位被硬件置1

0:寄存器尚未被同步

1:寄存器已經(jīng)被同步

Bit 2:溢出標(biāo)志

當(dāng)32位可編程計(jì)數(shù)器溢出時(shí),此位由硬件置1。此位只能由軟件清0

0:無溢出

1:32位可編程計(jì)數(shù)器溢出

Bit 1:鬧鐘標(biāo)志

當(dāng)32位可編程計(jì)數(shù)器達(dá)到RTC_ALR寄存器所設(shè)置的預(yù)定值,此位由硬件置1。此位只能由軟件清0。

0:無鬧鐘

1:有鬧鐘

Bit 0:秒標(biāo)志

當(dāng)32位可編程預(yù)分頻器溢出時(shí),此位由硬件置1,同時(shí)RTC計(jì)數(shù)器加1。此位只能由軟件清除。

0:秒標(biāo)志條件不成立

1:秒標(biāo)志條件成立

12.2.3 預(yù)分頻裝載寄存器1:RTC_PRLH

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

-

PRL[19:16]

Bit 3~Bit 0:RTC預(yù)分頻裝載值高位

12.2.4 預(yù)分頻裝載寄存器2:RTC_PRLL

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

PRL[15:0]

Bit 15~Bit 0:RTC預(yù)分頻裝載值低位

注:RTC時(shí)鐘頻率根據(jù)預(yù)分頻寄存器的值有如下計(jì)算公式。

pYYBAGP_AoyABJbhAAAR-b703dM921.png

其中RTCCLK代表的RTC的輸入時(shí)鐘,一般默認(rèn)32.768kHz。

12.3 實(shí)驗(yàn)例程

功能:讀取RTC的日期顯示在LCD上面。

(1)創(chuàng)建rtc.h文件輸入以下代碼。

/*********************************************************************************************************
*********************************************************************************************************/
#ifndef _RTC_H_
#define _RTC_H_

#include "sys.h"
/*********************************************************************************************************
                  數(shù)    據(jù)    結(jié)    構(gòu)
*********************************************************************************************************/
typedef struct
{
  u8 year;                    //年
  u8 month;                    //月
  u8 date;                    //日
  u8 hour;                    //時(shí)
  u8 minute;                    //分
  u8 second;                    //秒
}RTC_Data;
extern RTC_Data RTC_Time;
/*********************************************************************************************************
                  函    數(shù)    列    表
*********************************************************************************************************/
void RTC_Init( void ) ;                                          //RTC初始化
void RTC_Set_Time( u8 year, u8 month, u8 date, u8 hour, u8 minute, u8 second ) ;            //設(shè)置時(shí)間
void RTC_Get_Time( void ) ;                                        //獲取時(shí)間

#endif

(2)創(chuàng)建rtc.c文件并輸入以下代碼。

#include "rtc.h"
/***************************************************
Name    :RTC_Init
Fuction    :RTC初始化
Parameter  :None
Return    :None
***************************************************/
void RTC_Init()
{
  if( BKP->DR1!=0x5050 )
  {
    RCC->APB1ENR |= 1<<28 ;                                      //使能PWR時(shí)鐘
    RCC->APB1ENR |= 1<<27 ;                                      //使能BKP時(shí)鐘,RTC校準(zhǔn)在BKP相關(guān)寄存器中
    PWR->CR |= 1<<8 ;                                        //取消BKP相關(guān)寄存器寫保護(hù)
    RCC->BDCR |= 1<<16 ;                                      //備份區(qū)域軟復(fù)位
    RCC->BDCR &= ~( 1<<16 ) ;                                    //備份區(qū)域軟復(fù)位結(jié)束
    RCC->BDCR |= 1<<0 ;                                        //開啟外部低速振蕩器
    while( ( RCC->BDCR&0x02 )!=0x02 ) ;                                //等待外部時(shí)鐘就緒
    RCC->BDCR |= 1<<8 ;                                        //LSI作為RTC時(shí)鐘
    RCC->BDCR |= 1<<15 ;                                      //RTC時(shí)鐘使能
    while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
    while( !( RTC->CRL&( 1<<3 ) ) ) ;                                //等待RTC寄存器同步完成
    RTC->CRH &= ~( 7<<0 ) ;                                      //不允許中斷,CRH寄存器低三位有效
    while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
    RTC->CRL |= 1<<4 ;                                        //進(jìn)入配置模式
    RTC->PRLH = 0 ;
    RTC->PRLL = 32767 ;                                        //設(shè)定分頻值
    RTC->CRL &= ~( 1<<4 ) ;                                      //退出配置模式
    while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器最后一次操作完成
    BKP->DR1 = 0x5050 ;
  }
  else
  {
    while( !( RTC->CRL&( 1<<3 ) ) ) ;                                //等待RTC寄存器同步
      while( !( RTC->CRL&( 1<<5 ) ) ) ;                                //等待RTC寄存器操作完成
  }
}
/***************************************************
Name    :Is_Leap_Year
Function  :閏年判定
Parameter  :
      year:年份
Return    :閏年
***************************************************/
u8 Is_Leap_Year( u16 year )
{
  //必須能被4整除
  if( year%4==0 )
  {
    if( year%100==0 )
    {
      if( year%400==0 )
        return 1 ;
      else
        return 0 ;
    }
    else
      return 1 ;
  }
  else
    return 0;
}
/***************************************************
Name    :RTC_Set_Time
Fuction    :設(shè)置時(shí)間
Parameter  :
      year:年
      month:月
      date:日
      hour:時(shí)
      minute:分
      second:秒
Return    :None
***************************************************/
u8 mon_table[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } ;
void RTC_Set_Time( u8 year, u8 month, u8 date, u8 hour, u8 minute, u8 second )
{
  u16 t ;
  u32 seccount = 0 ;
  //把所有年份的秒鐘相加
  for( t=1970; tAPB1ENR |= 1<<28 ;                                        //使能電源時(shí)鐘
    RCC->APB1ENR |= 1<<27 ;                                        //使能備份時(shí)鐘
  PWR->CR |= 1<<8 ;                                          //取消備份區(qū)寫保護(hù)
  RTC->CRL |= 1<<4 ;                                          //允許配置
  RTC->CNTL = seccount&0xFFFF ;
  RTC->CNTH = seccount>>16 ;
  RTC->CRL &= ~( 1<<4 ) ;                                        //配置更新
  while( ( RTC->CRL&0x20 )!=0x20 ) ;                                  //等待RTC寄存器操作完成
  RTC_Get_Time() ;                                          //設(shè)置完之后更新一下數(shù)據(jù)
}
/***************************************************
Name    :RTC_Get_Time
Fuction    :獲取時(shí)間
Parameter  :None
Return    :None
***************************************************/
RTC_Data RTC_Time;
void RTC_Get_Time()
{
  u16 daycnt=0;
  u32 timecount=0;
  u32 temp=0;
  u16 temp1=0;
  //得到計(jì)數(shù)器中的值
  timecount = RTC->CNTH ;
  timecount <<= 16 ;
  timecount += RTC->CNTL ;
  //得到天數(shù)
   temp = timecount/86400 ;
  //超過一天了
  if( daycnt!=temp )
  {    
    daycnt = temp ;
    temp1 = 1970 ;                                          //從1970年開始
    while( temp>=365 )
    {
      //閏年
      if( Is_Leap_Year( temp1 ) )
      {
        if( temp>=366 )
          temp -= 366 ;                                    //閏年的秒鐘數(shù)
        else
          break ;
      }
      else
        temp -= 365;                                      //平年
      temp1 ++ ;
    }
    RTC_Time.year = temp1-2000 ;                                  //得到年份
    temp1 = 0 ;
    //超過了一個(gè)月
    while( temp>=28 )
    {
      if( Is_Leap_Year( RTC_Time.year+2000 )&&( temp1==1 ) )//當(dāng)年是不是閏年/2月份
      {
        if( temp>=29 )
          temp -= 29 ;//閏年的秒鐘數(shù)
        else
          break; 
      }
      else 
      {
        if( temp>=mon_table[ temp1 ] )
          temp -= mon_table[ temp1 ] ;                            //平年
        else
          break ;
      }
      temp1 ++ ;
    }
    RTC_Time.month = temp1+1 ;                                    //得到月份
    RTC_Time.date = temp+1 ;                                    //得到日期
  }
  temp = timecount%86400 ;                                      //得到秒鐘數(shù)
  RTC_Time.hour = temp/3600 ;                                      //小時(shí)
  RTC_Time.minute = ( temp%3600 )/60 ;                                //分鐘
  RTC_Time.second = ( temp%3600 )%60 ;                                //秒鐘
}+2000;>

(3)創(chuàng)建1.c文件并輸入以下代碼。

#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "rtc.h"

int main()
{
  u8 Str[ 50 ] ;
  STM32_Clock_Init( 9 ) ;                                        //STM32時(shí)鐘初始化
  SysTick_Init( 72 ) ;                                        //SysTick初始化
  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  LCD_Init() ;                                            //LCD初始化
  RTC_Init() ;
  RTC_Set_Time( 20, 12, 10, 10, 8, 0 ) ;
  while( 1 )
  {
    RTC_Get_Time() ;
    sprintf( ( char * )Str, "20%02d-%02d-%02d %02d:%02d:%02d", RTC_Time.year, RTC_Time.month, RTC_Time.date, RTC_Time.hour, RTC_Time.minute, RTC_Time.second ) ;
    LCD_ShowString( 10, 10, Str ) ;
    delay_ms( 500 ) ;
  }
}



聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 電子產(chǎn)品
    +關(guān)注

    關(guān)注

    6

    文章

    1118

    瀏覽量

    57890
  • 實(shí)時(shí)時(shí)鐘

    關(guān)注

    4

    文章

    232

    瀏覽量

    65529
  • RTC
    RTC
    +關(guān)注

    關(guān)注

    2

    文章

    511

    瀏覽量

    65897
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    RTC實(shí)驗(yàn)效果

    單片機(jī)RTC
    jf_06209345
    發(fā)布于 :2022年04月03日 16:24:41

    77 第22.1講 RTC實(shí)驗(yàn)-6U內(nèi)部RTC詳解 - 第1節(jié)

    控制器程序RTC
    充八萬
    發(fā)布于 :2023年08月17日 09:33:28

    77 第22.1講 RTC實(shí)驗(yàn)-6U內(nèi)部RTC詳解 - 第3節(jié)

    控制器程序RTC
    充八萬
    發(fā)布于 :2023年08月17日 09:35:09

    77 第22.1講 RTC實(shí)驗(yàn)-6U內(nèi)部RTC詳解 - 第5節(jié) #硬聲創(chuàng)作季

    控制器程序RTC
    充八萬
    發(fā)布于 :2023年08月17日 09:36:49

    STM32 RTC實(shí)驗(yàn)問題

    想使用內(nèi)部晶振作為時(shí)鐘源。但是rtc沒工作。代碼看的原子的寫的代碼如下:if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)//從指定的后備寄存器中讀出數(shù)據(jù)
    發(fā)表于 05-04 22:01

    【連載】【星光閃電STM32F407開發(fā)板】第十二章 RTC實(shí)驗(yàn)

    第十二章 RTC實(shí)驗(yàn)12.1 實(shí)驗(yàn)目的本實(shí)驗(yàn)旨在掌握STM32的實(shí)時(shí)時(shí)鐘RTC的使用,利用其測(cè)量日期時(shí)間,數(shù)據(jù)手冊(cè)請(qǐng)參看第16章。12.2
    發(fā)表于 11-11 16:01

    為什么我進(jìn)行RTC實(shí)驗(yàn)時(shí)LCD顯示的秒鐘快了10倍?

    在進(jìn)行RTC實(shí)驗(yàn)時(shí),我拔掉板后的電池,然后再用提供的例程燒盡去,結(jié)果發(fā)現(xiàn)LCD顯示的秒鐘快了10倍,這是為什么呢?高手們可否解釋一下……
    發(fā)表于 04-04 06:35

    RTC實(shí)驗(yàn)屏幕只有紅色的字

    剛把光盤上的第十一個(gè)實(shí)驗(yàn)燒寫上去,發(fā)現(xiàn)屏幕只有紅色的字,藍(lán)色的時(shí)間沒有,LED 不亮,這是板的問題,還是程序的問題了
    發(fā)表于 04-23 01:50

    RTC實(shí)驗(yàn)lCD顯示重影

    請(qǐng)教原子大哥,我按照你的rtc實(shí)驗(yàn),把LSE 改為L(zhǎng)SI 了,分頻改為39999; 其他都沒有變化,但是LCD顯示的時(shí)候這一秒和上一秒顯示的時(shí)候重影這么厲害啊,基本上看不清楚了,是什么原因呢
    發(fā)表于 05-09 06:35

    ucos中加入RTC代碼編譯不通過

    該添加的都添加了,該包含的也包含了。不知道問題出在哪。附件有工程代碼。ucos rtc實(shí)驗(yàn).zip (18.45 MB )
    發(fā)表于 04-16 04:35

    RTC實(shí)驗(yàn)程序disp-week找不到在哪?

    RTC實(shí)驗(yàn)程序disp-week找不到在哪?用軟件查詢沒有
    發(fā)表于 08-28 06:36

    如何通過串口超級(jí)終端修改RTC時(shí)間

    注意一定要下載RTC實(shí)驗(yàn)的例程,然后打開串口助手發(fā)送如下指令。RTC_Set(2019,12,14,21,10,30)就可以完成對(duì)RTC 的設(shè)置
    發(fā)表于 01-12 07:55

    RTC實(shí)驗(yàn)

    以前寫論文收集的一些資料,學(xué)習(xí)單片機(jī)、C語言的好資料?。。?!
    發(fā)表于 07-08 15:08 ?11次下載

    STM32入門學(xué)習(xí)筆記之RTC實(shí)驗(yàn)(上)

    實(shí)時(shí)時(shí)鐘Real TimeClock(簡(jiǎn)稱RTC),實(shí)時(shí)時(shí)鐘芯片是日常生活中應(yīng)用最為廣泛的消費(fèi)類電子產(chǎn)品之一。它為人們提供精確的實(shí)時(shí)時(shí)間,或者為電子系統(tǒng)提供精確的時(shí)間基準(zhǔn),目前實(shí)時(shí)時(shí)鐘芯片大多采用精度較高的晶體振蕩器作為時(shí)鐘源。有些時(shí)鐘芯片為了在主電源掉電時(shí),還可以工作,需要外加電池供電。
    的頭像 發(fā)表于 02-16 11:22 ?1320次閱讀
    STM32入門學(xué)習(xí)筆記之<b class='flag-5'>RTC</b><b class='flag-5'>實(shí)驗(yàn)</b>(上)

    STM32入門學(xué)習(xí)筆記之RTC實(shí)驗(yàn)(下)

    實(shí)時(shí)時(shí)鐘Real TimeClock(簡(jiǎn)稱RTC),實(shí)時(shí)時(shí)鐘芯片是日常生活中應(yīng)用最為廣泛的消費(fèi)類電子產(chǎn)品之一。它為人們提供精確的實(shí)時(shí)時(shí)間,或者為電子系統(tǒng)提供精確的時(shí)間基準(zhǔn),目前實(shí)時(shí)時(shí)鐘芯片大多采用精度較高的晶體振蕩器作為時(shí)鐘源。有些時(shí)鐘芯片為了在主電源掉電時(shí),還可以工作,需要外加電池供電。
    的頭像 發(fā)表于 02-16 11:22 ?473次閱讀