ARM RTC实验

ARM 170浏览

 

RTC是S3C2440的内部时钟(包括定时器)。板子上有专门的电池供电。所以开发板断电下,也可以维持当前的时钟。

下面的实验是当时钟过一秒后,触发定时器(闹钟)发出一声鸣笛。

#define GLOBAL_CLK  1

#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "mmu.h"

static char enable_beep=0;
U8 month,date,weekday,hour,minute,second;
U16 year;//年份是16位长
char *week[] = {"星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
static U32 cpu_freq;
static U32 UPLL;

static void cal_cpu_bus_clk(void)
{
 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; 
 val = rCAMDIVN;
 s = val>>8;
 
 switch (m) {
 case 0:
  HCLK = FCLK;
  break;
 case 1:
  HCLK = FCLK>>1;
  break;
 case 2:
  if(s&2)
   HCLK = FCLK>>3;
  else
   HCLK = FCLK>>2;
  break;
 case 3:
  if(s&1)
   HCLK = FCLK/6;
  else
   HCLK = FCLK/3;
  break;
 }
 
 if(p)
  PCLK = HCLK>>1;
 else
  PCLK = HCLK;
 
 if(s&0x10)
  cpu_freq = HCLK;
 else
  cpu_freq = FCLK;
  
 val = rUPLLCON;
 m = (val>>12)&0xff;
 p = (val>>4)&0x3f;
 s = val&3;
 UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
 UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;
}

void Get_Rtc(void)
{
   rRTCCON = 0x01;//RTC读写使能,选择BCD时钟,计数器,无复位,1/32768

   if (rBCDYEAR==0x99)
     year=0x1999;
   else
     year = 0x2000+rBCDYEAR;

   month = rBCDMON;
   date  = rBCDDATE;
   weekday=rBCDDAY;
   hour  = rBCDHOUR;
   minute= rBCDMIN;
   second= rBCDSEC;

   rRTCCON=0x0; //RTC读写禁止,选择BCD时钟、计数器,无复位,1/32768  
}

//显示当前时间
void __irq Tick_Isr()
{
   Get_Rtc();
  
   Uart_Printf( "RTC time : %04x-%02x-%02x %s %02x:%02x:%02x/n", year, month, date,week[weekday], hour, minute, second );
   ClearPending(BIT_TICK);
}

//设置定闹钟时器
void setRTCalm(U8 almyear,U8 almmon,U8 almdate,U8 almhour,U8 almmin,U8 almsec)
{
   rRTCCON=0x0001;
   rALMYEAR = almyear;
   rALMMON  = almmon;
   rALMDATE = almdate;
   rALMHOUR = almhour;
   rALMMIN  = almmin;
   rALMSEC  = almsec;
   rRTCCON = 0; //disable RTC write
}

//设置时钟时间
void setRTCtime(U8 wRTCyear,U8 wRTCmon,U8 wRTCdate,U8 wRTCday,U8 wRTChour,U8 wRTCmin,U8 wRTCsec)
{
   rRTCCON=0x01;
   rBCDYEAR = wRTCyear;
   rBCDMON  = wRTCmon;
   rBCDDATE = wRTCdate;
   rBCDDAY  = wRTCday;
   rBCDHOUR = wRTChour;
   rBCDMIN  = wRTCmin;
   rBCDSEC  = wRTCsec;
   rRTCCON = 0; //disable RTC write
}

//开实时时钟
void OpenRtc(void)
{
   pISR_TICK = (unsigned)Tick_Isr;
   rTICNT =0xff;//Tick time interrupt enable;Tick time count value=127
   EnableIrq(BIT_TICK);//open RTC Tick interupt
}

//关实时时钟
void CloseRtc(void)
{
   rTICNT &=~(1<<7);
   DisableIrq(BIT_TICK);
}

//关闹钟函数
void CloseAlarm()
{
   rRTCALM = 0; //disable alarm
   DisableIrq(BIT_RTC);
}

//实时时钟闹钟中断
void __irq IsrAlarm()
{
  int k;
  ClearPending(BIT_RTC);
 
  Beep(2000, 100);   
  for ( k=0; k<2000;k++);
 
  CloseAlarm();
}

//开闹钟函数
void OpenAlram()
{
  pISR_RTC = (unsigned)IsrAlarm;
  ClearPending(BIT_RTC);
  rRTCALM =(0x7f);//enable alarm
  EnableIrq(BIT_RTC);
}

void Main(void)

  ChangeClockDivider(3,1);
  ChangeMPllValue(127,2,1);//405MHz
  cal_cpu_bus_clk();

  Port_Init(); 
  
  MMU_Init();
 
  Uart_Init(0,115200);
 
  setRTCalm(0x09,0x08,0x01,0x10,0x30,0x0);//这里设置16以上的数字,直接表示即可,没必要装换为16进制
  setRTCtime(0x09,0x08,0x01,0x05,0x10,0x29,0x0);

  OpenAlram();
  OpenRtc();
 
  while (1){}   
}

 

这个实验的问题是如何计算一秒的时间长呢?rTICNT =0xff;这个设置时间间隔长为1秒(1+127)/128=1秒。

rTICNT的【6:0】即为127. 另外一点是,设置日期时间超过16数值时,可以不用转换为16进制。即30可以写为0x30。年份设置只能是00-99,如果超出99,比如设置2399年,这好像是不可以的。读取的时候,年份为16位长,通过0x2000相加得到当天的具体年份。打印的时候,要用%x 不能用%d.