这两天在学LPC2103的定时器,其中要用到中断这一功能,看了例子后,感觉ARM的中断设置可是真复杂啊,看了两天我才稍微有一点明白。
lpc2103的向量中断寄存器(VIC)有32个中断请求输入,可将其分为3类:FIQ(快速中断)、向量IRQ和非向量IRQ,其中FIQ优先级最高,向量IRQ次之,
非向量IRQ最低。
VIC的基本操作方法如下:
1、设置中断是FIQ还是IRQ,若是IRQ,再设置向量中断,并分配中断优先级。
2、设置中断允许,以及乡里向量中断对应地址或非向量中断默认地址。
3、有中断之后,若是IRQ中断,则可读取向量地址寄存器,然后跳转到该地址所在的响应服务代码。
4、当要推出中断时,对向量地址寄存器写0,通知VIC中断结束。
上次做的实验是采用查询的方式实现LED闪烁,因为在查询的时候CPU只能做一件事,极大地降低了CPU 的使用效率,所以一般情况下,采用中断方式来实现更经济实惠。
程序如下:
#include <intrinsics.h>
#include <stdio.h>
#include <iolpc2103.h>
// OSC [Hz] 外部晶振
#define FOSC 11059200UL
// Core clk [Hz] 处理器当前时钟
#define FCCLK FOSC
// Per clk [Hz] 外部器件时钟,由VPB分频器决定其与FCCLK的关系
#define PCCLK (FOSC/4)
// Timer tick per second 定时器分频
#define TICK_PER_SEC (2UL)
#define TIM_PER_S(Val) (PCCLK/Val)
#define MAX_TICK_PER TIM_PER_S(20)
#define MIN_TICK_PER TIM_PER_S(5)
// Timer Delta period [ms]
#define DELTA_PER (50UL)
#define TIM_DPER ((PCCLK*DELTA_PER)/1000UL)
#define LED_MASK 1<<18
/*************************************************************************
* 函数名称:irq_handler
* 入口参数:无
*
* 返回参数:无
*
* 描 述:IRQ handler
*
*************************************************************************/
#pragma vector="IRQV" //中断向量地址
__irq __arm void irq_handler (void)
{
void (*interrupt_function)();
unsigned int vector;
vector = VICVectAddr; //获得中断向量
interrupt_function = (void(*)())vector;
if(interrupt_function != NULL) //如果不是空函数
{
interrupt_function(); //调用中断指向的函数
}
else
{
VICVectAddr = 0; //清除在VIC中的中断
}
}
/*************************************************************************
* 函数名称: Timer0Handler
* 入口参数: 无
*
* 返回参数: 无
*
* 说 明: Timer 0 handler
*
*************************************************************************/
void Timer0Handler (void)
{
// clear interrupt flag 清除中断标志
T0IR_bit.MR0INT = 1;
// Change patern
if ((IOSET & LED_MASK) == 0)
IOSET = LED_MASK; //关闭LED
else
IOCLR = LED_MASK;
//pNextPattern = pNextPattern->pNextPattern; //调整当前的链表
T0IR=0x02;
VICVectAddr = 0;
}
/*************************************************************************
* 函数名称: VicInit 中断初始化子程序
* 入口参数: 无
*
* 返回参数: 无
*
* 说 明: Init VIC module
*
*************************************************************************/
void VicInit (void)
{
// 初始化中断选择寄存器,写0是IRQ,写1是FIQ,这里写0,选择IRQ.
VICIntSelect = 0;
// 中断使能清零寄存器,写1清零中断使能寄存器的对应位,并禁止对应的中断请求
VICIntEnClear = 0xFFFFFFFF;
// 软件中断清零寄存器,写1清零软件中断寄存器的相应位,并解除强制的中断请求
VICSoftIntClear = 0xFFFFFFFF;
// 保护使能寄存器 写0允许在用户和特权模式下都可以访问VIC寄存器,写1只能在用户模式下访问
VICProtection = 0;
// 向量地址寄存器 清零
VICVectAddr = 0;
// 默认向量地址寄存器 清零
VICDefVectAddr = 0;
// Clear address of the Interrupt Service routine (ISR) for vectored IRQs.
VICVectAddr0 = VICVectAddr1 = VICVectAddr2 = VICVectAddr3 =\
VICVectAddr4 = VICVectAddr5 = VICVectAddr6 = VICVectAddr7 =\
VICVectAddr8 = VICVectAddr9 = VICVectAddr10 = VICVectAddr11 =\
VICVectAddr12 = VICVectAddr13 = VICVectAddr14 = VICVectAddr15 = 0;
// Disable all vectored IRQ slots
VICVectCntl0 = VICVectCntl1 = VICVectCntl2 = VICVectCntl3 =\
VICVectCntl4 = VICVectCntl5 = VICVectCntl6 = VICVectCntl7 =\
VICVectCntl8 = VICVectCntl9 = VICVectCntl10 = VICVectCntl11 =\
VICVectCntl12 = VICVectCntl13 = VICVectCntl14 = VICVectCntl15 = 0;
}
/*************************************************************************
* 函数名称: Init_timer0
* 入口参数: 无
*
* 返回参数: 无
*
* 说 明: Init tiner0
*
*************************************************************************/
void Init_timer0(void)
{
// Init timer
// 定时器中断不允许,并且计数器TC和定时器分频器复位
T0TCR = 2;
// 计数控制寄存器,复位清零
T0CTCR = 0;
// 分频寄存器不分频
T0PR = 0;
// 匹配寄存器 给定初值
T0MR0 = PCCLK/TICK_PER_SEC;
// 匹配控制寄存器 匹配时产生中断并复位
T0MCR = 3;
// 没有外部中断
T0EMR = 0;
// 设置为向量IRQ
VICIntSelect_bit.TIMER0 = 0;
// 设置为TIMER0中断,使能定时器中断
VICVectAddr0 = (unsigned int) Timer0Handler;
VICVectCntl0_bit.NUMBER = VIC_TIMER0;
VICVectCntl0_bit.ENABLED = 1;
// Timer 0 interrupt enable
VICIntEnable_bit.TIMER0 = 1;
// Enable timer0
T0TCR = 1;
}
/*************************************************************************
* 函数名称: Init_Gpio
* 入口参数: 无
*
* 返回参数: 无
*
* 说 明: Init GPIO
*
*************************************************************************/
void Init_Gpio(void)
{
// Init GPIO
PINSEL0 = PINSEL1 = 0;
// Disable fast IO
SCS_bit.GPIO0M = 0;
// Set pins connect to LEDs as outputs
IODIR = LED_MASK;
// All LEDs off
IOCLR = LED_MASK;
}
/*************************************************************************
* 函数名称: Init_pll
* 入口参数: 无
*
* 返回参数: 无
*
* 说 明: Init PLL
*
*************************************************************************/
void Init_pll(void)
{
// Disable PLL
PLLCON = 0;
// Write Feed
PLLFEED = 0xAA;
PLLFEED = 0x55;
// Set periphery divider /4
APBDIV_bit.APBDIV = 0;
// Set MAM fully enable
MAMCR_bit.MODECTRL = 0;
MAMTIM_bit.CYCLES = 3;
MAMCR_bit.MODECTRL = 2;
}
/*************************************************************************
* 函数名称: main
* 入口参数: 无
*
* 返回参数: 无
*
* 描 述: main
*
*************************************************************************/
void main(void)
{
Init_pll();
// Memory map init flash memory is maped on 0 address
#ifdef FLASH
MEMMAP_bit.MAP = 1;
#else
MEMMAP_bit.MAP = 2;
#endif
__disable_interrupt();
VicInit();
Init_Gpio();
Init_timer0();
__enable_interrupt();
while(1)
{};
}
视频效果如下:
http://player.youku.com/player.php/sid/XNzc5NjA3NDg=/v.swf
大家如果有什么问题,请和我一起交流,QQ:272564309
用户557576 2011-2-19 15:08