1. 首先晓得RTC的基本知识
RTC被划分到timer,但RTC是面向时间点的。
如果按照定时器的思路去思考,那么应该考虑 时间周期 和 计数值。
RTC 不是面向时间点的,所以略有不同,
时间周期,RTC通过自己独立的晶振提供,并且晶振的频率都为 32.768KHZ
计数值,RTC的计数值不是用来定时,而是用来计时,RTC记录 年 月 日 时 分 秒 星期。(其中年是有一个基准值,如2000)
此外,RTC一般有独立的电池,保证掉电后继续计时。
整理下思路:
我们知道对于timer,我们需要设置时间周期和计数值,
但是对于RTC,时间周期已经设置好了,所以只需要考虑计数值。
2.对RTC计数值的设置
在数据手册可以找到这张图
可以看出
RTC计数值分为 年 月 日 时 分 秒 星期,每个都是用独立的寄存器保存。
所以对RTC计数值的设置就是通过 Control Register 设置那几个寄存器。
此外还需要知道 RTC 的时间使用 BCD 码表示,所以涉及 十进制和BCD码的转换
BCD码就是对数字编码,使用类似字符串的方式表示数字,如 0x56 的BCD码意义是 56.
转换方式:
static unsigned int num_2_bcd(unsigned int num) { return (((num / 10)<<4) | (num % 10)); } static unsigned int bcd_2_num(unsigned int bcd) { return (((bcd & 0xf0)>>4)*10 + (bcd & (0x0f))); }
有了思路后,开始完成 读写RTC 时间的实验
#define RTC_BASE (0xE2800000) #define rINTP (*((volatile unsigned long *)(RTC_BASE + 0x30))) #define rRTCCON (*((volatile unsigned long *)(RTC_BASE + 0x40))) #define rTICCNT (*((volatile unsigned long *)(RTC_BASE + 0x44))) #define rRTCALM (*((volatile unsigned long *)(RTC_BASE + 0x50))) #define rALMSEC (*((volatile unsigned long *)(RTC_BASE + 0x54))) #define rALMMIN (*((volatile unsigned long *)(RTC_BASE + 0x58))) #define rALMHOUR (*((volatile unsigned long *)(RTC_BASE + 0x5c))) #define rALMDATE (*((volatile unsigned long *)(RTC_BASE + 0x60))) #define rALMMON (*((volatile unsigned long *)(RTC_BASE + 0x64))) #define rALMYEAR (*((volatile unsigned long *)(RTC_BASE + 0x68))) #define rRTCRST (*((volatile unsigned long *)(RTC_BASE + 0x6c))) #define rBCDSEC (*((volatile unsigned long *)(RTC_BASE + 0x70))) #define rBCDMIN (*((volatile unsigned long *)(RTC_BASE + 0x74))) #define rBCDHOUR (*((volatile unsigned long *)(RTC_BASE + 0x78))) #define rBCDDATE (*((volatile unsigned long *)(RTC_BASE + 0x7c))) #define rBCDDAY (*((volatile unsigned long *)(RTC_BASE + 0x80))) #define rBCDMON (*((volatile unsigned long *)(RTC_BASE + 0x84))) #define rBCDYEAR (*((volatile unsigned long *)(RTC_BASE + 0x88))) #define rCURTICCNT (*((volatile unsigned long *)(RTC_BASE + 0x90))) #define rRTCLVD (*((volatile unsigned long *)(RTC_BASE + 0x94))) typedef struct rtc_time{ unsigned int year; unsigned int mon; unsigned int day; unsigned int hour; unsigned int min; unsigned int sec; unsigned int date; }rtc_time; static unsigned int num_2_bcd(unsigned int num) { return ((num / 10) << 4) | (num % 10); } static unsigned int bcd_2_num(unsigned int bcd) { return ((bcd >> 4) * 10) + (bcd & 0x0f); } void rtc_set_time(rtc_time t) { // 开启RTC设置 rRTCCON |= 1 << 0; rBCDSEC = num_2_bcd(t.sec); rBCDMIN = num_2_bcd(t.min); rBCDHOUR = num_2_bcd(t.hour); rBCDDAY = num_2_bcd(t.day); rBCDDATE = num_2_bcd(t.date); rBCDMON = num_2_bcd(t.mon); rBCDYEAR = num_2_bcd(t.year); // 关闭RTC设置 rRTCCON &= ~(1 << 0); } void rtc_get_time(rtc_time *t) { // 开启RTC设置 rRTCCON |= 1 << 0; t->sec = bcd_2_num(rBCDSEC); t->min = bcd_2_num(rBCDMIN); t->hour = bcd_2_num(rBCDHOUR); t->day = bcd_2_num(rBCDDAY); t->date = bcd_2_num(rBCDDATE); t->mon = bcd_2_num(rBCDMON); t->year = bcd_2_num(rBCDYEAR); // 关闭RTC设置 rRTCCON &= ~(1 << 0); }
从下面这张图中,还可以看出,RTC带有闹钟功能,能产生闹钟中断,现在来使用RTC闹钟功能
void rtc_sec_alarm() { rALMSEC = num_2_bcd(13); // 这样在每分钟的 13 秒都会发出ALRM中断 rRTCALM |= (1 << 6) | (1 << 0); } void isr_rtc_sec() { printf("isr_rtc_sec\n"); intc_clearvectaddr(); rINTP |= (1 << 1); }