新闻  |   论坛  |   博客  |   在线研讨会
Zigbee基础实验(2)—通过中断控制LED
luker | 2016-02-24 16:11:19    阅读:4134   发布文章

通过本次实验,将会清楚如何捕获一个外部中断和CC2530捕获外部中断后的处理流程

本次实验所学到的新寄存器为:

P0IEN:各个控制口的中断使能,0为中断禁止,1为中断使能。
D7
D6
D5
D4
D3
D2
D1
D0
P0_7 P0_6 P0_5 P0_4 P0_3 P0_2 P0_1 P0_0

P0INP:设置各个I/O口的输入模式,0为上拉/下拉,1为三态模式
D7
D6
D5
D4
D3
D2
D1
D0
P0_7模式
P0_6模式 P0_5模式 P0_4模式 P0_3模式 P0_2模式 P0_1模式 P0_0模式

PICTL:D0~D3设置各个端口的中断触发方式,0为上升沿触发,1为下降沿触发。
 D7控制I/O引脚在输出模式下的驱动能力。选择输出驱动能力增强来补偿引脚DVDD的低I/O电压,确保在较低的电压下的驱动能力和较高电压下相同。0为最小驱动能力增强。1为最大驱动能力增强。
D7
D6
D5
D4
D3
D2
D1
D0
I/O驱动能力
未用
未用
未用
P2_0~P2_4
P1_4~P1_7
P1_0~P1_3
P0_0~P0_7

IEN1:中断使能1,0为中断禁止,1为中断使能
D7
D6
D5
D4
D3
D2
D1
D0
未用
未用
端口0 定时器4
定时器3
定时器2 定时器1 DMA传输

P0IFG:中断状态标志寄存器当输入端口有中断请求时,相应的标志位将置1。
D7
D6
D5
D4
D3
D2
D1
D0
P0_7
P0_6 P0_5 P0_4 P0_3 P0_2 P0_1 P0_0


源代码:
#include
#define uint  unsigned int
#define uchar unsigned char
//定义控制灯的端口
#define RLED   P1_0      //定义LED1为P10口控制
#define YLED   P1_1      //定义LED2为P11口控制
#define GLED   P1_4      //定义LED3为P14口控制
#define KEY1   P0_1       //定义按键为P01口控制
//函数声明
void Delay(uint);                     //延时函数声明
void Initial(void);                     //初始化函数声明
void InitKey(void);                  //初始化按键函数声明
uchar KeyScan(void);            //按键扫描函数声明

uchar Keyvalue = 0 ;               //定义变量记录按键动作
uint  KeyTouchtimes = 0 ;        //定义变量记录按键次数

void Delay(uint n)
{
    uint i;
    for(i = 0;i     for(i = 0;i     for(i = 0;i     for(i = 0;i     for(i = 0;i }

void InitKeyINT(void)
{
  P0SEL &= ~0X02;  //普通功能
  P0DIR &= ~0X02; //P0_1I/O口,设置为输入模式
  P0INP |= 0x02; //上拉    
  
  P0IEN |= 0X02;   //P01设置为中断方式
  PICTL |= 0X01;   //下降沿触发
  EA = 1;
  IEN1 |= 0X20;   // P0设置为中断方式;
  P0IFG |= 0x00;   //初始化中断标志位  
}

void InitIO(void)
{
    P1DIR |= 0x13; //P10、P11、P14定义为输出
    RLED = 0;
    GLED = 0;
    YLED = 0;    //LED灯初始化为灭
}
 
#pragma vector = P0INT_VECTOR      //中断服务子程序
 __interrupt void P0_ISR(void)             
 {
        if(P0IFG0)            //按键中断
        {
          P0IFG = 0;
          Delay(25000);  
          if(P0IFG==0)         //按键中断
        {
          Delay(100);  
          KeyTouchtimes = KeyTouchtimes+1;  //每次中断发生时记录按键次数加1
        }  
        }       
        P0IF = 0;             //清中断标志
 }
 
void main(void)
{
    InitIO();    
        InitKeyINT();               //调用初始化函数
                 
        while(1)
        {
            if(KeyTouchtimes ==1)       //红灯亮、其余灯不亮
               {
           RLED = 1;                
           GLED = 0;
           YLED = 0;          
              }
         if(KeyTouchtimes == 2)        //红灯亮、黄灯亮、绿灯不亮
               {
                 RLED=1;
                 YLED=1;
                 GLED=0;         
               }
          if(KeyTouchtimes == 3)      //三盏灯全亮
               {
                 RLED=1;
                 YLED=1;
                 GLED=1;         
                }
         if(KeyTouchtimes == 4)      //全部灯灭
           {           
           RLED = 0;
           GLED = 0;
           YLED = 0;                   
           KeyTouchtimes =0;           //重置按键次数记录变量
                }
        }
        }

实验总结
CC2530中断机制:
①当按键S1按下时,因为S1所对应的I/O口为P0_1,所以P0端口将会发出一个中断请求,并自动将P0IFG寄存器对应位(即D1位)置1,等待CPU响应
②CPU在执行完一条指令之后就会检测是否有中断请求,如果检测到中断请求并且IEN1的D5位为1和P0IEN的D1为 1时,对应的中断使能位中断使能,则根据中断类型号获得中断向量,根据中断向量得到中断服务子程序的地址,执行终端服务子程序。当中断服务子程序执行完毕 后返回执行原来的程序。

P0IEN寄存器与IEN1寄存器的区别:
P0IEN和IEN1同样都是中断屏蔽寄存器,P0IEN控制P0口每一个端口的中断使能,IEN1控制整个P0的中断使能。当IEN1中设置了P0口中 断屏蔽时(D5=0),无论P1IEN中对应的使能位设置成屏蔽还是使能,该I/O发出的中断请求CPU都不予接受。例如:若将本例中 InitKeyINT()函数中的 IEN1 |= 0X20; 代码行注释掉,S1按下后LED将没有变化。


中断服务子程序的写法:
我们先看头文件中的部分代码:
#define  T1_VECTOR      VECT(  9, 0x4B )   /*  Timer 1 (16-bit) Capture/Compare/Overflow   */
#define  T2_VECTOR      VECT( 10, 0x53 )   /*  Timer 2 (MAC Timer)                         */
#define  T3_VECTOR      VECT( 11, 0x5B )   /*  Timer 3 (8-bit) Capture/Compare/Overflow    */
#define  T4_VECTOR      VECT( 12, 0x63 )   /*  Timer 4 (8-bit) Capture/Compare/Overflow    */
#define  P0INT_VECTOR   VECT( 13, 0x6B )   /*  Port 0 Inputs                               */

通过datasheet可知,0X6B为P0口的中断向量,#define  P0INT_VECTOR   VECT( 13, 0x6B )将P0口的中断向量定位为P0INT_VECTOR。同理,上面所列出的代码还将其他的中断向量分别作了定义。得知了中断向量后,我们就可以编写中断服务子程序。格式如下:
#pragma vector = 中断向量      
 __interrupt void 任意函数名(void)             
 {
                         //中断处理,处理完成后通常需要清除中断标志。
 }

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客