• CC2530外部中断


    一、中断基础概念

     内核外设之间的主要交互方式有两种:轮询中断。中断系统使得内核具备了应对突发事件的能力。

    在执行CPU当前程序时,由于系统中出现了某种急需处理的情况,CPU暂停正在执行的程序,转而去执行另外一段特殊程序来处理出现的紧急事务,处理结束后,CPU自动返回到原来暂停的程序中去继续执行。 这种程序在执行过程中由于外界的原因而被中间打断的情况,称为中断

    采用中断技术后,可以为计算机系统带来以下好处:

    1)实现分时操作

    速度较快的CPU和速度较慢的外设可以各做各的事情,外设可以在完成工作后再与CPU进行交互,而不需要CPU去等待外设完成工作,能够有效提高CPU的工作效率。

    2)实现实时处理

    在控制过程中,CPU能够根据当时情况及时做出反应,实现实时控制的要求。

    3)实现异常处理

    系统在运行过程中往往会出现一些异常情况,中断系统能够保证CPU及时知道出现的异常,以便CPU去解决这些异常,避免整个系统出现大的问题。

     两个重要的概念:

            <1> 中断服务函数: 内核响应中断后执行的相应处理程序。例如ADC转换完成中断被响应后,CPU执行相应的中断服务函数,该函数实现的功能一般是从ADC结果寄存器中取走并使用转换好的数据。

            <2> 中断向量:中断服务程序的入口地址,当CPU响应中断请求时,会跳转到该地址去执行代码。

    二、 CC2530中断

    CC2530具有18个中断源,每个中断源都有它自己的位于一系列SFR 寄存器中的中断请求标志。相应标志位请 求的每个中断可以分别使能或禁用。

    Tip:

    (1)当调用中断服务例程时清除硬件。

    (2)另外的 IRQ 掩码和 IRQ 标志位存在。

    三、CC2530中断处理函数格式书写

    中断服务函数与一般自定义函数不同,有特定的书写格式

    #pragma vector = 中断向量
    __interrupt void 函数名称 (void)
    {
    /*此处编写中断处理函数的具体程序*/
    PxIFG = 0; //先清除Px引脚的中断状态标志位
    PxIF = 0; //再清除Px端口组的中断状态标志位
    }

    <1> 在每一个中断服务函数之前,都要加上一句起始语句

      #pragma vector = <中断向量>

       <中断向量>表示接下来要写的中断服务函数是为那个中断源服务的,该 语句有两种写法:

     #pragma  vector = 0x7B或者#pragma  vector = P1INT_VECTOR

     前者是中断向量的入口地址,后者是头文件“ioCC2530.h”中的宏定义。

    <2> _ _interrupt关键字表示该函数是一个中断服务函数,<函数名称>可以 自定义,函数体不能带有参数,也不能有返回值

    四、外部中断

    (1)CC2530的P0、P1和P2端口中的每个引脚都具有外部中断输入功能,要使某些引脚具有外部中断功能,需要对IENx寄存器、PxIEN寄存器和PICTL寄存器进行适当的设置。 除了各个中断源都有自己的中断使能开关之外,中断系统还有一个总开关,可以同“EA = 1;”来打开总中断。

    IENx寄存器   使能端口组的中断功能。

    PxIEN寄存器   使能具体的外部中断引脚。

     

    PICTL寄存器    设置中断触发方式。

     

    (2)P0、P1和P2端口分别使用P0IFP1IFP2IF作为中断标志位,任何一个端口组上的引脚产生外部中断时,都会将对应端口组的中断标志自动置位。注意,外部中断标志必须在中断服务函数中手工清除,否则CPU会反复进入中断。 端口状态标志寄存器P0IFGP1IGFP2IFG,分别对应3个端口中各引脚的中断触发状态,当某引脚发生外部中断触发时,对应的标志位会自动置位,这个标志同样需要手工清除。

     

    题目:

    Zigbee小模块上SW1按键设置为外部中断输入引脚。在中断服务函数中,控制一个LED6灯的开关切换,也就是原来LED是点亮的熄灭,原来熄灭的点亮。同时在主程序中,运行一段跑马灯程序,使LED3和LED4轮流点亮和熄灭。

    思路:

    1)端口初始化和跑马灯程序

    2)定义一个外部中断初始化函数,将SW1引脚,即P1_ _2引脚配置成外部中断输入端口,将其中断触发方式设置为下降沿触发。

    3)为外部中断定义-一个中断服务函数,要照中断服务函数的书写格式编程,注意要在中断服务函数中把相应的中断标志位清除。必须先清除引脚的中断标志,再清除端口组的中断标志。

    解题:

    1】设计外部中断初始化函数Init_INTP()

            外部中断初始化函数,主要是完成跟中断相关的特殊功能寄存器配置工作:

            <1> 配置IENx寄存器,使能端口组的中断功能。

            <2> 配置PxIEN寄存器,使能具体的外部中断引脚。

            <3> 配置PICTL寄存器,设置中断触发方式。

    1 void Init_INTP()
    2 {
    3   IEN2 |= 0x10;         //端口1中断使能 0001 0000 端口1 中断使能
    4   P1IEN |= 0x04;        //端口P1_2外部中断使能   0000 0100 P1_2 使能具体的外部中断引脚。
    5   PICTL |= 0x02;        //端口P1_0到P1_3下降沿触发  0000 0010 P1_0和P1_1  下降沿触发
    6   EA = 1;               //使能总中断   
    7 }

    2设计外部中断服务函数Int1_Sevice()

            在编写中断服务函数的时候,书写格式要正确,中断向量不能搞错。特别要注意:在函数里面把端口组和引脚的标志位清除,否则CPU将会反复进入中断,必须先清除引脚标志位PxIFG,再清除端口组标志位PxIF。

    #pragma vector = P1INT_VECTOR     //外部中断1的向量入口
    __interrupt void Int1_Sevice()
    {
      LED6 = ~LED6;
    /*先清除引脚标志位,再清除端口标志位,否则会不断进入中断*/
      P1IFG &= ~ 0x04;        //软件清除P1_2引脚的标志位  
      P1IF = 0;               //软件清除P1端口组的标志位
    }

    最终代码:

     1 #include "ioCC2530.h"
     2 
     3 #define  LED6   P1_4
     4 #define  LED3   P1_0
     5 #define  LED4   P1_1
     6 /*===================延时函数=========================*/
     7 void Delay(unsigned int t)
     8 {
     9   while(t--);
    10 }
    11 /*==================端口初始化函数=====================*/
    12 void Init_Port()
    13 {
    14   //将P1_0、P1_1和P1_4设置为通用I/O端口功能
    15   P1SEL &= ~0x13;   
    16   //将P1_0、P1_1和P1_4的端口传输方式设置为输出
    17   P1DIR |= 0x13;   
    18   
    19   P1SEL &= ~0x04;     //P1_2作为通用I/O端口
    20   P1DIR &= ~0x04;     //P1_2端口输入
    21   P1INP &= ~0x04;     //P1_2设置为上拉/下拉模式
    22   P2INP &= ~0x40;     //P1_2设置为上拉
    23   
    24   LED6 = 0;
    25   LED3 = 0;
    26   LED4 = 0;
    27 }
    28 /*==================跑马灯子函数=====================*/
    29 void LED_Running()
    30 {
    31   LED3 = 1;
    32   Delay(50000);
    33   LED4 = 1;
    34   Delay(50000);
    35   LED3 = 0;
    36   Delay(50000);
    37   LED4 = 0;
    38   Delay(50000);
    39 }
    40 /*===============外部中断初始化函数==================*/
    41 void Init_INTP()
    42 {
    43   IEN2 |= 0x10;         //端口1中断使能 0001 0000 端口1 中断使能
    44   P1IEN |= 0x04;        //端口P1_2外部中断使能   0000 0100 P1_2 使能具体的外部中断引脚。
    45   PICTL |= 0x02;        //端口P1_0到P1_3下降沿触发  0000 0011 P1_0和P1_1  下降沿触发
    46   EA = 1;               //使能总中断   
    47 }
    48 /*================外部中断1服务函数====================*/
    49 #pragma vector = P1INT_VECTOR     //外部中断1的向量入口
    50 __interrupt void Int1_Sevice()
    51 {
    52   LED6 = ~LED6;
    53 /*先清除引脚标志位,再清除端口标志位,否则会不断进入中断*/
    54   P1IFG &= ~ 0x04;        //软件清除P1_2引脚的标志位  
    55   P1IF = 0;               //软件清除P1端口组的标志位
    56 }
    57 /*====================主函数==========================*/
    58 void main()
    59 {
    60   Init_Port();          //初始化通用I/O端口
    61   Init_INTP();          //初始化外部中断
    62   while(1)
    63   {
    64     LED_Running();     //跑马灯
    65   }
    66 }
    View Code

    总结

    void Init_INTP() //中断初始化函数
    {
    EA = 1; //开总中断
    IENx = ? ; //要用哪一个端口组?P0,P1还是P2?
    /*
    IEN1 |= 0x20;开P0端口组中断
    IEN2 |= 0x10;开P1端口组中断
    IEN2 |= 0x01;开P2端口组中断
    以上都为固定开各个端口组中断的写法,至于为什么是这样子才能开P0,P1,或P2端口组的中断,翻看手册就知道了
    */
    PxIEN = ? ; //开端口组中断之后,要选择用哪一个引脚?
    PICTL = ? ; //开引脚中断之后,选择沿触发方式,上升沿还是下降沿?
    }

    #pragma vector = 中断向量
    __interrupt void 函数名称 (void)
    {
    /*此处编写中断处理函数的具体程序*/
    PxIFG = 0; //先清除Px引脚的中断状态标志位
    PxIF = 0; //再清除Px端口组的中断状态标志位
    }

  • 相关阅读:
    JS中的“&&”与“&”和“||”“|”有什么区别?
    深入理解CSS过度动画transition
    使用navigator.userAgent查看浏览器当前模式和版本
    node.js面试题
    Javascript 中的 ...(展开运算符)
    JavaScript立即执行函数
    JavaScript实现继承的6种方式
    JavaScript的排序算法--冒泡、选择、直接插入
    JavaScript RegExp 对象
    (CVPR 2020 Oral)最新Scene Graph Generation开源框架
  • 原文地址:https://www.cnblogs.com/yuling520/p/12673144.html
Copyright © 2020-2023  润新知