这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » ARTX ARTX菜鸟中断嵌套笔记

共2条 1/1 1 跳转至

ARTX ARTX菜鸟中断嵌套笔记

院士
2006-09-17 18:14:16     打赏
ARTX ARTX菜鸟中断嵌套笔记



关键词: 菜鸟     中断     嵌套     笔记    

院士
2006-12-22 22:43:00     打赏
2楼
问 /*--------------------------------------------------------
               ARTX菜鸟中断嵌套笔记
代码长度  6660(优化)
HotPower@126.com       2005.9.17 于西安大雁塔村队部
---------------------------------------------------------*/
#include <ARTX.h>
#include <LPC213x.H>    // Philips Peripheral Registers
#include <LPC213xDEF.H>    //ARM菜鸟HotPower创建定义文件

//本程序共有7个任务,需改写OS_TASK_CNT为7
OS_TID IdTask, IdTask1, IdTask2;
OS_TID IdTaskEint0, IdTaskEint1, IdTaskEint2, IdTaskEint3;

void TaskMain (void) __task;
void Task1 (void) __task;
void Task2 (void) __task;

void TaskEint0 (void) __task;//外部中断Eint0处理任务
void TaskEint1 (void) __task;//外部中断Eint1处理任务
void TaskEint2 (void) __task;//外部中断Eint2处理任务
void TaskEint3 (void) __task;//外部中断Eint3处理任务

volatile unsigned int FCount = 1;

volatile unsigned int Count = 0;
volatile unsigned int Count1 = 0;
volatile unsigned int Count2 = 0;
volatile unsigned int Count10 = 0;
volatile unsigned int Count20 = 0;

volatile unsigned int Sum0 = 0;
volatile unsigned int Sum00 = 0;
volatile unsigned int Sum1 = 0;
volatile unsigned int Sum10 = 0;
volatile unsigned int Sum2 = 0;
volatile unsigned int Sum20 = 0;
volatile unsigned int Sum3 = 0;
volatile unsigned int Sum30 = 0;
unsigned int Eint1Count = 0;

void EINT0IRQ(void) __irq;//声明中断ISR函数
void EINT1IRQ(void) __irq;//声明中断ISR函数
void EINT2IRQ(void) __irq;//声明中断ISR函数
void EINT3IRQ(void) __irq;//声明中断ISR函数

// Macros for Interrupt Nesting
#define IENABLE                             /* Nested Interrupts Entry */   \
  __asm { MRS     LR, SPSR      }           /* Copy SPSR_irq to LR     */   \
  __asm { STMFD   SP!, {LR}     }           /* Save SPSR_irq           */   \
  __asm { MSR     CPSR_c, #0x1F }           /* Enable IRQ (Sys Mode)   */   \
  __asm { STMFD   SP!, {LR}     }           /* Save LR                 */   \

#define IDISABLE                            /* Nested Interrupts Exit  */   \
  __asm { LDMFD   SP!, {LR}     }           /* Restore LR              */   \
  __asm { MSR     CPSR_c, #0x92 }           /* Disable IRQ (IRQ Mode)  */   \
  __asm { LDMFD   SP!, {LR}     }           /* Restore SPSR_irq to LR  */   \
  __asm { MSR     SPSR_cxsf, LR }           /* Copy LR to SPSR_irq     */   \

void ei() __ARM    __swi(8)
{
  __asm
  {
    STMFD   SP,{R0}
    MRS     R0, SPSR
    BIC     R0, R0, #0xc0;//打开irq,fiq中断
    MSR     SPSR_c, R0
    LDMFD   SP,{R0}
  }
}

void di() __ARM __swi(9)
{
  __asm
  {
    STMFD   SP,{R0}
    MRS     R0, SPSR
    ORR     R0, R0, #0xc0;//关闭irq,fiq中断
    MSR     SPSR_c, R0
    LDMFD   SP,{R0}
  }
}

void EINT0IRQ (void) __irq{//IRQ中断函数EINT0IRQ被挂接在VICVectCntl0
  if (VICIRQStatus & (1 << VICIntSel_EINT0)) {
    IOPIN1 ^= (1 << P1_16);    //取反P1.16
    isr_evt_set (0x1000, IdTaskEint0);//退出中断后立即执行TaskEint0任务
  }
  VICSoftIntClr = (1 << VICIntSel_EINT0);
  EXTINT = (1 << EINT0);    //清除INT0中断标志
  VICVectAddr = 0;
}

void EINT1IRQ (void) __irq{//IRQ中断函数EINT1IRQ被挂接在VICVectCntl1
  if (VICIRQStatus & (1 << VICIntSel_EINT1)) {
    IOSET1 = (1 << P1_17);    //P1.17=1
    EXTINT = (1 << EINT1);    //清除INT1中断标志
    IENABLE;//开放中断嵌套
    PINSEL0 &= ~(P0_3_EINT1 << P0_3_PINSEL); //重新选择P0.3为普通IO引脚!!!
    while ((IOPIN0 & (1 << P0_3)) == 0);//等待P0.3变为高电平,注意没上句程序将不能测IO引脚电平!!!
    PINSEL0 |= (P0_3_EINT1 << P0_3_PINSEL); //重新选择P0.3为INT1外部中断引脚!!!
    IDISABLE;//关闭中断嵌套
    isr_evt_set (0x2000, IdTaskEint1);//退出中断后立即执行TaskEint1任务
    IOCLR1 = (1 << P1_17);    //P1.17=0
    VICSoftIntClr = (1 << VICIntSel_EINT1);
  }
  VICVectAddr = 0;
}

void EINT2IRQ (void) __irq{//IRQ中断函数EINT2IRQ被挂接在VICVectCntl2
  if (VICIRQStatus & (1 << VICIntSel_EINT2)) {
    IOPIN1 ^= (1 << P1_18);    //取反P1.18
    isr_evt_set (0x3000, IdTaskEint2);//退出中断后立即执行TaskEint2任务
  }
  EXTINT = (1 << EINT2);    //清除INT2中断标志
  VICSoftIntClr = (1 << VICIntSel_EINT2);
  VICVectAddr = 0;
}

void EINT3IRQ (void) __irq{//IRQ中断函数EINT3IRQ被挂接在VICVectCntl3
  if (VICIRQStatus & (1 << VICIntSel_EINT3)) {
    IOPIN1 ^= (1 << P1_19);    //取反P1.19
    isr_evt_set (0x4000, IdTaskEint3);//退出中断后立即执行TaskEint3任务
  }
  EXTINT = (1 << EINT3);    //清除INT3中断标志
  VICSoftIntClr = (1 << VICIntSel_EINT3);
  VICVectAddr = 0;
}





void TaskMain (void) __task {
  IdTask = os_tsk_self ();//取本任务ID
  os_tsk_prio_self (13);//任务级别
  IdTask1 = os_tsk_create (Task1, 11);//创建Task1任务及级别
  IdTask2 = os_tsk_create (Task2, 11);//创建Task2任务及级别
  IdTaskEint0 = os_tsk_create (TaskEint0, 100);//创建TaskEint0任务及级别
  IdTaskEint1 = os_tsk_create (TaskEint1, 100);//创建TaskEint1任务及级别
  IdTaskEint2 = os_tsk_create (TaskEint2, 100);//创建TaskEint2任务及级别
  IdTaskEint3 = os_tsk_create (TaskEint3, 100);//创建TaskEint3任务及级别

  for (;;) {
    Count ++;//TaskMain任务事件计数
    if ((Count % 10) == 0) os_evt_set (FCount, IdTask1);//每10次执行Task1任务
    else os_evt_set (0x2222, IdTask2);//其他9次执行Task2任务
    IOPIN0 ^= (1 << P0_16);    //取反P0.16
    os_dly_wait (1);//延时10mS并将控制权交还OS
  }
}

void Task1 (void) __task {
OS_RESULT result;
unsigned int i;    
  for (;;) {
    result = os_evt_wait_or(0xffff, 0xffff);//等待Task1任务事件发生
    if(result == OS_R_EVT) {//未超时
      i = os_evt_get();
      switch(i) {
        case 1:    FCount = 2;
                break;
        case 2:    FCount = 3;
                break;
        case 3:    FCount = 4;
                break;
        case 4:    FCount = 1;
                break;
      }
      Count1 ++;//Task1任务事件计数
    }
    else {
      Count10 ++;
    }
  }
}

void Task2 (void) __task {
OS_RESULT result;    
//volatile unsigned int Count2 = 0;
  for (;;) {
    result = os_evt_wait_and(0x2222, 0xffff);//等待Task2任务事件发生
    if(result == OS_R_EVT) {//未超时
      Count2 ++;//Task2任务事件计数
    }
    else {
      Count20 ++;
    }
  }
}

void TaskEint0 (void) __task {
OS_RESULT result;    
  for (;;) {
    result = os_evt_wait_and(0x1000, 0xffff);//等待TaskEint0任务事件发生
    if(result == OS_R_EVT) {//未超时
      Sum0 ++;//TaskEint0任务事件计数
    }
    else {
      Sum00 ++;
    }
  }
}


void TaskEint1 (void) __task {
OS_RESULT result;    
//unsigned int Eint1Count = 0;
  for (;;) {
    result = os_evt_wait_and(0x2000, 0xffff);//等待TaskEint1任务事件发生
    if(result == OS_R_EVT) {//未超时
      Sum1 ++;//TaskEint1任务事件计数
      IOSET1 = (1 << P1_23);
      Eint1Count = 0;
      PINSEL0 &= ~(P0_3_EINT1 << P0_3_PINSEL); //重新选择P0.3为普通IO引脚!!!
      while ((IOPIN0 & (1 << P0_3)) == 0) {//等待P0.3变为高电平,注意没上句程序将不能测IO引脚电平!!!
        os_dly_wait (1);//延时10mS并将控制权交还OS
        Eint1Count ++;
      }
      PINSEL0 |= (P0_3_EINT1 << P0_3_PINSEL); //重新选择P0.3为INT1外部中断引脚!!!
      if (Eint1Count >= 2) {//20mS
        if (Eint1Count >= 100) {//1000mS
          IOPIN1 |= (1 << P1_22);//可认为长压键
        }
        else {//大于20mS小于1S
          IOPIN1 &= ~(1 << P1_22);//可认为短压键
        }
      }
      else {//认为无键压下
      }
      IOCLR1 = (1 << P1_23);
    }
    else {
      Sum10 ++;
    }
  }
}
//以上结论为:非IO配置的引脚不能测试IO引脚,否则只能临时改变IO配置才能正确测试IO引脚!!!


void TaskEint2 (void) __task {
OS_RESULT result;    
  for (;;) {
    result = os_evt_wait_and(0x3000, 0xffff);//等待TaskEint2任务事件发生
    if(result == OS_R_EVT) {//未超时
      Sum2 ++;//TaskEint2任务事件计数
    }
    else {
      Sum20 ++;
    }
  }
}

void TaskEint3 (void) __task {
OS_RESULT result;    
  for (;;) {
    result = os_evt_wait_and(0x4000, 0xffff);//等待TaskEint3任务事件发生
    if(result == OS_R_EVT) {//未超时
      Sum3 ++;//TaskEint3任务事件计数
    }
    else {
      Sum30 ++;
    }
  }
}


void main (void) {
  di();//关irq,fiq中断
  IODIR0         = 0;//全部设置为输入方式
  IODIR0        |= (1 << P0_16);//设置LED输出方式

  IODIR1         = 0;//全部设置为输入方式
  IODIR1         = (1 << P1_23) | (1 << P1_22) | (1 << P1_21) | (1 << P1_20)
                  |(1 << P1_19) | (1 << P1_18) | (1 << P1_17) | (1 << P1_16);//设置LED输出方式

  PINSEL0         = 0;//全部选择第1功能
  PINSEL0          |= (P0_14_EINT1 << P0_14_PINSEL) //选择P0.14为INT1外部中断引脚
                     | (P0_7_EINT2 << P0_7_PINSEL)   //选择P0.7为INT2外部中断引脚
                     | (P0_15_EINT2 << P0_15_PINSEL) //选择P0.15为INT2外部中断引脚
                     | (P0_9_EINT3 << P0_9_PINSEL)   //选择P0.9也为INT3外部中断引脚
                     | (P0_1_EINT0 << P0_1_PINSEL)   //选择P0.1也为INT0外部中断引脚
                     | (P0_3_EINT1 << P0_3_PINSEL);  //选择P0.3也为INT1外部中断引脚
  PINSEL1         = 0;//全部选择第1功能
  PINSEL1          |=
//                  (P0_16_EINT0 << P0_16_PINSEL) //选择P0.16为INT0外部中断引脚
//                 |
                    (P0_20_EINT3 << P0_20_PINSEL) //选择P0.20也为INT3外部中断引脚
                     | (P0_30_EINT3 << P0_30_PINSEL);//选择P0.30也为INT3外部中断引脚(Keil仿真不了,非也,原来PINSEL1没初始化!!!)
//以上多引脚配置为中断功能但只有管脚号小的才能引发中断!!!
//即
//Eint0---P0.1(有效),P0.16(无效)
//Eint1---P0.3(有效),P0.14(无效)
//Eint2---P0.7(有效),P0.15(无效)
//Eint3---P0.9(有效),P0.20(无效),P30(无效)

//Eint3---P0.9(有效),P0.20(无效)
//Eint3---P0.9(有效),P30(无效)
//Eint3---P0.20(有效),P30(无效)

//以上只是通过Keil仿真得出,可能有误导之嫌!!!
//不知如何才能让多引脚引发中断???
  
  EXTPOLAR       &= ~((1 << EXTPOLAR0) //INT0为低电平有效
                  |  (1 << EXTPOLAR1)  //INT1为低电平有效
                  |  (1 << EXTPOLAR2)  //INT2为低电平有效
                  |  (1 << EXTPOLAR3));//INT3为低电平有效

  EXTPOLAR       |= (1 << EXTPOLAR0); //INT0为高电平有效


  EXTMODE        |= (1 << EXTMODE0) //设置INT0为边沿触发
                  | (1 << EXTMODE1) //设置INT1为边沿触发(将原来的电平触发改为边沿触发不要兜死OS且进行IO测试演示)
                  | (1 << EXTMODE2) //设置INT2为边沿触发
                  | (1 << EXTMODE3);//设置INT3为边沿触发

//  EXTMODE        &= ~(1 << EXTMODE1);//设置INT1为电平触发(屏蔽此句为了不兜死OS且进行IO测试演示,见任务TaskEint1()内的处理)


  VICVectCntl0   = VICIntSel_Enable//使能IRQ中断
                 | VICIntSel_EINT0;//获取EINT0的IRQ级别
  VICVectAddr0   = (long) EINT0IRQ;//取INT0中断服务地址


  VICVectCntl1   = VICIntSel_Enable//使能IRQ中断
                 | VICIntSel_EINT1;//获取EINT1的IRQ级别
  VICVectAddr1   = (long)EINT1IRQ;//取INT1中断服务地址

  VICVectCntl2   = VICIntSel_Enable//使能IRQ中断
                 | VICIntSel_EINT2;//获取EINT2的IRQ级别
  VICVectAddr2   = (long)EINT2IRQ;//取INT2中断服务地址

  VICVectCntl3   = VICIntSel_Enable//使能IRQ中断
                 | VICIntSel_EINT3;//获取EINT3的IRQ级别
  VICVectAddr3   = (long)EINT3IRQ;//取INT3中断服务地址

  EXTINT = (1 << EINT0) | (1 << EINT1) | (1 << EINT2) | (1 << EINT3);    //清除INT中断标志

  VICIntEnable   = (1 << VICIntSel_EINT0) //使能EINT0中断
                 | (1 << VICIntSel_EINT1) //使能EINT1中断
                 | (1 << VICIntSel_EINT2) //使能EINT2中断
                 | (1 << VICIntSel_EINT3);//使能EINT3中断

  ei();//开irq,fiq中断
  os_sys_init (TaskMain);//启动ARTX,此函数并不返回main()
}
1: 本帖只是经过软仿真,不知那位"地主"能给硬件调试一番???纸上谈兵确实很乏味...有苦难言!!! 2: 多引脚触发中断需要触发方式相同然后读引脚状态即可判断

共2条 1/1 1 跳转至

回复

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