从S5PV210学习最基础的定时器(RTC篇)

注:下文都以S5PV210为背景。

      本文只学习RTC的读取和设置还有闹钟功能。


      RTC,一个较为特殊的定时器,其他定时器都是定的时间段,而RTC定的是时间点。

一.RTC介绍

     (1)real time clock,真实时间,就是所谓的xx年x月x日x时x分x秒星期x
     (2)RTC是SoC中一个内部外设,RTC有自己独立的晶振提供RTC时钟源(32.768KHz),内部有一些寄存器用来记录时间(年月日时分秒星期)。一般情况下为了在系统关机时时间仍然在走,还会给RTC提供一个电池供电。

     (3)RTC的时间寄存器们(SEC,MIN,HOUR,YEAR...)使用的是BCD码保存时间数据。

注:什么是BCD码?

   (1)RTC中所有的时间(年月日时分秒星期,包括闹钟)都是用BCD码编码的。
   (2)BCD码本质上是对数字的一种编码。用来解决这种问题:由56得到0x56(或者反过来)。也就是说我们希望十进制的56可以被编码成56(这里的56不是十进制56,而是两个数字5和6).
   (3)BCD码的作用在于可以将十进制数拆成组成这个十进制数的各个数字的编码,变成编码后就没有位数的限制了。譬如我有一个很大的数123456789123456789,如果这个数纯粹当数字肯定超出了int的范围,计算机无法直接处理。要想让计算机处理这个数,计算机首先得能表达这个数,表达的方式就是先把这个数转成对应的BCD码(123456789123456789)
   (4)BCD码在计算机中可以用十六进制的形式来表示。也就是说十进制的56转成BCD码后是56,在计算机中用0x56来表达(暂时存储与运算)。 

 (5)所以我们需要写两个函数进行十进制和BCD的互转,示例代码如下:

static unsigned int bcd_2_dec(unsigned int bcd)
{
    volatile unsigned int dec_h, dec_l;
    dec_h = ((bcd &(0xf << 4))>>4);
    dec_l = bcd&0xf;
    
    return dec_h*10 + dec_l;
}


static unsigned int dec_2_bcd(unsigned int dec)
{
    return ((dec/10)<<4)|(dec%10);
}



 二.S5PV210的RTC

     (1)看图说话:

     从S5PV210学习最基础的定时器(RTC篇)_第1张图片      

      分析:

       (1)使用独立的晶振。

       (2)对外可以输出两种TICK信号:TICK中断和TICK唤醒。

       (3)对外可以输出两种ALARM信号:ALARM中断和ALARM唤醒。


      Time Tick Generator:产生tick,说明这个RTC可以用来生成tick给操作系统用。

      Clock Divider:分频器,但RTC的分频器是设定好了的,所以软件操作不需要设置。

      Control Register:控制各大部门的,主要是用来控制enable和disable。

      Reset Register:复位。

      Leap Year Generator:闰年生成器。

      Alarm Generator:闹钟生成器。

      SEC,MIN,HOUR...:记录各个时间级的寄存器。


       (2)重要寄存器和操作注意

          重要寄存器简介:

       (1)INTP 中断挂起寄存器
       (2)RTCCON RTC控制寄存器
       (3)RTCALM ALMxxx 闹钟功能有关的寄存器
       (4)BCDxxx   时间寄存器

         操作注意:

     (1)基础使用的RTC是不需要初始化的。

    (2)为了避免RTC的时间寄存器被误操作,所以默认情况下RTC读写是禁止的,因此当我们要更改RTC时间时,应该先打开RTC的读写开关,然后再进行读写操作,操作完了后立即关闭读写开关。

     (3)RTC各个时间级的ALARM是独立的,如:只使用ALMSEC,并设置ALMSEC为1,那么每次SEC为1是都会发出中断。

     三.实战编程

      

void rtc_set_time(const struct rtc_time *p)
{
    // 第一步,打开RTC读写开关
    rRTCCON |= (1<<0);
    
    // 第二步,写RTC时间寄存器
    rBCDYEAR = num_2_bcd(p->year - 2000);
    rBCDMON = num_2_bcd(p->month);
    rBCDDATE = num_2_bcd(p->date);
    rBCDHOUR = num_2_bcd(p->hour);
    rBCDMIN = num_2_bcd(p->minute);
    rBCDSEC = num_2_bcd(p->second);
    rBCDDAY = num_2_bcd(p->day);
    
    // 最后一步,关上RTC的读写开关
    rRTCCON &= ~(1<<0);
}

void rtc_get_time(struct rtc_time *p)
{
    // 第一步,打开RTC读写开关
    rRTCCON |= (1<<0);
    
    // 第二步,读RTC时间寄存器
    p->year = bcd_2_num(rBCDYEAR) + 2000;
    p->month = bcd_2_num(rBCDMON);
    p->date = bcd_2_num(rBCDDATE);
    p->hour = bcd_2_num(rBCDHOUR);
    p->minute = bcd_2_num(rBCDMIN);
    p->second = bcd_2_num(rBCDSEC);
    p->day = bcd_2_num(rBCDDAY);
    
    // 最后一步,关上RTC的读写开关
    rRTCCON &= ~(1<<0);
}

void rtc_set_alarm(void)
{
    rALMSEC = num_2_bcd(23);
    rRTCALM |= 1<<0;
    rRTCALM |= 1<<6;
}

void isr_rtc_alarm(void)
{
    static int i = 0; 
    printf("rtc alarm, i = %d...", i++);
    
    rINTP |= (1<<1);
    intc_clearvectaddr();
}
     需要注意的:

        (1)读取时间,都需要使能RTCEN。

        (2)RTC是使用BCD码,而人是使用十进制,所以要进行转码。

       (3)RTC的闹钟是使用哪个就设置哪个,并开启ALMEN(闹钟功能)和对应的闹钟(如SEC就是SECEN)。






          




你可能感兴趣的:(S5PV210)