找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3713|回复: 1
打印 上一主题 下一主题
收起左侧

2440裸机编程之六 实时时钟

[复制链接]
跳转到指定楼层
楼主
ID:68618 发表于 2014-11-12 13:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
实时日历时钟(RTC)单元作为S3C2440A 内部一个独立的功能单元,能够像钟表和日历一样保存并自动计算时间。它还具有定时报警和产生节拍的功能。RTC 单元仅需要通过外接一个32. 768 kHz 的晶振来提供时钟源。


RTC 可以通过备用电池供电,因此,即使系统电源关闭,也可以继续工作。RTC 的寄存器保存了一些表示时间的8 位BCD 码数据,包括:秒、分、时、日期、星期、月和年。


下面分四部分分别介绍:RTC的显示,RTC的设置,RTC的节拍中断,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;  //设置年份为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);
}
}

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

运行结构如图:


二、RTC的设置
其实就是写年月日这些寄存器,没什么复杂的地方
//********************************************************************
const char week[][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
void Main(void)
{     
    int i;
    ……硬件初始化……

Uart_Printf("RTC设置时间\n\n");
Uart_Printf("按S键设定时间             按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键设定时间            按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;  //设置年份为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键设定时间            按D键显示时间 \n");
}

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


三、RTC的节拍中断

节拍中断即每个RTC节拍产生一个中断
这里用到TICNT寄存器,TICNT[7]用于使能,TICNT[6:0]取值为1~127,其对应的节拍中断时间间隔为(TICNT+1)/128
这是RTC的节拍中断的实验程序,间隔时间设为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;   //允许设置
rTICNT = 1<<7 | 127 ; //允许TICK中断,每次中断时间为:  (n+1)/128 * 1秒 ,其中  n = TICNT[6:0]
rRTCCON = 0;   //禁止设置
}
void tick_INT_init(void)    //RTC报警中断初始化
{
ClearPending(1<<8);   //清除报警中断标志
pISR_TICK = (U32)tick_ISR;  //填入中断例程 于中断向量表的 报警中断向量处
rINTMSK &= ~(1<<8);   //禁止屏蔽报警中断
}
void tick_ISR(void)  __irq   //RTC报警中断例程
{
Uart_Printf("当前时间: %2x年%2x月%2x日  %s  %2x:%2x:%2x\n",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
ClearPending(1<<8);   //清除报警中断标志
}

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


结果如图




四、RTC的报警中断
报警,其实就像个闹钟,一旦当前时间(BCDYEAR……)与报警时间(ALMYEAR ……)匹配,就会引发中断
这里用到的寄存器有:
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键设定时间       按A键设定报警时间      按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);
   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键设定时间       按A键设定报警时间      按D键显示时间\n");
}
while(1);
}
void alarm_init(void)    //RTC报警中断初始化
{
ClearPending(1<<30);   //清除报警中断标志
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);   //清除报警中断标志
}
void RTC_set(void)     //RTC当前时间设置
{
Uart_Printf("设置当前时间:\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;  //设置年份为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键设定时间       按A键设定报警时间      按D键显示时间\n");
}
void RTC_alarm_set(void)   //RTC报警时间设置
{
Uart_Printf("设置报警时间:\n");

time_input();        //输入时间:年月日时分秒

rRTCCON  = rRTCCON  & ~(0xf)  | 0x1;  //使能RTC控制
   
    rALMYEAR = rALMYEAR & ~(0xff) | (year/10<<4)+year%10;  //设置年份为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键设定时间       按A键设定报警时间      按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);
}
//*******************************************************************
结果如图

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:45457 发表于 2015-9-11 19:08 | 只看该作者
2440裸机编程之六 实时时钟
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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