aerkate

MSP430中断以及一个键盘的例子【原创】

0
阅读(2757)

 

最近在学习和实践的过程中接触到了线程的概念。当你需要处理一大堆数据或者等待一个事件发生时候,系统其实并不需要等在那里,只需建立一个线程,适时的让它在后台运行,处理这些很占用系统的事件。我想这与中断的功能很是相似,有些时候你让程序卡在那里仅仅是为了等待一个参数的改变,而这个参数完全可以在中断中实现修改,所以巧妙的使用中断对于高效的程序是必须的。

 

MSP430提供了3类中断:

系统复位;

非可屏蔽中断;

可屏蔽中断。

 

下表列出了三种中断各自的中断源:

系统复位中断源

可屏蔽中断中断源

可屏蔽中断中断源

加电源电压

RST/NMI引脚有上升信号

看门狗定时器溢出(定时器模式)

RST/NMI引脚加低电平

振荡器故障

其他有中断能力的外部模块

看门狗定时器溢出(看门狗模式)

 

 

看门狗定时器密钥不符

 

 

 

MSP430中断优先级结构图如上图所示。各模块的中断优先级由模块连接链决定,越接近CPU/NMIRS的模块,其中断优先级越高。

 

 

上图给出了中断的执行过程,相信大家可以在任何其他的书本中找到类似的流程图。中断发生,全局中断开启,并且允许相应此中断,此时需要等待当前指令完成。保存短点和寄存器值。然后清除寄存器的值以及中断标志位,如果同时有多个中断发生则选择优先级最高的执行,进入中断服务子程序,执行完后,恢复断点,继续执行主程序。通过这种前后台程序的切换控制程序运行,得到高效率。

 

下面让我们来看一个4x4键盘的例子。我们通过中断的方式来感知键盘的操作,通过一个键盘扫描程序来确认按下的键,然后通过数码管动态的显示出来。

#include<msp430x24x.h>

static int nRes;

int nP10,nP11,nP12,nP13;

static char LEDData[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};

void delay(int number)

{

 while(--number);

}

 

int KeyProcess(void)

{

  int nres=0;

   //P1.4输出低电平

  P1OUT = 0xe0;

  nP10 = P1IN&BIT0;

  if (nP10 == 0) nres = 13;

  nP11 = (P1IN & BIT1) >> 1;

  if (nP11 == 0) nres = 14;

  nP12 = (P1IN & BIT2) >> 2;

  if (nP12 == 0) nres = 15;

  nP13 = (P1IN & BIT3) >> 3;

  if (nP13 == 0) nres = 16;

 

 

   //P1.5输出低电平

  P1OUT = 0xd0;

  nP10 = P1IN&BIT0;

  if (nP10 == 0) nres = 9;

  nP11 = (P1IN & BIT1) >> 1;

  if (nP11 == 0) nres = 10;

  nP12 = (P1IN & BIT2) >> 2;

  if (nP12 == 0) nres = 11;

  nP13 = (P1IN & BIT3) >> 3;

  if (nP13 == 0) nres = 12;

 

 

    //P1.6输出低电平

  P1OUT = 0xb0;

  nP10 = P1IN&BIT0;

  if (nP10 == 0) nres = 5;

  nP11 = (P1IN & BIT1) >> 1;

  if (nP11 == 0) nres = 6;

  nP12 = (P1IN & BIT2) >> 2;

  if (nP12 == 0) nres = 7;

  nP13 = (P1IN & BIT3) >> 3;

  if (nP13 == 0) nres = 8;

 

    //P1.7输出低电平

  P1OUT = 0x70;

  nP10 = P1IN&BIT0;

  if (nP10 == 0) nres = 1;

  nP11 = (P1IN & BIT1) >> 1;

  if (nP11 == 0) nres = 2;

  nP12 = (P1IN & BIT2) >> 2;

  if (nP12 == 0) nres = 3;

  nP13 = (P1IN & BIT3) >> 3;

  if (nP13 == 0) nres = 4;

 

   

   while(!(nP10 && nP11  && nP12  && nP13 ))

   {

     P1OUT = 0x00; //恢复以前值

  //读取各个管脚的状态

    nP10 = P1IN&BIT0;

    nP11 = (P1IN&BIT1) >> 1;

    nP12 = (P1IN&BIT2) >> 2;

    nP13 = (P1IN&BIT3) >> 3;

   }

 

   

   return nres;

}

 

void display(int number)

{

  int tens,single;

  tens = number/10;

  single = number%10;

  P4OUT = LEDData[single];

  P6OUT = 0x01;

  delay(100);

  P6OUT = 0x00;

  P4OUT = LEDData[tens];

  P6OUT = 0x02;

  delay(100);

  P6OUT = 0x00;

}

void main()

{

  WDTCTL=WDTPW+WDTHOLD; //关闭看门狗

    //将P1口的所有的管脚在初始化的时候设置为输入方式

  P1DIR=0;

  //将P1口所有的管脚设置为一般I/O口

  P1SEL=0;

  //将P1.4、P1.5、P1.6、P1.7设置为输出方向

  P1DIR |= BIT4+BIT5+BIT6+BIT7;

 

  //输出低电平

  P1OUT = 0x00;

  P2DIR |= BIT0+BIT1+BIT2+BIT3;  // when there is a interrupt there be a led indicate

  P2OUT = 0x00;

  P4DIR |= 0xff;  // P4、P5口用于输出字型码

  //P5DIR |= 0xff;

  P6DIR |= BIT0+BIT1;  // P6.0 P6.1用于片选

  P1IE |= BIT0;

  P1IE |= BIT1;

  P1IE |= BIT2;

  P1IE |= BIT3;

  P1IES |= (BIT0+BIT1+BIT2+BIT3);// pattern of the trigger

  _EINT();

  nRes=0;

  while (1)

  {

    display(nRes);

  }

}

#pragma vector= PORT1_VECTOR

__interrupt void Port_1(void)

{

  P1OUT = 0x00;

  nRes=KeyProcess();

  P1IFG = 0x00;

}