打印

处理中断嵌套如何

[复制链接]
2029|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
金鱼木鱼|  楼主 | 2010-11-21 16:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
huzixian| | 2010-11-21 19:27 | 只看该作者
在中断处理函数中,重新使能CPSR中的中断使能位

使用特权

评论回复
板凳
米其林r| | 2010-11-21 20:05 | 只看该作者
ARM的中断管理体系和51系列微控制器的中断管理体系不太一样。熟悉51体系结构的用户需要特别注意这一点。ARM的中断不会自动嵌套,实现ARM微控制器的中断嵌套比较烦琐,我们不提倡中断嵌套。但不排除需要嵌套的应用,因而在启动代码中,有对中断嵌套的处理。模板中的文件IRQ.S用于处理中断嵌套,是以下中断处理方法的依据。用户要根据自己的应用更改此文件,只需要在文件末尾添加中断处理程序的句柄即可。
          中断嵌套的原则:低优先级的中断嵌套高优先级的中断。
          可嵌套中断服务程序编写方法:
            1、保存当前中断使能寄存器VICIntEnable的值;
            2、禁止当前中断和低优先级中断;
            3、清除中断逻辑,使VIC能够响应更高优先级的中断;
            4、中断处理服务程序;
            5、恢复保存的中断使能寄存器的值。
          声明需要嵌套的中断服务程序时,不能使用"__irq"关键字,而需要通过句柄的方式进行。
          请注意IRQ.S中宏$IRQ_Label HANDLER $IRQ_Exception_Function的用法。
例子如下:

#include "config.h"
#define BEEPCON ((uint32)0x01<<7) // P0.7引脚控制蜂鸣器,低电平蜂鸣
#define BEEP_ON() IO0CLR=BEEPCON // P0.7引脚输出低电平,蜂鸣器蜂鸣
#define BEEP_OFF() IO0SET=BEEPCON // P0.7引脚输出高电平,蜂鸣器不蜂鸣
#define SPI_CS ((uint32)0x01<<20) // P1.20引脚模拟SPI的片选信号
#define SPI_DATA ((uint32)0x01<<22) // P0.22引脚模拟SPI的数据信号
#define SPI_CLK ((uint32)0x01<<25) // P1.25引脚模拟SPI的时钟信号
#define H_SPI_CS() IO1SET=SPI_CS // SPI的片选信号置高
#define L_SPI_CS() IO1CLR=SPI_CS // SPI的片选信号置低
#define H_SPI_DATA() IO0SET=SPI_DATA // SPI的数据信号置高
#define L_SPI_DATA() IO0CLR=SPI_DATA // SPI的数据信号置低
#define H_SPI_CLK() IO1SET=SPI_CLK // SPI的时钟信号置高
#define L_SPI_CLK() IO1CLR=SPI_CLK // SPI的时钟信号置低
void Timer0_Handler(void);
void Eint0_Handler(void);
uint8 data;

void SendDataTo74HC595(uint8 data){
      uint8 i;
      L_SPI_CS(); // SPI_CS=0
      for(i=0;i<8;i++) // 发送8位数据(1个字节)
        {
           L_SPI_CLK(); // SPI_CLK=0
         
           if((data & 0x80)!=0)
              H_SPI_DATA(); // SPI_DATA=1
           else
              L_SPI_DATA(); // SPI_DATA=0
          data<<=1; // 将要发送的1字节数据左移一位
          H_SPI_CLK(); // SPI_CLK=1
       }
      H_SPI_C); //SPI_CS=1
}

void IRQ_Timer0(void){
    uint32 bak;
    bak="VICIntEnable"; // 备份当前VICIntEnable的值
    VICIntEnClr=(1<<4)(1<<14); // 禁止当前优先级中断及低优先级中断
    VICVectAddr="0x00"; // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断
   
    if(data==0x00)
        data="0xff";
    else
        data="0x00";
    SendDataTo74HC595(data);
    T0IR=0x01; // 清除Timer0中断标志 VICIntEnable="bak";
}

void IRQ_Eint0(void){
    uint32 bak;
    bak="VICIntEnable"; // 备份当前VICIntEnable的值
    VICIntEnClr="1"<<14; // 禁止当前中断
    VICVectAddr="0x00"; // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断
    IRQEnable(); // 使能IRQ中断
   
    if((IO0PIN & BEEPCON)==0)
       BEEP_OFF();
     else
       BEEP_ON();
   
     while((EXTINT & 0x01)!=0)
        { EXTINT="0x01"; }
     VICIntEnable="bak";
   }

int main(void){
    PINSEL0&=~((uint32)0x03<<14); // 将P0.7引脚选择为GPIO功能
    IO0DIR=BEEPCON; // 设置P0.7为输出
    BEEP_OFF(); // 蜂鸣器禁止蜂鸣
    PINSEL1&=~((uint32)0x03<<0); // 将P0.16引脚选择为EINT0功能
    PINSEL1=0x00000001;
    PINSEL1&=~((uint32)0x03<<12); // 设置P0.22引脚为GPIO
    PINSEL2&=~((uint32)0x01<<3); // 设置P1.20和P1.25引脚为GPIO
    IO0DIR=SPI_DATA; // 设置P0.22,P1.20,P1.25引脚为输出
    IO1DIR=(SPI_CS SPI_CLK);
    T0TC=0; // 定时器设置为0
    T0PR=0; // 时钟不分频
    T0MCR=0x03; // 设置T0MR0匹配后复位T0TC,并产生中断标志
    T0MR0=Fpclk/10; // 0,1秒定时
    T0TCR=0x01; // 启动定时器 I
    RQEnable(); // 使能IRQ中断
    data="0x00";

    VICIntSelect="0x00000000"; // 设置所有中断分配为IRQ中断
    VICVectCntl0=0x20+4; // 分配Timer0中断到向量中断0
    VICVectAddr0=(uint32)Timer0_Handler; // 设置中断服务程序地址
    VICVectCntl1=0x20+14; // 分配EINT0中断到向量中断1
    VICVectAddr1=(uint32)Eint0_Handler; // 设置中断服务程序地址
    T0IR=0x01; // 清除Timer0中断标志
    EXTINT="0x01"; // 清除EINT0中断标志
    VICIntEnable=(1<<4)(1<<14); // 使能Timer0、EINT0中断
    while(1); // 等待中断
    return 0;
}

使用特权

评论回复
地板
米其林r| | 2010-11-21 20:06 | 只看该作者
本帖最后由 米其林r 于 2010-11-21 20:08 编辑

在不使用中断嵌套的情况下,可以直接用关键字“__irq”来申明IRQ中断服务程序,此时中断现场的保护由编译器自动完成。由于ARM7硬件不支持IRQ中断嵌套,因而要想实现IRQ中嵌套,只有通过软件来完成。这段代码的汇编部分就包含在IRQ.s文件中。
使用方法,以外部中断1,嵌套外部中断0为例说明。
首先,在IRQ.S文件中填加中断句柄
EINT0ISR HANDLER EINT0ISR_Exception
EINT1ISR HANDLER EINT1ISR_Exception
其次,在用户程序中申明引用这两个外部函数
extern void EINT0ISR(void);
extern void EINT1ISR(void);
再者,在中断初始化程序中,把上面申明为引用的函数地址赋给向量地址寄存器
...
VICVectAddr0 = (uint32)EINT0ISR;
VICVectAddr1 = (uint32)EINT1ISR;
...
最后,编写IRQ中断服务程序,以中断0的中断服务程序为例,中断1的服务程序与此相同
void EINT0ISR_Exception(void)
{
    uint32 Bak;
    Bak = VICIntEnable; // 备份当前VICIntEnable的值
    VICIntEnClr = 1 << 14; // 禁止当前中断
    VICVectAddr = 0x00; // 清楚向量地址
    IRQEnable(); // 使能IRQ中断
    ... // 用户代码
}

使用特权

评论回复
5
3B1105| | 2010-11-21 21:16 | 只看该作者
这个RQEnable(); // 使能IRQ中断   应该是跳到汇编段执行!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

346

主题

1551

帖子

2

粉丝