/***************************************************
Project: Timer0实验
Writer:SHOW
Time:2011/10/16
Hareware: 硬件平台:mini2440 , J-link.
Function: 通过定时器0实现LED1以1s的时间间隔闪烁。
Direction:这个实验主要设计的知识是定时器与定时器时钟源的设置,整个实验思路如下:
1.设置定时器时钟源PCLK大小。
2.设置定时器定时频率大小。
3.定时时间到进入中断服务函数,让lED1闪烁。
参考代码:国嵌ARM精讲第三天演示程序,JustDo的CLK实验。
参考书籍:韦东山《嵌入式linux应用开发完全手册P166。s3c2440手册。
***************************************************/
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "def.h"
#include "mmu.h"
#include "Option.h"
#define LED1_OFF (1<<5)
#define LED2_OFF (1<<6)
#define LED3_OFF (1<<7)
#define LED4_OFF (1<<8)
#define MPLL_200MHZ ((0x5c<<12) | (0x01<<4) | (0x02))
void Init_LED(void);
void __irq EintHandler(void);
void Set_TimerSourceClock_PCLK(void);
void Init_Timer0(void);
void __irq IRQ_Timer0_Handle(void);
void LED_Run(void);
//========================================================================
// 函数名称: 延时1ms子函数
// 功能描述: 延时
// 参数:times为延时的ms数。
// 返回值:void
//========================================================================
void Delay1ms(int times)
{
int i;
for( ;
times > 0;
times-- )
for(i=400;
i>0 ;
i--);
}
//========================================================================
// 函数名称: 主函数
// 功能描述: 函数入口
// 参数:void
// 返回值:void
//========================================================================
void Main(void)
{
MMU_Init();
Init_LED();
//初始化LED。
Set_TimerSourceClock_PCLK();
Init_Timer0();
while(1);
}
//========================================================================
// 函数名称: 定时器时钟源频率PCLK设置子函数
// 功能描述
完成对时钟源的设置。并且确定MPLL与PCLK大小。
// 参数:void
// 返回值:void
// PS->时钟源设置步骤: 1.定时器的时钟源由MPLL的PCLK提供。这里首先先设置MPLL为200M,通过CLKDIVN寄存器设置
// FCLK,HCLK,PCLK的的分频比,得到需要的PCLK = 50M。
//
2.MPLL的设置方法:MPLL与FCLK的设置计算公式一样,设置对应的寄存器为MPLLCON。
// MPLLCON的[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV。其中m=MDIV+8,p=PDIV+2,s=SDIV。
//
计算公式为MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)。PS: Fin为板子外接晶振频率,MIni2440的Fin = 12M。
// 总结:设置定时器时钟源是频率,步骤(1)首先设置MPLLCON确定FCLK。(2)再设置CLKDIVN确定分频比确定PCLK。一共需要设置MPLLCON和CLKDIVN两个寄存器。
//========================================================================
void Set_TimerSourceClock_PCLK(void)
{
rMPLLCON = 0;
rMPLLCON|= MPLL_200MHZ;
//MPLL = FCLK
rCLKDIVN = 0x03;
//FCLK:HCLK:PCLK = 1:2:4 => PCLK = 50MHz.
//
rMPLLCON = 0;
//
rMPLLCON |= (0x3f<<12 | 2<<4 | 2<<0);
//设置FCLK的值
//
rCLKDIVN |= (1<<2 | 1<<0);
//设置FCLK:HCLK:PCLK的比值
}
//========================================================================
// 函数名称: 定时器初始化子函数
// 功能描述: 完成对定时器0的设置与开定时器中断。
// 参数:void
// 返回值:void
// PS->定时器的设置步骤: 根据格式 定时器输出频率= PCLK/{prescaler value+1}/{divider value}
//
prescaler value = https://www.it610.com/article/0~255,divider value = 2,4,8,16。
//
1.设置定时器配置寄存器0(TCFG0)确定prescaler value。
//
2.设置定时器配置寄存器1(TGFG1)确定divider value。
//
3.设置定时器0计数缓存寄存器(TCNTB0)与比较缓存寄存器(TCMPB0)确定计数初值。
//
4.设置寄存器TCON,确定定时器工作方式,并且启动定时器。
//========================================================================
void Init_Timer0(void)
{
rTCFG0 = 49;
//prescaler = 49
rTCFG1 |= 0x03;
//divider = 16
rTCNTB0 = 62500;
//TCNTB0[15:0]=计数值50000000/49+1/16=62500
rTCON |=(1<<1);
//更新TCNTB0 和 TCMTB0的值
rTCON =0;
//将TCON的值清0,注这一步很重要,如没有,定时器将一直更新TCNTB0和TCMTB0的值导致无法启动
rTCON |= (1<<3 | 1<<0);
//启动定时器0,并设置为自动装载
ClearPending(BIT_TIMER0);
pISR_TIMER0 = (U32)IRQ_Timer0_Handle;
// 中断入口
EnableIrq(BIT_TIMER0);
//开中断
}
//========================================================================
// 函数名称: LED初始化子函数
// 功能描述: 初始化IO口 设置GPIO为输出口。
// 参数:void
// 返回值:void
//========================================================================
void Init_LED(void)
{
//
rGPBCON = 0;
复位即为0可不用先给0。
rGPBCON |= (1<<10) | (1<<12) | (1<<14) | (1<<16);
// 设置GPB5~GPB8 为输出口。
rGPBDAT |= (LED1_OFF | LED2_OFF | LED3_OFF | LED4_OFF);
// 初始化熄灭。
}
//========================================================================
// 函数名称: Timer0中断服务函数
// 功能描述: 进入中断后LED亮1s,灭1秒。
// 参数:void
// 返回值:void
//========================================================================
void __irq IRQ_Timer0_Handle(void)
{
ClearPending(BIT_TIMER0);
LED_Run();
}
//========================================================================
// 函数名称: LED闪烁函数
// 功能描述: 前后两次分别执行与或操作,使LED产生亮灭。
// 参数:void
// 返回值:void
//========================================================================
void LED_Run(void)
{
if(rGPBDAT &(1<<5))
rGPBDAT &=~(1<<5);
else
rGPBDAT |=(1<<5);
}