實時日歷時鐘(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é)果如圖

|