LPC1114外部中断

发布者:数字翻飞最新更新时间:2016-08-23 来源: eefocus关键字:LPC1114  外部中断 手机看文章 扫描二维码
随时随地手机看文章
外部中断作为处理器响应外部事件的通道,在控制系统中起着非常重要的作用。下面就来讨论一下LPC1114外部中断的使用情况。

LPC1114的每一个引脚都可以响应一个外部中断,所以有多少个引脚就有多少个外部中断。但LPC1114的中断系统非常强大,外部中断只是它其中的一小部分。因此,要用好外部中断,就必须先来了解LPC1114的整个中断系统。下面就来看一下它的中断系统。

在LPC11xx系列处理器中,有一个部分被称为“私有外设总线”(Private peripheral bus),它位于Memory map中地址为0xE0000000~0xE0100000的地方,包含有下表中的几个核心外设。

外部中断 - 西区故事 - 松柏后凋

其中的Nested Vectored Interrupt Contorller(NVIC)就是中断系统,被称为“内嵌套向量中断控制器”。它与处理器内核紧密耦合,可实现低中断延迟及对新中断的有效处理。它具有以下特征:

拥有32路向量中断;每个中断的优先级均可编程设置为0~192(步长64),数值越小优先级越高,0级为最高优先级;支持电平和边沿触发中断;支持中断尾链;拥有一个外部不可屏蔽中断NMI。

NVIC所涉及到的寄存器如下表所示。

外部中断 - 西区故事 - 松柏后凋

从表中可以看出,每个寄存器都是32位的结构,都具有可读可写的属性,复位值都为全0。其中ISER寄存器是设置中断的使能,32位对应32路中断,值为1使能中断,值为0不使能中断。ICER寄存器是设置中断的禁能,32位对应32路中断,值为1禁能中断,值为0不禁能。ISPR寄存器是设置中断的挂起,32位对应32路中断,值为1挂起,值为0不挂起。ICPR寄存器是清除中断的挂起,32位对应32路中断,值为1清除挂起,值为0不清除挂起。IPR0~7寄存器是设置中断优先级。

下面是NVIC寄存器组所对应的结构体形式(位于头文件core_cm0.h中)。 

typedef struct
{
  __IO uint32_t ISER[1];                 /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
       uint32_t RESERVED0[31];
  __IO uint32_t ICER[1];                 /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register          */
       uint32_t RSERVED1[31];
  __IO uint32_t ISPR[1];                 /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register           */
       uint32_t RESERVED2[31];
  __IO uint32_t ICPR[1];                 /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register         */
       uint32_t RESERVED3[31];
       uint32_t RESERVED4[64];
  __IO uint32_t IP[8];                   /*!< Offset: 0x300 (R/W)  Interrupt Priority Register              */
}  NVIC_Type;

因NVIC寄存器组的基址为0xE000E100,所以要将基址指针强制转换为上述结构体,还必须要加上下面的定义。

#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address */
#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!< NVIC Base Address                 */
#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!< NVIC configuration struct          */

接下来给出的是上面NVIC32位寄存器所对应的32路中断向量的中断源。
外部中断 - 西区故事 - 松柏后凋

为了能描述上面的32路中断源,在C语言中运用了枚举类型,代码如下所示(位于头文件lpc11xx.h中)。 

typedef enum IRQn
{
/******  Cortex-M0 Processor Exceptions Numbers ***************************************************/
  NonMaskableInt_IRQn           = -14,      /*!< 2 Non Maskable Interrupt                         */
  HardFault_IRQn                = -13,      /*!< 3 Cortex-M0 Hard Fault Interrupt                 */
  SVCall_IRQn                   = -5,       /*!< 11 Cortex-M0 SV Call Interrupt                   */
  PendSV_IRQn                   = -2,       /*!< 14 Cortex-M0 Pend SV Interrupt                   */
  SysTick_IRQn                  = -1,       /*!< 15 Cortex-M0 System Tick Interrupt               */
/******  LPC11xx/LPC11Cxx Specific Interrupt Numbers **********************************************/
  WAKEUP0_IRQn                  = 0,        /*!< All I/O pins can be used as wakeup source.       */
  WAKEUP1_IRQn                  = 1,        /*!< There are 13 pins in total for LPC11xx           */
  WAKEUP2_IRQn                  = 2,
  WAKEUP3_IRQn                  = 3,
  WAKEUP4_IRQn                  = 4,   
  WAKEUP5_IRQn                  = 5,        
  WAKEUP6_IRQn                  = 6,        
  WAKEUP7_IRQn                  = 7,        
  WAKEUP8_IRQn                  = 8,        
  WAKEUP9_IRQn                  = 9,        
  WAKEUP10_IRQn                 = 10,       
  WAKEUP11_IRQn                 = 11,       
  WAKEUP12_IRQn                 = 12,       
  CAN_IRQn                      = 13,       /*!< CAN Interrupt                                    */
  SSP1_IRQn                     = 14,       /*!< SSP1 Interrupt                                   */
  I2C_IRQn                      = 15,       /*!< I2C Interrupt                                    */
  TIMER_16_0_IRQn               = 16,       /*!< 16-bit Timer0 Interrupt                          */
  TIMER_16_1_IRQn               = 17,       /*!< 16-bit Timer1 Interrupt                          */
  TIMER_32_0_IRQn               = 18,       /*!< 32-bit Timer0 Interrupt                          */
  TIMER_32_1_IRQn               = 19,       /*!< 32-bit Timer1 Interrupt                          */
  SSP0_IRQn                     = 20,       /*!< SSP0 Interrupt                                   */
  UART_IRQn                     = 21,       /*!< UART Interrupt                                   */
  Reserved0_IRQn                = 22,       /*!< Reserved Interrupt                               */
  Reserved1_IRQn                = 23,       
  ADC_IRQn                      = 24,       /*!< A/D Converter Interrupt                          */
  WDT_IRQn                      = 25,       /*!< Watchdog timer Interrupt                         */  
  BOD_IRQn                      = 26,       /*!< Brown Out Detect(BOD) Interrupt                  */
  FMC_IRQn                      = 27,       /*!< Flash Memory Controller Interrupt                */
  EINT3_IRQn                    = 28,       /*!< External Interrupt 3 Interrupt                   */
  EINT2_IRQn                    = 29,       /*!< External Interrupt 2 Interrupt                   */
  EINT1_IRQn                    = 30,       /*!< External Interrupt 1 Interrupt                   */
  EINT0_IRQn                    = 31,       /*!< External Interrupt 0 Interrupt                   */
} IRQn_Type;

从上述代码中可以看出,除了32路中断源外,还加入了优先级更高5个中断源。这里先不进行说明,在后面用到时再来讨论。定义好上述代码后,就可以来写中断所需要的函数了。下面就是依据CMSIS规范所定义的8个中断操作函数(位于头文件core_cm0.h中)。 

1.允许某个中断或异常

static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
  NVIC->ISER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

2.禁止某个中断或异常

static __INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{
  NVIC->ICER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

3.读取某个中断或异常的挂起状态

static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
  return((uint32_t) ((NVIC->ISPR[0] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}

4.把某个中断或异常的挂起状态设为1

static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
  NVIC->ISPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}

5.把某个中断或异常的挂起状态清为0

static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
  NVIC->ICPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* Clear pending interrupt */
}

6.把某个中断或异常的可配置优先级设为1

static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if(IRQn < 0) {
    SCB->SHP[_SHP_IDX(IRQn)] = (SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
        (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
  else {
    NVIC->IP[_IP_IDX(IRQn)] = (NVIC->IP[_IP_IDX(IRQn)] & ~(0xFF << _BIT_SHIFT(IRQn))) |
        (((priority << (8 - __NVIC_PRIO_BITS)) & 0xFF) << _BIT_SHIFT(IRQn)); }
}

7.读取某个中断或异常的优先级

static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
{

  if(IRQn < 0) {
    return((uint32_t)((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS)));  } /* get priority for Cortex-M0 system interrupts */
  else {
    return((uint32_t)((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS)));  } /* get priority for device specific interrupts  */
}

8.复位NVIC

static __INLINE void NVIC_SystemReset(void)
{
  __DSB();                                                     /* Ensure all outstanding memory accesses included buffered write are completed before reset */
  SCB->AIRCR  = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk);
  __DSB();                                                     /* Ensure completion of memory access */
  while(1);                                                    /* wait until reset */
}

在上述函数中有几点要说明一下,一是数组的引用其取值只能是0(即第一个元素),这是因为在结构体定义中只定义了一个数组元素,且由于需要利用数组的地址连续性来对映CPU物理地址,所以也不能将其定义为一个普通变量;二是关键字“__INLINE ”在头文件core_cm0.h中已做了宏定义“#define __INLINE  __inline”,__inline是通知编译器其后面的函数为内联形式;三是中断源IRQn要与0x1F与一下,是为了屏蔽高27位的值,因为中断源的最大值只到31,所以只用了32位中的低5位(31的二进制是11111,十六进制是0x1F);四是在函数的参数中,由于引入了枚举类型,所以可以在调用函数的时候,在参数部分可直接使用枚举中的名称,这样就可以省去记忆32个中断源在32位寄存器中的对应位置,便于书写和阅读。例如,要开启端口0的外部中断,执行程序“NVIC_EnableIRQ(EINT0_IRQn)”即可。

上述就是LPC1114中的整个中断系统,即“内嵌套向量中断控制器”。可以看出,它控制着整个处理器32路中断源的使能与挂起等8个动作,功能非常强大。但做为外部中断的端口中断源却只有4个,即EINT0_IRQn、EINT1_IRQn、EINT2_IRQn、EINT3_IRQn四个。而每一个端口又对应有12个引脚(端口3为6个)又都可以产生外部中断,那怎么来判断是那个引脚上申请的中断呢?这就需要借助前面“通用输入/输出端口”部分介绍过的MIS寄存器了。在外部中断响应的服务程序内,判别MIS寄存器的各个位,值为1的位所对应的就是触发本次外部中断的引脚。

和所有的单片机一样,在中断响应后,程序指针会跳转到相应的中断向量入口处去执行中断服务程序,而在C语言中则是以特定形式的中断入口函数来呈现。比如EINT0_IRQn、EINT1_IRQn、EINT2_IRQn、EINT3_IRQn四个端口的外部中断入口函数分别如下:

void PIOINT0_IRQHandler(void)
{
  端口0的中断服务程序部分
}
void PIOINT1_IRQHandler(void)
{
  端口1的中断服务程序部分
}
void PIOINT2_IRQHandler(void)
{
  端口2的中断服务程序部分
}
void PIOINT3_IRQHandler(void)
{
  端口3的中断服务程序部分
}
上述函数的名称是不能改变的,它标志着特定的中断入口,除了四个外部中断以外的其它中断源,也有各自的中断入口函数,它们都位于起动文件“startup_LPC11xx.s”中,在以后用到时再讨论,这里就不给出了。

下面来讨论一个外部中断的例子,要求使用外部中断来实现按键控制LED的亮灭。程序代码如下(假设KEY接在GPIO1.9,LED接在GPIO1.0):

#include
//=================端口1的外部中断服务程序=====================
void PIOINT1_IRQHandler(void)
{
 if((LPC_GPIO1->MIS&0x200)==0x200)                              //检测是否是GPIO1.9引脚上的中断
  {
   LPC_GPIO1->MASKED_ACCESS[1] = 0;                        //开启LED
   while(LPC_GPIO1->MASKED_ACCESS[512] != 0x200); //等待GPIO1.9引脚按键释放
   LPC_GPIO1->MASKED_ACCESS[1] = 1;                        //关闭LED
  }
 LPC_GPIO1->IC |= 0x200;                                                  //清除GPIO1.9引脚上的中断标志
}
//==========================主程序============================
int main(void)
{
 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16);      //使能IOCON时钟
 LPC_IOCON->R_PIO1_0 = 0XD1;                           //把芯片上的33脚设置为GPIO1.0功能
 LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<16);  //禁能IOCON时钟
 LPC_GPIO1->DIR &= ~(1<<9);                               //设置GPIO1.9为输入方向
 LPC_GPIO1->DIR |= (1<<0);                                   //设置GPIO1.0为输出方向
 LPC_GPIO1->MASKED_ACCESS[1]  = 1;              //输出高电平,关闭LED
 LPC_GPIO1->IS &= ~(1<<9);                                 //选择中断为边沿触发
 LPC_GPIO1->IEV &= ~(1<<9);                               //选择下降沿触发
 LPC_GPIO1->IE |= (1<<9);                                    //设置中断P1.9不被屏蔽
 NVIC_EnableIRQ(EINT1_IRQn);                            //使能GPIO1中断
 while(1)
 {
  ;
 }
}

把上述程序编译后下载到LPC1114中,给系统上电,可以看出在按下KEY后LED亮,放开KEY后LED灭,达到了使用外部中断控制的目的。

最后说明一点,如果需要打开或关闭中断“总中断”,可调用“__enable_irq();和__disable_irq();”来实现,它们是通过调用汇编语言来实现这一操作的,具体的原型在头文件“core_cmFunc.h”中,可自行查看,这里就不详述了。

关键字:LPC1114  外部中断 引用地址:LPC1114外部中断

上一篇:LPC1114系统定时器(SysTick)
下一篇:LPC1114通用输入/输出端口(GPIO)续

推荐阅读最新更新时间:2024-03-16 15:06

认识C51外部中断(INT0)
以下将以红外遥控解码为例讲一下C51外部中断(INT0)的编程亲身体会. 要对红外遥控信号解码那么就要使用C51外部中断,并且要设置成为负跳变沿触发方式.一般都会在主程序的开始外初始化中断(或将初始化中断程序写成函数,将这个函数放入主程序)如下: void main(void) {  IT0=1;//负跳变触发  EX0=1;//开外部中断0  EA=1;//开总中断  .........//其它程序  .......... } void INT0() interrupt 0 {  .......//红外信号解码程序 } 根据需要打开外部中断(EX0=1):  以上程序在开始处便打开了外部中断.从理论上是完
[单片机]
s3c6410 的外部中断实现
6410各个中断寄存器的关系 图 EINT0CON0 External Interrupt 0(Group0) Configuration Register 0 设置 外部中断的触发方式(高电平等) EINT0PEND External Interrupt 0(Group0) Pending Register 屏蔽前的中断(谁中断,相应位置1) EINT0MASK External Interrupt 0(Group0) Mask Register 屏蔽(屏蔽谁,相应位置1) 以上两个是管脚级别(GPIO)的pending和mask寄存器; 下边是中断控制器的pending和mask寄存器 VIC0INTENABLE I
[单片机]
s3c6410 的<font color='red'>外部中断</font>实现
STM32的中断操作(一)——EXTI
前言 在单片机的编程中,中断都是很重要的一个概念。在stm32中,中断有两种,一种是外部中断(EXTI),另一种是定时器中断(SysTick),本篇文章从中断的概念入手,再对外部中断简要的做一些介绍。 一、中断是什么? 相信大家在初学中断这个概念时都听过这样一个例子:如果你一个人在家里正在做饭,这时门铃响了,你选择先去开门,然后再回来做饭,这就是一个浅显易懂的中断的例子,做饭为主程序,而去开门就是中断程序,门铃响起就是中断请求。而如果门铃响起同时电话也响起,那么你决定先去处理哪一件事的过程就是中断优先级的判别过程。 中断的定义如下: 中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并
[单片机]
STM32的中断操作(一)——<font color='red'>EXTI</font>
C51/C52的中断(EXTI
一、什么是中断 打断:打断当前做的事情,去执行中断函数里的程序,执行完过后回来接着执行原来未执行完的程序。如下图所示: ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 二、中断源及中断号 注意:写中断服务函数时,中断源与中断号要一一对应,否则不能进入中断服务函数,比如: void Timer0IRQ(void) inter
[单片机]
C51/C52的中断(<font color='red'>EXTI</font>)
关于单片机外部中断的扩展
单片机外部中断有限,仅有两个,在某些系统设计中可能会不够用。这里给大家推荐一个比较简单的扩展外部中断的方法。灵感来至于单片机键盘设计! 在有些键盘设计中,如果在程序中采用轮询的方法在检测按键,会花费大量的cpu资源,特别是还要进行大量的数据处理的情况下。所以很多按键设计都加入了中断,上一篇博文里的按键设计其实都可以加入中断,这样可以更好的利用cpu资源。 一般在按键设计中只会用一个中断,但是却可以控制n多的按键。每一个按键的按下都相当于产生了一个中断,所以利用这个原理,我们也可以 无限 的扩展外部中断。一个简单的电路图如下: 这样当外部送来一个低电平的信号时,通过与非门后将产生一个中断信号,这个信号可以送到单片机的外部中断
[单片机]
STM32F407 外部中断配置步骤
介绍STM32F407外部中断配置步骤,以按键为例,实现外部中断配置,使用按键触发中断进行LED灯控制。 【1】外部中断相关知识介绍 CM4 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256级的可编程中断设置。但 STM32F4 并没有使用 CM4 内核的全部东西,而是只用了它的一部分。 STM32F40xx/STM32F41xx 总共有 92 个中断, STM32F42xx/STM32F43xx 则总共有 96 个中断,以下仅以 STM32F40xx/41xx 为例讲解。 STM32F40xx/STM32F41xx 的 92 个中断里面, 包括 10 个内核中断和 8
[单片机]
STM32F407 <font color='red'>外部中断</font>配置步骤
ARM7与FPGA相结合的应用
  ARM7与FPGA相结合在工业控制和故障检测中的应用   工业控制中往往需要完成多通道故障检测及多通道命令控制(这种多任务设置非常普遍),单独的CPU芯片由于其外部控制接口数量有限而难以直接完成多路检控任务,故利用ARM芯片与FPGA相结合来扩展检控通道是一个非常好的选择。这里介绍用Atmel公司ARM7处理器(AT91FR40162)和ALTERA公司的低成本FPGA芯片(cyclone2)结合使用完成多通道检控任务的一种实现方法。    各部分功能简介   图1为此系统的结构连接框图。如图所示,ARM芯片与FPGA芯片之间通过数据总线、地址总线及读写控制线相连,而与终端PC则通过串口通信;FPGA与目标设备通过命令控
[嵌入式]
cortex m0 lpc1114 adc介绍资料详解
LPC1114内部有一个逐次逼近型ADC模块,总的来说有如下特征: 8个模拟信号输入通道,可以开1个通道测电压,也可以8个通道全开测电压,软件控制模式下,只能开1个通道,硬件扫描模式下,可以开多个通道 输入电压范围0~VDD 最高10位精度 ADC时钟可调,最大4.5MHz,最快转换时间2.44微秒 可以软件控制转换,也可硬件扫描转换,转换形式多种多样 每个通道都有独立的转换结果寄存器,转换结束可以产生中断 1. 软件控制模式 软件控制ADC转换,分为3种转换方式: 1. 给控制寄存器CR的bit24(即START位)写1启动转换,这种转换的特点是由程序控制何时转换,可以随时转换; 2. 通过CT16B0和CT32B
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved