一、实时时钟概念
实时时钟(REAL TIME CLOCK)英文缩写也叫RTC。计算机系统通常需要一个能够记录时间的功能单元,在系统关闭后依然可以记录时间,这个功能单元就叫实时时钟单元。实时时钟通常可以提供年、月、日、时、分、秒等信息。有些还可以提供定时等功能。
开发注意事项:精度高、功耗低、抗干扰、温度漂移 --> 以此保证时间的精准
1、S3C2440实时时钟单元
BCD码的年、月、日、星期、小时、分钟、秒输出功能
- Alarm定时唤醒功能
- 独立的电源供电管脚(RTCVDD)
- 为RTOS提供毫秒级的定时
- 时钟晶振选取32.768HZ
2、实时时钟操作
二、实战演练——初始化时钟(rtc_basic)
area Init,code, readonly
code32
entry
start
ldr sp, =0x34000000
import Main
b Main
stop
b stop
end
#include "2440addr.h"
/*
tclk = pclk / ((pre + 1) * div)
fout = 1kHz
pclk = 50MHz
pre = 15
div = 8
1/fout = count * (1/tclk)
1/fout = count * ((pre+1) * div) / pclk
count = pclk / (fout*(pre+1)* div)
= 50Mhz / (1KHz * 16 * 8)
= 390.625 = 391
*/
/*
*/
#define PCLK 50000000
unsigned int gFre[7] =
{500, 650, 880, 1000, 1200, 1400, 1600};
void setFre(int fre)
{
// 定时器配置
rTCFG0 |= (15<<0); // pre = 15
rTCFG1 |= (2<<0); // div = 8
rTCNTB0 = PCLK / (fre * 16 * 8);
rTCMPB0 = rTCNTB0 >> 1; // 占空比50%开发板
rTCON |= (1<<3) | (1<<1) | (1<<0); // 自动加载,手动更新,启动定时器。
rTCON &= ~(1<<1); // 关闭手动加载
}
void toutIoCfg(void)
{
// 引脚配置
rGPBCON &= ~(3<<0);
rGPBCON |= (2<<0); // 配置为tout0功能
}
void tout0Init(void)
{
// 引脚配置
rGPBCON &= ~(3<<0);
rGPBCON |= (2<<0); // 配置为tout0功能
// 定时器配置
rTCFG0 |= (15<<0); // pre = 15
rTCFG1 |= (2<<0); // div = 8
rTCNTB0 = 391;
rTCMPB0 = rTCNTB0 >> 1; // 占空比50%
rTCON |= (1<<3) | (1<<1) | (1<<0); // 自动加载,手动更新,启动定时器。
rTCON &= ~(1<<1); // 关闭手动加载
}
void delay(unsigned int loops)
{
while(loops-->0);
}
void Main(void)
{
int i=0;
toutIoCfg();
while(1)
{
for(i=0; i<7; i++)
{
setFre(gFre[i]);
delay(0x10000000);
}
}
}
三、实战演练——闹钟功能(rtc_alarm)
start.s
同rtc_basic_start.s
rtc.c
在之前的基础上更改,主要是alarmInit()函数
#include "2440addr.h"
#include "uart0.h"
#include "mmu.h"
void __irq alarm_irq_handler(void);
void __irq tick_irq_handler(void);
#define pISR_alarm (*((unsigned int *) (0x33FFFF98)))
#define pISR_tick (*((unsigned int *) (0x33FFFF20 + 32)))
void setRTC(void)
{
rRTCCON = 1; // 使能读写
rBCDYEAR = 0x17; // 年
rBCDMON = 0x03;
rBCDDATE = 0x09;
rBCDDAY = 0x4;
rBCDHOUR = 0x14;
rBCDMIN = 0x07;
rBCDSEC = 0x10;
rRTCCON = 0; // disable 读写
}
void displayRTC(void)
{
unsigned char year, month, date, hour, minute, second, day;
//rRTCCON = 1;
year = rBCDYEAR ; //年
month = rBCDMON ; //月
date = rBCDDATE ; //日
day = rBCDDAY ; //星期
hour = rBCDHOUR ; //小时
minute = rBCDMIN ; //分
second = rBCDSEC ; //秒
//rRTCCON &= ~1 ;
Uart0_Printf("%04x-%02x-%02x %02x:%02x:%02x 星期%x\r\n",\
0x2000+year, month, date, hour, minute, second, day);
}
void alarmInit(void)
{
rRTCALM |= (1<<0) | (1<<6); // SEC 使能,总 使能
rALMSEC = rBCDSEC + 5; // 程序下载5s后闹铃
// 初始化中断
pISR_alarm = (unsigned int)alarm_irq_handler; // 存入汇编的地址表里
rINTMSK &= ~(1<<30); // 使能INT_RTC
rSRCPND |= (1<<30);
}
void tickInit(void)
{
rTICNT = (1<<7) | 127; // 使能tick, 计数值127
// 中断控制器
rINTMSK &= ~(1<<8);
rSRCPND |= (1<<8);
rINTPND |= (1<<8);
pISR_tick = (unsigned int)tick_irq_handler;
}
void __irq tick_irq_handler(void)
{
displayRTC();
rSRCPND = rSRCPND;
rINTPND = rINTPND;
}
// 热启动 : 延时5s
// 中断服务程序
void __irq alarm_irq_handler(void)
{
tickInit();
//rSRCPND = (1<<30);
//rINTPND = (1<<30);
//rSRCPND |= (1<<30);
//rINTPND |= (1<<30);
rSRCPND = rSRCPND;
rINTPND = rINTPND;
rRTCALM = 0;
}
void Main(void)
{
MMU_Init();
uart0_init();
setRTC();
alarmInit();
//displayRTC();
while(1);
} area Init, code, readonly
code32
entry
b start
nop
nop
nop
nop
nop
nop
nop
start
ldr sp, =0x34000000
import Main
b Main
stop
b stop
end