这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » UCOS 在UCOS中,编了一个中断嵌套的试验程序,试验结果不对,请帮忙!

共2条 1/1 1 跳转至

UCOS 在UCOS中,编了一个中断嵌套的试验程序,试验结果不对,请帮忙!

院士
2006-09-17 18:14:16     打赏
UCOS 在UCOS中,编了一个中断嵌套的试验程序,试验结果不对,请帮忙!



关键词: 编了     一个     中断     嵌套     试验     程序     结果     不对         

院士
2006-12-22 22:43:00     打赏
2楼
ARM芯片  : LPC2124

目的     :任务1就是一个由定时器0控制的LED闪程序,观察
与外部中断2嵌套后,两个LED的现象。
程序如下 :


/*
main.c
*/

#include "config.h"
#include "stdlib.h"

#define    TaskStkLengh    64            //Define the Task0 stack length 定义用户任务0的堆栈长度

//试验代码
#define    LED1CON            0x00000010  //P0.4_P27为LED1控制端
#define LED2CON            0x00000020  //P0.5_P29为LED2控制端

OS_STK    TaskStk0 [TaskStkLengh];
void     Task0(void *pdata);            //Task0 任务0
/****************************************************************************
* 名称:EnableIRQ()
* 功能:打开IRQ中断允许。
* 入口参数:无
* 出口参数:无
****************************************************************************/
__inline void  EnableIRQ(void)
{  int  tmp;

   __asm
   {  MRS    tmp, CPSR
      BIC   tmp, tmp, #0x80
      MSR   CPSR_c, tmp
   }
}

        int main (void)
{    
    PINSEL0 = 0x0000C000;            //引脚连接设置,P0.0,P0.1为串口,P0.7_P31为EINT2
    PINSEL1 = 0x00000000;
    PINSEL2 = 0x00000000;
    
    IO0DIR = LED1CON|LED2CON;
    
    
    OSInit ();                                                                                                        
    OSTaskCreate (Task0,(void *)0, &TaskStk0[TaskStkLengh - 1], 2);        
    OSStart ();
    return 0;                                                            
}

/*********************************************************************************************************
**                            Task0 任务0
********************************************************************************************************/
        void Task0    (void *pdata)
{
    
    pdata = pdata;
    
    TargetInit ();
        while (1)
    {
        if(0==(IO0SET&LED1CON)) IO0SET = LED1CON;                //点亮LED
        else IO0CLR = LED1CON;
        OSTimeDly(30);
    }
}
/****************************************************************************
* 名称:IRQ_Eint3()
* 功能:外部中断EINT3服务函数,取反LED4。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void   IRQ_Eint2(void)
{  uint32  i, bak;
   
   bak = VICIntEnable;
   VICIntEnClr = (1<<16);            
   VICVectAddr = 0x00;                
   EnableIRQ();                        // 打开IRQ中断允许
   
   i = IO0SET;                        // 读取当前LED4控制值
   if( (i&LED2CON)==0 )                // 控制LED4输出
   {  IO0SET = LED2CON;
   }
   else
   {  IO0CLR = LED2CON;
   }
   
   while( (EXTINT&0x04)!=0 )        // 等待外部中断信号恢复为高电平    
   {  EXTINT = 0x04;                // 清除EINT3中断标志
   }
   
   VICIntEnable = bak;
}

/*
target.c
*/
        void VICInit(void)
{
    extern void IRQ_Handler(void);
    extern void Timer0_Handler(void);
    
    extern void Eint2_Handler(void);                //**添加用户代码**
    
    extern void Uart0_Handler(void);

    VICIntEnClr = 0xffffffff;
    VICDefVectAddr = (uint32)IRQ_Handler;
    
    VICVectAddr0 = (uint32)Timer0_Handler;
    VICVectCntl0 = (0x20 | 0x04);
    
    
    VICVectAddr2 = (uint32)Eint2_Handler;        //**添加用户代码**
    VICVectCntl2 = (0x20 | 0x10);                //**添加用户代码**
    EXTMODE = 0x04;                                //设置EINT2为边沿触发
    EXTPOLAR = 0x00;
       
    VICIntEnable = 1<<4;
    VICIntEnable = 1<<16;                        //**添加用户代码**            
}
        void TargetInit(void)
{
    OS_ENTER_CRITICAL();
    srand((uint32) TargetInit);
    VICInit();
    Timer0Init();
    Eint2Init();

    OS_EXIT_CRITICAL();
}

/*
IRQ.S
*/

            INCLUDE        irq.inc            ; Inport the head file 引入头文件

    CODE32

    AREA    IRQ,CODE,READONLY


;/* 以下添加中断句柄,用户根据实际情况改变 */
;/* Add interrupt handler here,user could change it as needed */

;/*中断*/
;/*Interrupt*/
IRQ_Handler    HANDLER IRQ_Exception


;/*定时器0中断*/
;/*Time0 Interrupt*/
Timer0_Handler  HANDLER Timer0_Exception

;/*外部中断2*/
;/*EINT0 Interrupt*/
Eint2_Handler   HANDLER IRQ_Eint2

试验现象是 :
当按键按下不放时,中断控制的LED和定时器控制的LED同步闪烁,我认为应该是中断控制的LED不变,定时器控制的LED不间断的闪烁.
请问问题出在什么地方? 1: 没道理外部中断2控制的LED2会闪!我已经在中断初始化函数(VICInit())中将EINT2设置为下边沿触发,这样,当按住按键不放的情况下,不会在触发中断啦!外部中断服务子程序就不会执行,LED2也就不可能闪啊!可它闪个不停!请大家帮忙看看! 2: 请周工帮忙分析一下吧!回答问题的大侠少了! 3: 这个问题困扰我好几天啦!解决不了的话,解决不了的话,后面的应用程序开发就没戏啦!有条件的朋友帮忙跑一下程序,看看问题出在哪里?人多力量大啊!先谢谢支持的朋友啦!谢谢! 4: 中断嵌套比较麻烦,不做过多技术支持。仅给一个例子:        void UART0_Exception(void)
{
    uint8 IIR, temp, i;
    
    VICIntEnClr = (1 << 6) | (1 << 4);
    VICVectAddr = 0;            // 通知中断控制器中断结束
    OS_ENTER_CRITICAL();
    OS_EXIT_CRITICAL();

    while(((IIR = U0IIR) & 0x01) == 0)
    {                                                   /* 有中断未处理完 */
        switch (IIR & 0x0e)
        {
            case 0x02:                                  /* THRE中断    */
                for (i = 0; i < UART0_FIFO_LENGTH; i++) /* 向发送FIFO填充数据 */
                {
                    if (QueueRead(&temp, UART0SendBuf) == QUEUE_OK)
                    {
                        U0THR = temp;
                    }
                    else
                    {
                        U0IER = U0IER & (~0x02);        /* 队列空,则禁止发送中断 */
                    }
                }
                break;
            case 0x04:                                  /* 接收数据可用 */
                OSSemPost(Uart0Sem);                    /* 通知接收任务 */
                U0IER = U0IER & (~0x01);                /* 禁止接收及字符超时中断 */
                break;
            case 0x06:                                  /* 接收线状态   */
                temp = U0LSR;
                break;
            case 0x0c:                                  /* 字符超时指示 */
                OSSemPost(Uart0Sem);                    /* 通知接收任务 */
                U0IER = U0IER & (~0x01);                /* 禁止接收及字符超时中断 */
                break;
            default :
                break;
        }
    }
    VICIntEnable = (1 << 6) | (1 << 4);
}






        void Timer0_Exception(void)
{
    VICIntEnClr = 1 << 4;
    VICVectAddr = 0;            // 通知中断控制器中断结束
    OS_ENTER_CRITICAL();
    OS_EXIT_CRITICAL();

    T0IR = 0x01;
    OSTimeTick();
    VICIntEnable = 1 << 4;
}






        void VICInit(void)
{
    extern void IRQ_Handler(void);
    extern void Timer0_Handler(void);
    extern void UART0_Handler(void);

    VICIntEnClr = 0xffffffff;
    VICDefVectAddr = (uint32)IRQ_Handler;

    VICVectAddr14 = (uint32)UART0_Handler;
    VICVectCntl14 = (0x20 | 0x06);
    VICIntEnable = 1 << 6;

    VICVectAddr15 = (uint32)Timer0_Handler;
    VICVectCntl15 = (0x20 | 0x04);
    VICIntEnable = 1 << 4;
}




5: 再问一下!UCOSII中肯定要用一个定时中断作为时钟节拍,如果加上键盘扫描使用一个外部中断,定时中断不能停,是不是就一定要中断嵌套,在定时中断中嵌套外部中断,还是外部中断嵌套定时中断?我认为是后者,在外部中断中开定时器中断?

还有就是你还没指出我的程序哪里不对呀! 6: 留下QQ,有愿意讨论中断嵌套的朋友请加入。408709006 7: 不明白还是要问!我在你们网站上下载了一段中断嵌套的程序,在板上运行挺正常,可是改了部分程序就出现问题:
源程序
/****************************************************************************
* 文件名:EINT03_VECT.C
* 功能:使能外部中断0和外部中断3,当外部中断0有效时,控制LED1取反;当外部中断3有效时,
*      控制取反LED4。使用向量中断方式。
* 说明:将跳线器JP4_LED1、JP4_LED4短接,然后按下/放开KEY1,使EINT0为低/高电平;按
*      下/放开KEY5,使EINT3为低/高电平。
*
*****************已更改,允许IRQ中断嵌套*****************
****************************************************************************/
#include  "config.h"
  

#define   LED1CON       (1<<22)              /* P0.22口为LED1控制端 */
#define   LED4CON       (1<<25)              /* P0.25口为LED4控制端 */


void  Eint0_Handler(void);
void  Eint3_Handler(void);

/****************************************************************************
* 名称:EnableIRQ()
* 功能:打开IRQ中断允许。
* 入口参数:无
* 出口参数:无
****************************************************************************/
__inline void  EnableIRQ(void)
{  int  tmp;

   __asm
   {  MRS    tmp, CPSR
      BIC   tmp, tmp, #0x80
      MSR   CPSR_c, tmp
   }
}


/****************************************************************************
* 名称:IRQ_Eint0()
* 功能:外部中断EINT0服务函数,取反LED1。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void  IRQ_Eint0(void)
{  uint32  i, bak;

   bak = VICIntEnable;                // 备份当前VICIntEnable的值
   VICIntEnClr = (1<<14)|(1<<17);    // 禁止当前优先级中断及低优先级中断
   VICVectAddr = 0x00;                // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断
   EnableIRQ();                        // 打开IRQ中断允许
   
   i = IO0SET;                        // 读取当前LED1控制值
   if( (i&LED1CON)==0 )                // 控制LED1输出
   {  IO0SET = LED1CON;
   }
   else
   {  IO0CLR = LED1CON;
   }
   
   while( (EXTINT&0x01)!=0 )        // 等待外部中断信号恢复为高电平    
   {  EXTINT = 0x01;                // 清除EINT0中断标志
   }
     
   VICIntEnable = bak;
}        



/****************************************************************************
* 名称:IRQ_Eint3()
* 功能:外部中断EINT3服务函数,取反LED4。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void   IRQ_Eint3(void)
{  uint32  i, bak;
   
   bak = VICIntEnable;
   VICIntEnClr = (1<<17);            
   VICVectAddr = 0x00;                
   EnableIRQ();
   
   i = IO0SET;                        // 读取当前LED4控制值
   if( (i&LED4CON)==0 )                // 控制LED4输出
   {  IO0SET = LED4CON;
   }
   else
   {  IO0CLR = LED4CON;
   }
   
   while( (EXTINT&0x08)!=0 )        // 等待外部中断信号恢复为高电平    
   {  EXTINT = 0x08;                // 清除EINT3中断标志
   }
   
   VICIntEnable = bak;
}
            

/****************************************************************************
* 名称:main()
* 功能:初始化外部中断0、3为向量中断,并设置为下降沿触发模式,然后等待外部中断。
* 说明:在STARTUP.S文件中使能IRQ中断(清零CPSR中的I位)。
****************************************************************************/
int  main(void)
{  PINSEL0 = 0x00000000;            
   PINSEL1 = 0x00000301;            // 设置管脚连接,P0.16设置为EINT0,P0.20设置为EINT3
   IO0DIR = LED1CON|LED4CON;        // 设置B1控制口为输出,其它I/O为输入
   
   /*  打开EINT0、EINT3中断(设置向量控制器,即使用向量IRQ) */
   VICIntSelect = 0x00000000;        // 设置所有中断分配为IRQ中断
   VICVectCntl0 = 0x20|14;            // 分配EINT0中断到向量中断0
   VICVectAddr0 = (int)Eint0_Handler;     // 设置中断服务程序地址
   VICVectCntl1 = 0x20|17;            // 分配EINT3中断到向量中断1
   VICVectAddr1 = (int)Eint3_Handler;     // 设置中断服务程序地址
   EXTINT = 0x09;                    // 清除EINT0、EINT3中断标志    
   
   VICIntEnable = (1<<14)|(1<<17);    // 使能EINT0、EINT3中断
   EnableIRQ();
   
   while(1);                        // 等待中断
   return(0);
}

修改后的程序

/****************************************************************************
* 文件名:EINT03_VECT.C
* 功能:使能外部中断0和外部中断3,当外部中断0有效时,控制LED1取反;当外部中断3有效时,
*      控制取反LED4。使用向量中断方式。
* 说明:将跳线器JP4_LED1、JP4_LED4短接,然后按下/放开KEY1,使EINT0为低/高电平;按
*      下/放开KEY5,使EINT3为低/高电平。
*
*****************已更改,允许IRQ中断嵌套*****************
****************************************************************************/
#include  "config.h"
  

#define   LED1CON       (1<<4)              /* P0.22口为LED1控制端 */
#define   LED4CON       (1<<5)              /* P0.25口为LED4控制端 */   

void  Eint0_Handler(void);
void  Eint2_Handler(void);
void  Timer0_Handler(void);

/****************************************************************************
* 名称:EnableIRQ()
* 功能:打开IRQ中断允许。
* 入口参数:无
* 出口参数:无
****************************************************************************/
__inline void  EnableIRQ(void)
{  int  tmp;

   __asm
   {  MRS    tmp, CPSR
      BIC   tmp, tmp, #0x80
      MSR   CPSR_c, tmp
   }
}

/****************************************************************************
* 名称:IRQ_Time0()
* 功能:外部中断EINT0服务函数,取反LED1。
* 入口参数:无
* 出口参数:无
****************************************************************************/

void IRQ_Timer0(void)
{  uint32  i, bak;

   bak = VICIntEnable;                // 备份当前VICIntEnable的值
   VICIntEnClr = (1<<4)|(1<<16);    // 禁止当前优先级中断及低优先级中断
   VICVectAddr = 0x00;                // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断
   
   EnableIRQ();                        // 打开IRQ中断允许
   
   i = IO0SET;                        // 读取当前LED1控制值
   if( (i&LED1CON)==0 )                // 控制LED1输出
   {  IO0SET = LED1CON;
   }
   else
   {  IO0CLR = LED1CON;
   }
   T0IR = 0x01;

     
   VICIntEnable = bak;
}        
/****************************************************************************
* 名称:IRQ_Eint0()
* 功能:外部中断EINT0服务函数,取反LED1。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void  IRQ_Eint0(void)
{  uint32  i, bak;

   bak = VICIntEnable;                // 备份当前VICIntEnable的值
   VICIntEnClr = (1<<14)|(1<<16);    // 禁止当前优先级中断及低优先级中断
   VICVectAddr = 0x00;                // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断
   EnableIRQ();                        // 打开IRQ中断允许
   
   i = IO0SET;                        // 读取当前LED1控制值
   if( (i&LED1CON)==0 )                // 控制LED1输出
   {  IO0SET = LED1CON;
   }
   else
   {  IO0CLR = LED1CON;
   }
   
   
   while( (EXTINT&0x01)!=0 )        // 等待外部中断信号恢复为高电平    
   {  EXTINT = 0x01;                // 清除EINT0中断标志
   }
     
   VICIntEnable = bak;
}        



/****************************************************************************
* 名称:IRQ_Eint3()
* 功能:外部中断EINT3服务函数,取反LED4。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void   IRQ_Eint2(void)
{  uint32  i,bak;
   
   bak = VICIntEnable;
   VICIntEnClr = (1<<16);            
   VICVectAddr = 0x00;                
   EnableIRQ();
   
   i = IO0SET;                        // 读取当前LED4控制值
   if( (i&LED4CON)==0 )                // 控制LED4输出
   {  IO0SET = LED4CON;
   }
   else
   {  IO0CLR = LED4CON;
   }
   
   while( (EXTINT&0x04)!=0 )        // 等待外部中断信号恢复为高电平    
   {  EXTINT = 0x04;                // 清除EINT3中断标志
   }
   
   EXTINT = 0x04;
   VICIntEnable = bak;
}
            

/****************************************************************************
* 名称:main()
* 功能:初始化外部中断0、3为向量中断,并设置为下降沿触发模式,然后等待外部中断。
* 说明:在STARTUP.S文件中使能IRQ中断(清零CPSR中的I位)。
****************************************************************************/
int  main(void)
{  PINSEL0 = 0x0000C000;            
   PINSEL1 = 0x00000000;            // 设置管脚连接,P0.1设置为EINT0,P0.7设置为EINT2
   PINSEL2 = 0x00000000;
   IO0DIR = LED1CON|LED4CON;        // 设置B1控制口为输出,其它I/O为输入
   
   /*  打开EINT0、EINT3中断(设置向量控制器,即使用向量IRQ) */
   VICIntSelect = 0x00000000;        // 设置所有中断分配为IRQ中断
     
   T0PR = 99;
   T0MCR = 0x03;
   T0MR0 = 110592/2;
   T0IR = 0xffffffff;
   T0TC = 0;
   T0TCR = 0x03;
   T0TCR = 0x01;

   
   //VICVectCntl0 = 0x20|14;            // 分配EINT0中断到向量中断0
   //VICVectAddr0 = (int)Eint0_Handler;     // 设置中断服务程序地址
   VICVectCntl0 = 0x20|4;            // 分配TIMER0中断到向量中断0
   VICVectAddr0 = (int)Timer0_Handler;  //设置中断服务程序地址
   VICVectCntl1 = 0x20|16;            // 分配EINT2中断到向量中断1
   VICVectAddr1 = (int)Eint2_Handler;     // 设置中断服务程序地址
   EXTINT = 0x04;                    // 清除EINT0、EINT2中断标志    
   EXTMODE = 0x04;                    //置外部中断0和2为边沿触发方式
   
   VICIntEnable = (1<<4)|(1<<16);    // 使能EINT0、EINT2中断
   EnableIRQ();
   
   while(1);                        // 等待中断
   return(0);
}
可以看出源程序是两个外部中断0和2嵌套,在EINT2中打开EINT0,KEY1控制EINT0,KEY2控制EINT2,板子上的现象是,按住KEY1,键KEY2多次动作只被记住一次,按住KEY2,键KEY1动作不受影响.
修改后的程序运行结果理论上是,在EINT2中开TIMER0中断,按住KEY时,EINT2控制的LED不闪,TIMER0控制的LED闪,可我实际看到的是它们同时闪,EINT2已经被我设定为下边沿触发,当按下KEY不放时EINT2应该只中断一次,即LED亮或灭一次,并保持不动啊!WHY? 8: 总结。经过多次的试验,发现将外部中断改为电平触发,结果正常.
在EINT2中开TIMER0中断. 9: 该贴 一定要顶

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]