TQ2440裸机中断(定时器TIMER0中断)

1.S3C2440定时器知识   

    在讲解之前,先介绍一下s3c2440时钟系统。一般来说,MCU的主时钟源主要是外部晶振或外部时钟,而用的最多的是外部晶振。在正确情况下,系统内所使用的时钟都是外部时钟源经过一定的处理得到的。由于外部时钟源的频率一般不能满足系统所需要的高频条件,所以往往需要PLL(锁相环)进行倍频处理。

    在s3c2440中,有2个不同的PLL,一个是MPLL,另一个是UPLL。UPLL是给USB提供48MHz。在这里,我们主要介绍MPLL。外部时钟源经过MPLL处理后能够得到三个不同的系统时钟:FCLK、HCLK和PCLK。FCLK是主频时钟,用于ARM920T内核;HCLK用于AHB总线设备,如ARM920T,内存控制,中断控制,LCD控制,DMA以及USB主模块;PCLK用于APB总线设备,如外围设备的看门狗,IIS,I2C,PWM,MMC接口,ADC,UART,GPIO,RTC以及SPI。这三个系统时钟(FCLK、HCLK和PCLK)是有一定的比例关系,这种关系是通过寄存器CLKDIVN中的HDIVN位和PDIVN位来控制的,因此我们只要知道了FCLK,再通过这两位的控制,就能确定HCLK和PCLK。而FCLK是如何得到的呢?它是通过输入时钟(即外部时钟源)的频率,经过一个计算公式(具体公式请查阅数据手册)得到的,这个计算公式还需要三个参数(MDIV、PDIV、SDIV),而这三个参数是经过寄存器MPLLCON配置得到的。最后,我们用最清晰的线路来绘制一下时钟的产生过程:

外部时钟源通过寄存器MPLLCON得到FCLK再通过寄存器CLKDIVN得到HCLK和PCLK

    这个配置过程在启动文件中就已完成。在TQ2440开发板上,外部晶振为12MHz,进过MPLL倍频以后得到400MHz的FCLK,而FCLK、HCLK、PCLK之间的比例关系为1:4:8,因此HCLK为100MHz,PCLK为50MHz。

s3c2440的时钟系统就介绍到这里,我们再回到定时器的配置上来。如何才能得到精确的定时呢?那就要靠TCFG0和TCFG1这两个寄存器来配置定时器的频率(TCFG0预分频,TCFG1分频),即要确定TCNTOn每递减一个数所需要的时间,它们之间是倒数的关系。具体的计算公式为:

定时器输出时钟频率=PCLK ÷ (prescaler+1) ÷ divider

其中prescaler值由TCFG0决定,divider值由TCFG1决定,而prescaler只能取0~255之间的整数,divider只能取2、4、8和16。比如已知PCLK为50MHz,而我们想得到某一定时器的输出时钟频率为25kHz,则依据公式可以使prescaler等于249,divider等于8。有了这个输出时钟频率,理论上我们通过设置寄存器TCNTBn就可以得到任意与0.04毫秒(1÷25000×1000)成整数倍关系的时间间隔了。例如我们想要得到1秒钟的延时,则使TCNTBn为25000(1000÷0.04)即可。

 

2.代码分析

代码地址:http://download.csdn.net/detail/forsakening/5490447

TCON寄存器中关于TIMER0的部分:

/* TIMER0控制LED灯闪烁 */

#include "2440addr.h"

#define _ISR_STARTADDRESS 	0x33ffff00 

static unsigned int flag = 1;

/*****************************************************************/
/* LED部分 */
/*****************************************************************/
#define Led1_On()      {rGPBDAT &= (~(1 << 5));} 
#define Led1_Off()     {rGPBDAT |= (1 << 5);} 
#define Led2_On()      {rGPBDAT &= (~(1 << 6));} 
#define Led2_Off()     {rGPBDAT |= (1 << 6);} 
#define Led3_On()      {rGPBDAT &= (~(1 << 7));} 
#define Led3_Off()     {rGPBDAT |= (1 << 7);} 
#define Led4_On()      {rGPBDAT &= (~(1 << 8));} 
#define Led4_Off()     {rGPBDAT |= (1 << 8);} 

void Led_Init(void)
{
	rGPBCON &= ~((3 << 10) | (3 << 12) | (3 << 14) |(3 << 16));
	rGPBCON |= ((1<<10) | (1<<12) | (1<<14) | (1<<16)) ;
	rGPBUP  &=  ~((1 << 5) | (1 << 6) | (1 << 7) || (1 << 8) ) ;
	rGPBDAT |= (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) ;
}

/*****************************************************************/
/* 定时器部分 */
/*****************************************************************/
/*
 * 启动代码中已经设置了系统时钟,PCLK = 50M
 * 若TIMER0获得25KHZ的时钟源,选择分频50M/25K = 2000
 * 2000 = 250 * 8 ,所以prescaler等于249,divider等于8
 * TCFG0控制预分频,TCFG1控制分频
 * TCNTB0/TCMPB0定时器0计数缓冲寄存器和比较缓冲寄存器
 * 详细参看S3C2440寄存器手册
 */
void Timer0_Init(void)
{
	rTCFG0 &= ~(0xff) ;
	rTCFG0 |= 249 ;
	rTCFG1 &=  ~(0xf) ;
	rTCFG1 |=  0X02 ;
	rTCNTB0 =  12500 ;//0.5s中断一次
	
	rTCON |= (1 << 1) ;//手动更新
	rTCON =  0x09 ; //自动加载,清除手动更新位,启动定时器	
}

/*****************************************************************/
/* 中断部分: */
/*****************************************************************/
/*
 * 开启定时器0中断INTMSK第10位是TIMER0的标志位
 */
void Timer0_Interrupt_Init(void)
{
	rSRCPND = rSRCPND | (0x1<<10);
    rINTPND = rINTPND | (0x1<<10); 
	rINTMSK &= ~(1 << 10) ;
}
/*****************************************************************/

/*****************************************************************/
/*
 * 中断处理:关闭LED1,记得清除中断
 */
void __irq Timer0_Isr(void)
{
	flag = !flag;
	
	if (flag)
	{
		Led1_On();
	}
	else
	{
		Led1_Off();
	}

	rSRCPND |= 1 << 10 ;
	rINTPND |= 1 << 10 ;
}

void Isr_Init(void)
{
	pISR_TIMER0 = (unsigned int)Timer0_Isr ;	
}
/*****************************************************************/

void IO_Init()
{
	Led_Init() ;
	Isr_Init() ;
	Timer0_Interrupt_Init();
	Timer0_Init();
}

int Main()
{
	IO_Init() ;
	
	while(1);

	return 0;	
}


3.后记

1)理论知识部分主要参考:http://blog.csdn.net/zhaocj/article/details/5323728

2)[MARK]这里有个问题,明明设置的是0.5s的定时,但是实际运行起来感觉超过0.5s,可能是启动代码中设置系统时钟不精确的原因吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值