找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4160|回復(fù): 1
收起左側(cè)

2440裸機(jī)編程之六 實時時鐘

[復(fù)制鏈接]
ID:68618 發(fā)表于 2014-11-12 13:50 | 顯示全部樓層 |閱讀模式
實時日歷時鐘(RTC)單元作為S3C2440A 內(nèi)部一個獨立的功能單元,能夠像鐘表和日歷一樣保存并自動計算時間。它還具有定時報警和產(chǎn)生節(jié)拍的功能。RTC 單元僅需要通過外接一個32. 768 kHz 的晶振來提供時鐘源。


RTC 可以通過備用電池供電,因此,即使系統(tǒng)電源關(guān)閉,也可以繼續(xù)工作。RTC 的寄存器保存了一些表示時間的8 位BCD 碼數(shù)據(jù),包括:秒、分、時、日期、星期、月和年。


下面分四部分分別介紹:RTC的顯示,RTC的設(shè)置,RTC的節(jié)拍中斷,RTC的報警中斷
一、RTC的顯示
RTCCON用于RTC的控制,其中RTCCON[0]用于控制使能,所以在操作RTC的任何寄存器之前,要使這一位使能,這樣才使操作有效
rBCDYEAR            存放年份值,BCD碼形式
rBCDMON             月
rBCDDATE            日(按月)   
rBCDDAY             日(按星期)      
rBCDHOUR            小時
rBCDMIN             分
rBCDSEC             秒

RTC的顯示實驗程序:
//********************************************************************
const char week[][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
void Main(void)
{     
    int i;
    ……硬件初始化……

Uart_Printf("RTC顯示\n\n");

rRTCCON  = rRTCCON  & ~(0xf)  | 0x1;  //使能RTC控制
   
    rBCDYEAR = rBCDYEAR & ~(0xff) | 0x99;  //設(shè)置年份為99年,注意是BCD碼形式,賦值不要越界
    rBCDMON  = rBCDMON  & ~(0x1f) | 0x12;  //月
    rBCDDATE = rBCDDATE & ~(0x3f) | 0x31;  //日(按月)   
    rBCDDAY  = rBCDDAY  & ~(0x7)  | 0x1;  //日(按星期)      
    rBCDHOUR = rBCDHOUR & ~(0x3f) | 0x23;  //小時
    rBCDMIN  = rBCDMIN  & ~(0x7f) | 0x59;  //分
    rBCDSEC  = rBCDSEC  & ~(0x7f) | 0x45;  //秒
   
    rRTCCON  = 0x0;                 //取消RTC控制使能
temp = rBCDSEC;
while(1)
{
  while(rBCDSEC==temp);     //等待一秒
  temp = rBCDSEC;
  Uart_Printf("%2x年%2x月%2x日  %s  %2x:%2x:%2x\n",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
}
}

//*******************************************************************

運行結(jié)構(gòu)如圖:


二、RTC的設(shè)置
其實就是寫年月日這些寄存器,沒什么復(fù)雜的地方
//********************************************************************
const char week[][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
void Main(void)
{     
    int i;
    ……硬件初始化……

Uart_Printf("RTC設(shè)置時間\n\n");
Uart_Printf("按S鍵設(shè)定時間             按D鍵顯示時間\n");
do
{
  key = Uart_Getch();
  if(key=='s' || key=='S') RTC_set();
  else if(key=='d' || key=='D') Uart_Printf("%2x年%2x月%2x日  %s  %2x:%2x:%2x\n",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
  else Uart_Printf("無效的輸入!        按S鍵設(shè)定時間            按D鍵顯示時間\n\n");
}
while(1);
}

void RTC_set(void)
{
do
{
  Uart_Printf("輸入年份:");
  year = Uart_GetIntNum();  //輸入年份
}
while(year>99);
Uart_Printf("年份:%d\n",year);

do
{
  Uart_Printf("輸入月份:");
  month = Uart_GetIntNum();
}
while(month<1 || month>12);
Uart_Printf("月份:%d\n",month);

do
{
  Uart_Printf("輸入日:");
  date = Uart_GetIntNum();
}
while(date<1 || date>31);
Uart_Printf("日:%d\n",day);

do
{
  Uart_Printf("輸入星期幾(1:星期日、2:星期一......7:星期六):");
  day = Uart_GetIntNum();
}
while(day<1 || day>7);
Uart_Printf("%s\n",week[day-1]);

do
{
  Uart_Printf("輸入小時:");
  hour = Uart_GetIntNum();
}
while(hour>23);
Uart_Printf("小時:%d\n",hour);

do
{
  Uart_Printf("輸入分:");
  minute = Uart_GetIntNum();
}
while(minute>59);
Uart_Printf("分:%d\n",minute);

do
{
  Uart_Printf("輸入秒:");
  second = Uart_GetIntNum();
}
while(second>59);
Uart_Printf("秒:%d\n",second);


rRTCCON  = rRTCCON  & ~(0xf)  | 0x1;  //使能RTC控制
   
    rBCDYEAR = rBCDYEAR & ~(0xff) | (year/10<<4)+year%10;  //設(shè)置年份為99年,注意是BCD碼形式,賦值不要越界
    rBCDMON  = rBCDMON  & ~(0x1f) | (month/10<<4)+month%10;  //月
    rBCDDATE = rBCDDATE & ~(0x3f) | (date/10<<4)+date%10;  //日(按月)   
    rBCDDAY  = rBCDDAY  & ~(0x7)  | 0x1;      //日(按星期)      
    rBCDHOUR = rBCDHOUR & ~(0x3f) | (hour/10<<4)+hour%10;  //小時
    rBCDMIN  = rBCDMIN  & ~(0x7f) | (minute/10<<4)+minute%10;  //分
    rBCDSEC  = rBCDSEC  & ~(0x7f) | (second/10<<4)+second%10;  //秒
   
    rRTCCON  = 0x0;                 //取消RTC控制使能
   
    Uart_Printf("輸入完畢\n");
    Uart_Printf("按S鍵設(shè)定時間            按D鍵顯示時間 \n");
}

//*******************************************************************


三、RTC的節(jié)拍中斷

節(jié)拍中斷即每個RTC節(jié)拍產(chǎn)生一個中斷
這里用到TICNT寄存器,TICNT[7]用于使能,TICNT[6:0]取值為1~127,其對應(yīng)的節(jié)拍中斷時間間隔為(TICNT+1)/128
這是RTC的節(jié)拍中斷的實驗程序,間隔時間設(shè)為1秒
//********************************************************************
const char week[][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
void Main(void)
{     
    int i;
    ……硬件初始化……

Uart_Printf("RTC TICK中斷\n\n");

tick_init();
tick_INT_init();

while(1);
}
void tick_init(void)  //RTC TICK初始化
{
rRTCCON = 1;   //允許設(shè)置
rTICNT = 1<<7 | 127 ; //允許TICK中斷,每次中斷時間為:  (n+1)/128 * 1秒 ,其中  n = TICNT[6:0]
rRTCCON = 0;   //禁止設(shè)置
}
void tick_INT_init(void)    //RTC報警中斷初始化
{
ClearPending(1<<8);   //清除報警中斷標(biāo)志
pISR_TICK = (U32)tick_ISR;  //填入中斷例程 于中斷向量表的 報警中斷向量處
rINTMSK &= ~(1<<8);   //禁止屏蔽報警中斷
}
void tick_ISR(void)  __irq   //RTC報警中斷例程
{
Uart_Printf("當(dāng)前時間: %2x年%2x月%2x日  %s  %2x:%2x:%2x\n",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
ClearPending(1<<8);   //清除報警中斷標(biāo)志
}

//*******************************************************************


結(jié)果如圖




四、RTC的報警中斷
報警,其實就像個鬧鐘,一旦當(dāng)前時間(BCDYEAR……)與報警時間(ALMYEAR ……)匹配,就會引發(fā)中斷
這里用到的寄存器有:
ALMYEAR                          報警年份寄存器
ALMMON                           月
ALMDATE                          日(按月)   
ALMHOUR                          小時
ALMMIN                           分
ALMSEC                           秒

RTCALM 決定年月日時分秒這六個寄存器哪些需要使能,比如:如果ALMMON未使能,則在匹配的時候忽略ALMMON的值。

下面是測試報警中斷的程序:
//********************************************************************
const char week[][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
void Main(void)
{     
    int i;
    ……硬件初始化……

Uart_Printf("RTC報警中斷實驗\n");

alarm_init();
Uart_Printf("        按S鍵設(shè)定時間       按A鍵設(shè)定報警時間      按D鍵顯示時間\n");
do
{
  key = Uart_Getch();
  if(key=='s' || key=='S') RTC_set();
  else if(key=='d' || key=='D')
  {
   Uart_Printf("當(dāng)前時間: %2x年%2x月%2x日  %s  %2x:%2x:%2x\n",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
   Uart_Printf("報警時間: %2x年%2x月%2x日          %2x:%2x:%2x\n",rALMYEAR,rALMMON,rALMDATE,rALMHOUR,rALMMIN,rALMSEC);
  }
  else if(key=='a' || key=='A') RTC_alarm_set();
  else Uart_Printf("無效的輸入!        按S鍵設(shè)定時間       按A鍵設(shè)定報警時間      按D鍵顯示時間\n");
}
while(1);
}
void alarm_init(void)    //RTC報警中斷初始化
{
ClearPending(1<<30);   //清除報警中斷標(biāo)志
pISR_RTC = (U32)alarm_ISR;  //填入中斷例程 于中斷向量表的 報警中斷向量處
rINTMSK &= ~(1<<30);   //禁止屏蔽報警中斷
}
void alarm_ISR(void)  __irq   //RTC報警中斷例程
{
Uart_Printf("報警時間到!!!\n");
Uart_Printf("報警時間到!!!\n");
Uart_Printf("報警時間到!!!\n");
ClearPending(1<<30);   //清除報警中斷標(biāo)志
}
void RTC_set(void)     //RTC當(dāng)前時間設(shè)置
{
Uart_Printf("設(shè)置當(dāng)前時間:\n");

  do
{
  Uart_Printf("輸入星期幾 (1:星期日、2:星期一......7:星期六):");
  day = Uart_GetIntNum();  //輸入星期幾
}
while(day<1 || day>7);
Uart_Printf("%s\n",week[day-1]);

time_input();     //輸入時間:年月日時分秒


rRTCCON  = rRTCCON  & ~(0xf)  | 0x1;  //使能RTC控制
   
    rBCDYEAR = rBCDYEAR & ~(0xff) | (year/10<<4)+year%10;  //設(shè)置年份為99年,注意是BCD碼形式,賦值不要越界
    rBCDMON  = rBCDMON  & ~(0x1f) | (month/10<<4)+month%10;  //月
    rBCDDATE = rBCDDATE & ~(0x3f) | (date/10<<4)+date%10;  //日(按月)   
    rBCDDAY  = rBCDDAY  & ~(0x7)  | 0x1;      //日(按星期)      
    rBCDHOUR = rBCDHOUR & ~(0x3f) | (hour/10<<4)+hour%10;  //小時
    rBCDMIN  = rBCDMIN  & ~(0x7f) | (minute/10<<4)+minute%10;  //分
    rBCDSEC  = rBCDSEC  & ~(0x7f) | (second/10<<4)+second%10;  //秒
   
    rRTCCON  = 0x0;                 //取消RTC控制使能
   
    Uart_Printf("輸入完畢\n");
Uart_Printf("       按S鍵設(shè)定時間       按A鍵設(shè)定報警時間      按D鍵顯示時間\n");
}
void RTC_alarm_set(void)   //RTC報警時間設(shè)置
{
Uart_Printf("設(shè)置報警時間:\n");

time_input();        //輸入時間:年月日時分秒

rRTCCON  = rRTCCON  & ~(0xf)  | 0x1;  //使能RTC控制
   
    rALMYEAR = rALMYEAR & ~(0xff) | (year/10<<4)+year%10;  //設(shè)置年份為99年,注意是BCD碼形式,賦值不要越界
    rALMMON  = rALMMON  & ~(0x1f) | (month/10<<4)+month%10;  //月
    rALMDATE = rALMDATE & ~(0x3f) | (date/10<<4)+date%10;  //日(按月)   
//   rALMDAY  = rALMDAY  & ~(0x7)  | 0x1;      //日(按星期)   報警無此寄存器     
    rALMHOUR = rALMHOUR & ~(0x3f) | (hour/10<<4)+hour%10;  //小時
    rALMMIN  = rALMMIN  & ~(0x7f) | (minute/10<<4)+minute%10;  //分
    rALMSEC  = rALMSEC  & ~(0x7f) | (second/10<<4)+second%10;  //秒
   
    rRTCCON  = 0x0;                 //取消RTC控制使能
   
rRTCALM = 0x7F;        //開啟全局報警
    Uart_Printf("輸入完畢\n");
Uart_Printf("       按S鍵設(shè)定時間       按A鍵設(shè)定報警時間      按D鍵顯示時間\n");
}
void time_input(void)     //輸入時間:年月日時分秒
{
do
{
  Uart_Printf("輸入年份:");
  year = Uart_GetIntNum();  //輸入年份
}
while(year>99);
Uart_Printf("年份:%d\n",year);

do
{
  Uart_Printf("輸入月份:");
  month = Uart_GetIntNum();
}
while(month<1 || month>12);
Uart_Printf("月份:%d\n",month);

do
{
  Uart_Printf("輸入日:");
  date = Uart_GetIntNum();
}
while(date<1 || date>31);
Uart_Printf("日:%d\n",day);

do
{
  Uart_Printf("輸入小時:");
  hour = Uart_GetIntNum();
}
while(hour>23);
Uart_Printf("小時:%d\n",hour);

do
{
  Uart_Printf("輸入分:");
  minute = Uart_GetIntNum();
}
while(minute>59);
Uart_Printf("分:%d\n",minute);

do
{
  Uart_Printf("輸入秒:");
  second = Uart_GetIntNum();
}
while(second>59);
Uart_Printf("秒:%d\n",second);
}
//*******************************************************************
結(jié)果如圖

回復(fù)

使用道具 舉報

ID:45457 發(fā)表于 2015-9-11 19:08 | 顯示全部樓層
2440裸機(jī)編程之六 實時時鐘
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表