2440裸机编程之六 实时时钟

2019-11-09来源: 51hei关键字:2440  裸机编程  实时时钟

实时日历时钟(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);
}

[1] [2]
关键字:2440  裸机编程  实时时钟 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic479518.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:2440裸机编程之七 模数转换器ADC
下一篇:LPC1778的IAP编程源码

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

S3C2440 启动代码分析
启动代码是系统上电或复位以后运行的第一段代码,它的作用是在用户程序运行之前对系统硬件及软件运行环境进行必要的初始化并在最后使程序跳转到用户程序,它直接面对ARM 处理器内核及硬件控制器进行编程,所执行的操作与具体的目标系统紧密相关。S3C2440 支持两种方式的启动:Nor Flash 启动和Nand Flash 启动。Nor Flash 和Nand Flash 都是非易失性存储器,Nor Flash 的特点是芯片内执行,程序可以直接在其中运行,而不必将程序读取到RAM 中运行。Nor Flash 虽然具有这个优点,但是它的性价比远低于Nand Flash,因而很多系统采用Nand Flash 启动。Nand Flash 的特点是
发表于 2019-11-14
TQ2440开发板 Linux第一个驱动--点灯
我用的是TQ2440开发板,这个程序是参考韦东山的.4盏LED灯以下是驱动程序#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/arch/regs-gpio.h>#include <
发表于 2019-11-14
ARM9之2440之os-ii
  ,  10     10 , 11    11  , 10   10 , 10   10 , 10    10    rGPHCON = 0x2afaaa;    rGPHUP  = 0x7ff;    // The pull up function is disabled GPH[10:0]    // Added for S3C2440, DonGo    //PORT J GROUP   
发表于 2019-11-13
ARM9之2440时钟
其实ARM9并没有什么了不起的,和ARM7,6基本是一样的,裸奔起来并没有什么不同,个人感觉八错!倒是那万能的C语言却是真的! U32 val;U8 m, p, s;val = rMPLLCON;m = (val>>12)&0xff;p = (val>>4)&0x3f;s = val&3;//(m+8)*FIN*2 不要超出32位数!FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;val = rCLKDIVN;m = (val>>1)&3;p = val&1;     &n
发表于 2019-11-13
ARM2440的启动模式
。好了,知道这两个指令的区别之后我们来看代码是如何实现的从SRAM到SDRAM的跳转,首先需要指出,2440的开发板有SRAM和SDRAM,SRAM是从地址0x00000000开始的4KB内存空间,SDRAM是从0x30000000开始的64M空间。无论用ADS编译还是用arm-linux-gcc编译都会将代码链接到0x30000000以后(也就是SDRAM中),ADS用户可以通过查看ADS的工程配置,其中有项配置是RO起始地址是0x30000000,linux用户在链接时需要用-T指定代码的其实地址为0x30000000。根据编译原理,在链接阶段程序中函数的地址就已经确定了,也就是说函数的实际地址都在0x30000000之后,而程序
发表于 2019-11-12
S3C2440裸奔之环境搭建
首先需要搭建一个可以编译代码的环境。从一开始我就不想用ADS(安装完ADS后会产生一个CodeWarrior for ARM Developer Suite的工具,可以编译和调试代码),虽然它是个很好的工具,但是它却隐藏了很多的细节,不利于新手去深度学习。所以我还是希望从Makefile入手,一步一步弄懂所有的细节。第一步:需要先搭建一个Linux环境,我是安装在虚拟机上面的。安装好Linux后,再从网上下载arm-linux-gcc,一般解压后之后就可以直接使用了,但需要先设置好环境参数。二步:编写代码,然后在Linux系统上进行编译。代码在后面会给出。第三步:需要把编译好的bin文件烧写到板子上。这个需要使用J-Link烧录器,
发表于 2019-11-11
S3C2440裸奔之环境搭建
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved