历史上的今天
返回首页

历史上的今天

今天是:2024年11月09日(星期六)

正在发生

2019年11月09日 | 2440裸机编程之六 实时时钟

2019-11-09 来源:51hei

实时日历时钟(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显示nn");

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:%2xn",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
}

}


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


运行结构如图:


二、RTC的设置
其实就是写年月日这些寄存器,没什么复杂的地方
//********************************************************************
const char week[][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};

void Main(void)
{     
    int i;
    ……硬件初始化……

Uart_Printf("RTC设置时间nn");
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:%2xn",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
  else Uart_Printf("无效的输入!        按S键设定时间            按D键显示时间nn");
}
while(1);
}


void RTC_set(void)
{
do
{
  Uart_Printf("输入年份:");
  year = Uart_GetIntNum();  //输入年份
}
while(year>99);
Uart_Printf("年份:%dn",year);

do
{
  Uart_Printf("输入月份:");
  month = Uart_GetIntNum();
}
while(month<1 || month>12);
Uart_Printf("月份:%dn",month);

do
{
  Uart_Printf("输入日:");
  date = Uart_GetIntNum();
}
while(date<1 || date>31);
Uart_Printf("日:%dn",day);

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

do
{
  Uart_Printf("输入小时:");
  hour = Uart_GetIntNum();
}
while(hour>23);
Uart_Printf("小时:%dn",hour);

do
{
  Uart_Printf("输入分:");
  minute = Uart_GetIntNum();
}
while(minute>59);
Uart_Printf("分:%dn",minute);

do
{
  Uart_Printf("输入秒:");
  second = Uart_GetIntNum();
}
while(second>59);
Uart_Printf("秒:%dn",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中断nn");

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:%2xn",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:%2xn",rBCDYEAR,rBCDMON,rBCDDATE,week[rBCDDAY-1],rBCDHOUR,rBCDMIN,rBCDSEC);
   Uart_Printf("报警时间: %2x年%2x月%2x日          %2x:%2x:%2xn",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("%sn",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");
}

推荐阅读

史海拾趣

亿宝科技(CNIBAO)公司的发展小趣事

在技术创新的基础上,亿宝科技积极拓展市场。公司通过与国内外知名企业的合作,将产品打入国际市场。同时,亿宝科技还注重品牌建设,通过参加各类展会、举办技术研讨会等方式,提升品牌知名度和影响力。在一次国际电子展上,亿宝科技的产品凭借其卓越的性能和品质,赢得了众多客户的青睐,成功打开了国际市场的大门。

CHONGQING PINGYANG ELECTRONICS CO.,LTD.公司的发展小趣事

2005年,重庆平洋电子有限公司迎来了一个重要的合作机会。经过严格的筛选和谈判,公司与海尔集团达成了先期采购协议,成为海尔集团在重庆市唯一一家免第三方认证的企业。这一合作不仅为公司带来了稳定的订单和收益,还进一步提升了公司的品牌影响力和市场竞争力。

EDAL公司的发展小趣事

EDAL公司始终秉持持续创新和客户至上的理念。公司不断投入研发资源,推出新的EDA产品和解决方案,满足客户的多样化需求。同时,EDAL公司还建立了完善的客户服务体系,为客户提供全方位的技术支持和解决方案。这些举措不仅增强了客户对EDAL公司的信任和忠诚度,还为公司的长期发展奠定了坚实的基础。

Advanced_Linear_Devices_Inc.公司的发展小趣事

随着市场需求的不断增长,ALD不断拓展其产品线。除了最初的CMOS线性集成电路外,公司还研发出了轨到轨运算放大器、双斜率A/D前端转换器、电压比较器等一系列产品。这些产品不仅满足了不同行业的需求,还进一步提升了ALD在电子行业的市场地位。同时,公司还针对特定应用,如医疗仪器和汽车领域,推出了定制化的解决方案,赢得了客户的广泛赞誉。

EPIC公司的发展小趣事

Epic Games一直关注并支持独立游戏开发者的发展。过去,独立开发者有机会与Epic Store签订协议以获得财务支持或提高游戏的知名度。然而,随着市场环境的变化和金融合约结构的转变,独立开发者面临着越来越多的挑战。尽管如此,Epic Games仍然致力于提供支持和资源来帮助独立开发者克服障碍、实现创新并推动整个游戏行业的进步。通过与独立开发者的紧密合作和持续支持,Epic Games不仅促进了游戏行业的多样性发展,也为自己赢得了广泛的好评和声誉。

Hitachi Metals公司的发展小趣事

自1956年成立以来,Hitachi Metals便逐步在电子材料领域建立了坚实的基础。公司早期便专注于研发和生产用于电子设备的核心部件,如磁性材料。随着电子行业的蓬勃发展,日立金属迅速抓住了市场机遇,推出了高性能的Nd-Fe-B系列烧结磁石和高性能铁氧体烧结磁石,这些材料广泛应用于计算机、半导体集成电路器件及平板显示屏等高科技产品中。凭借其卓越的产品质量和稳定的市场供应,Hitachi Metals在电子材料市场上赢得了广泛的认可。

问答坊 | AI 解惑

STK500下载器的烧录文件

注意:以下的烧录文件,仅用于手工升级的STK500下载器,如我们邮购部供应的STK500下载器(手工升级版)。…

查看全部问答>

求助,有谁能解释这种现象!

我用单片机的IO口经过通过8050三极管驱动继电器,单片机上电后就让IO口输出高电平,希望继电器有动作,结果就是没有动作,必须先置低IO口后再输出高电平才能得到自己想要的效果,到现在我也不明白什么为什么。而且继电器线圈的放电二极管我也加上了 ...…

查看全部问答>

想买正版MDK —可听说出 μVision4 了! 大家比较一下和μVision3 有什么区别

首先说明一下不是做广告    本来想购买 RealView MDK呢,在和代理商沟通中无意得知要出 μVision4 于是想等待观望 1、如果现在购买了mdk  是mdk4.0的版本 ulink2仿真机      μVision4 是否支持 ul ...…

查看全部问答>

BIOS研发技术剖析

这是一本老书,献给致力于BIOS开发的人,据说台湾有第二版了,不知哪位大侠能搞到。 …

查看全部问答>

2010年英特尔杯大学生电子设计竞赛嵌入式系统专题邀请赛实施细则

本帖最后由 paulhyde 于 2014-9-15 08:59 编辑 一、参赛学生的培训与报名 1、本次专题邀请赛的时间从2010年3月18日开始,到6月30日结束,评审工作在7月底完成,参加本次专题竞赛的学生,在竞赛期间必须是普通高校全日制在校本科学生,评审时,如 ...…

查看全部问答>

双网卡下的组播通讯问题

最近在做一个组播通讯的程序。我在有一个网卡的学习板上编写了程序,并且可以在PC上获得该网卡发出的数据,但是我将程序下载到有双网卡的板子上运行就会出现不能接收的问题。而后我在双网卡的板子上进行了单播和广播的测试,PC均能收到数据,唯独组 ...…

查看全部问答>

GPRS猫

有几个关于GPRS猫的问题请教大家: 1、中国移动的APN有两种cmwap和cmnet,我通过AT+CGDCONT=1,\"IP\",\"XXXXX\"命令设置(XXXXX代表cmwap或cmnet),然后用ATD拨号,得到的服务器段IP地址都是一样的192.168.111.111,说明我连接的是同一个服务器, ...…

查看全部问答>

嵌入式linux入门学习(北京9.22,上海10.27)

1天的学习时间,比较适合想学习嵌入式linux却无从下手的初学者,可以系统全面了解嵌入式开发流程,入门解惑,为将来进行嵌入式linux的深化学习打下良好基础。 感兴趣的朋友请关注:http://www.farsight.com.cn/courses/TS-LinuxBasic.aspx…

查看全部问答>