Cortex-M3 (NXP LPC1788)之SysTick系统节拍定时器

        在GPIO控制篇中的延时闪烁LED只用了简单的for循环,为了精确的计时本篇介绍使用SysTick定时器每1ms产生中断,从而实现精确定时的目的。要使用系统节拍定时器主要进行两个部分的配置。1:系统时钟控制。2系统节拍定时器的控制。

一,系统时钟控制

        LPC1788有3个独立的振荡器。他们是主振荡器,内部RC振荡器,RTC振荡器。复位后,LPC1788将用内部的RC振荡器运行,直到被软件切换。这样就能在没有任何外部晶振的情况下运行。LPC1788的时钟控制如图1所示


        在开发板上使用12M的晶振作为主振荡器,它通过锁相环PLL0来提高频率提供CPU。由于芯片总是从内部的RC振荡器开始工作,因此主振荡器只会应软件的请求而启动。实现方法是设定SCS寄存器中的OSCEN位使能。主振荡器提供一个状态标志SCS寄存器的OSCSTAT位,这样软件就可以确定何时主振荡器在运行稳定。此时,软件可以控制切换到主振荡器,使其作为时钟源。在启动以前,必须通过SCS的OSCRANGE位,选择一个频率范围。在确定了主振荡器之后,需要进行锁相环的配置。1,配置CLKSRCSEL选择正确的时钟源。2,将正确的PLL设置值写入PLLCFG寄存器并且在PLLCON中使能PLL。3,向PLLFEED寄存器中写入馈送序列0xAA,0x55。4,设置所需的时钟分配器如CCLKSEL,PCLSEL,EMCCLKSEL,以及USBCLKSEL寄存器。5,查询PLLSTAT寄存器等待PLL锁定。

二,系统节拍定时器的控制

        LPC1788的系统节拍定时器是一个24位的定时器,当数值达到0时产生中断。系统节拍定时器的时钟信号可以由CPU时钟提供(即图1中的cclk)。想要在规定的时间间隔循环的产生中断,必须将指定的正确时间间隔值装入STRELOAD寄存器进行初始化。假如我们选择cclk作为系统节拍的时钟信号,并且根据开发板将系统时钟设置成12MHZ,为了循环1ms产生一次中断,我们写入STRELOAD的值为cclk/1000 - 1 。


        程序的代码如下,使LED灯每500ms闪烁。SystemInit函数在启动文件中被调用。

#define rFIO1DIR		(*(volatile unsigned*)0x20098020)
#define rFIO1MASK 		(*(volatile unsigned*)0x20098030)
#define rFIO1PIN		(*(volatile unsigned*)0x20098034)
#define rFIO1SET		(*(volatile unsigned*)0x20098038)
#define rFIO1CLR		(*(volatile unsigned*)0x2009803c)

#define rCLKSRCSEL	(*(unsigned *)(0x400FC10C))		//时钟源选择寄存器
#define rPLL0CON	(*(unsigned *)(0x400FC080))		//PLL0控制寄存器
#define rPLL0CFG	(*(unsigned *)(0x400FC084))		//PLL0配置寄存器
#define rPLL0STAT	(*(unsigned *)(0x400FC088))		//PLL0状态寄存器
#define rPLL0FEED	(*(unsigned *)(0x400FC08C))		//PLL0馈送寄存器
#define rPLL1CON	(*(unsigned *)(0x400FC0A0))		
#define rPLL1CFG	(*(unsigned *)(0x400FC0A4))
#define rPLL1STAT	(*(unsigned *)(0x400FC0A8))
#define rPLL1FEED	(*(unsigned *)(0x400FC0AC))
#define rCCLKSEL	(*(unsigned *)(0x400FC104))		//CPU时钟选择寄存器
#define rUSBCLKSEL	(*(unsigned *)(0x400FC108))		//USB时钟选择寄存器
#define rPCLKSEL	(*(unsigned *)(0x400FC1A8))		//外设时钟寄存器
#define rPCON		(*(unsigned *)(0x400FC0C0))
#define rPXCONP		(*(unsigned *)(0x400FC0C4))
#define rSCS		(*(unsigned *)(0x400FC1A0))		//系统控制和状态寄存器
#define rCLKOUTCFG	(*(unsigned *)(0x400FC1C8))

#define rSTCTRL		(*(unsigned *)(0xE000E010))
#define rSTRELOAD	(*(unsigned *)(0xE000E014))
#define rSTCURR		(*(unsigned *)(0xE000E018))
#define rSTALIB		(*(unsigned *)(0xE000E01C))

#define CCLK		120000000

volatile unsigned long SysTickCnt;

/*
系统时钟初始化
*/
void SystemInit()
{
	rSCS &= ~(0x1<<4);				//频率12M
	rSCS |= (0x1<<5);				//使能主振荡器
	while(0 == (rSCS & (0x1<<6)));//等待主振荡器稳定
	
	rCLKSRCSEL = 0x1;
	
	rPLL0CFG = 0x9;					//配置CCLK = 120M
	rPLL0CON = 0x01;
	rPLL0FEED = 0xAA;
	rPLL0FEED =0x55;
	while( 0 == (rPLL0STAT & (0x1<<10))); 
	
	rCCLKSEL = (0x1 | (0x1<<8));
	rPCLKSEL = 0x2;					//配置PCLK = 60M
	
	rCLKOUTCFG = 0x0 | (0xb<<4) | (0x1<<8);
}

/*
系统节拍定时器初始化
*/
unsigned char SysTick_Config(unsigned int ticks)
{
	if(ticks > 0xFFFFFFUL)
		return 0;
	rSTRELOAD = ticks;
	rSTCURR = 0x0;
	rSTCTRL = (0x1) | (0x1<<1) | (0x1<<2);
	return 1;
}
/*
系统节拍定时器中断处理函数
*/
void SysTick_Handler (void)
{
	SysTickCnt++;
}

int main()
{
	unsigned char value = 1;

	SysTick_Config(CCLK/1000-1);			//每1ms产生一次SysTick系统异常	
	rFIO1DIR |= (1<<18); 				//GPIO1.18 -> OUTPUT
	
	while(1)
	{
		if(SysTickCnt >= 500)
		{
			SysTickCnt = 0;
			value = !value;
		}
		if(0 == value)
		{
			rFIO1PIN &= ~(1<<18);
		}
		else if(1 == value)
		{
			rFIO1PIN |= (1<<18);
		}
	}
}

        关于SysTick的异常的优先级可以在SHPR3中进行设置,优先级等级可以从0~31。初始化默认为0,只低于固定的负数优先级的复位,硬件故障和NMI。

你可能感兴趣的:(Cortex-M3 (NXP LPC1788)之SysTick系统节拍定时器)