【物联网技能竞赛】【ZigBee】Zigbee外部中断

中断概念

        CPU在执行当前程序时,由于系统出现了某急需处理的的情况,CPU暂停正在执行的程序,转而去执行另外一段特殊程序来处理出现的紧急事务,处理结束后,CPU自动返回到带原来暂停的程序中去继续执行,这种程序在执行过程中由于外界的原因被打断的情况称为中断。
        1.中断服务函数:内核响应中断后执行的相应处理程序。
        2.中断向量:中断服务程序的入口地址。每个中断源都对应一个固定的入口地址。当内核响应中断请求时,就会暂停当前的程序执行,然后跳转到该入口地址执行代码。
        CC2530具有18个中断源,每个中断源都由各自的一系列特殊功能寄存器来进行控制。可以编程设计相关特殊功能寄存器,设置18个中断源的优先级以及使能中断申请响应等。

外部中断的工作原理

        CC2530 的 P0、P1 和 P2 端口中,每一个引脚在设置为输入后,都可以用于产生外部中断。产生外部中断的信号有上升沿下降沿 2 种,通过 PICTL 端口输入信号控制寄存器设置。 三个端口组作为三个独立的中断源,有三个中断使能控制位:IEN1.P0IEIEN2.P1IE IEN2.P2IE。每个端口组又有三个端口中断屏蔽寄存器 P0IENP1IENP2IEN,用于使能端口组中具体产生外部中断信号的引脚。在使能端口外部中断总中断后,还需要通过 PxIEN 寄存器来设置当前端口组中,那些引脚具有外部中断功能。

        只要端口的引脚产生了设定的中断触发信号,PxIFG 寄存器中对应的位便会置 1。在使能了 PxIEN 寄存器和 EA 总中断后,只要该端口组中有一个或多个引脚产生了中断触发信号, 对应的 PxIF 标志位置 1,内核响应便会响应该端口的外部中断请求,但内核并不知道是端口组中的哪一个引脚产生的请求。也就是说,不管是 P1_0 产生的中断请求,还是 P1_2 产生 的中断请求,在内核看来都是 P1 端口产生的中断请求。因此,在进行中断服务函数设计时, 还需要对 PxIFG 进行判断,才能确定是哪一个具体引脚产生的外部中断请求。 可以结合 P1 端口的外部中断结构,理解外部中断的工作原理。

CC2530 的 18 个中断源

寄存器

大致了解有哪些中断后,话不多说,我们来看看有关外部中断的使能寄存器:

IEN0 中断使能寄存器 0(可位寻址)

位名称复位值操作描述
7EA0R0

中断系统使能控制位,即:总中断

0:禁止所有中断。 1:允许所有中断。

6--00R0未使用,读为 0
5STIE0R/W

睡眠定时器中断使能。

0:中断禁止                        1:中断使能

4ENCIE0R/W

AES 加密/解密中断使能。

0:中断禁止                        1:中断使能

3URX1IE0R/W

USART1 接收中断使能。

0:中断禁止                        1:中断使能

2URX0IE0R/W

USART0 接收中断使能。

0:中断禁止                        1:中断使能

1ADCIE0R/W

ADC 中断使能。

0:中断禁止                        1:中断使能

0RFERRIE0R/W

RF 发送/接收 FIFO 中断使能。

0:中断禁止                        1:中断使能

IEN1 中断使能寄存器 1(可位寻址)

位名称复位值操作描述
7:6--00R0不使用,读为 0
5P0IE0R/W

端口 0 中断使能。

0:中断禁止                        1:中断使能

4T4IE0R/W

定时器 4 中断使能。

0:中断禁止                        1:中断使能

3T3IE0R/W

定时器 3 中断使能。

0:中断禁止                        1:中断使能

2T2IE0R/W

定时器 2 中断使能

0:中断禁止                        1:中断使能

1T1IE0R/W

定时器 1 中断使能。

0:中断禁止                        1:中断使能

0DMAIE0R/W

DMA 中断使能

0:中断禁止                        1:中断使能

 IEN2 中断使能寄存器 2(在 ioCC2530.h 头文件中没做位定义,故不能位寻址)

位名称复位值操作描述
7:6--00R0不使用,读为 0。
5WDTIE0R/W

看门狗定时器中断使能。

0:中断禁止                        1:中断使能

4P1IE0R/W

端口 1 中断使能。

0:中断禁止                        1:中断使能

3UTX1IE0R/W

USART1 发送中断使能

0:中断禁止                        1:中断使能

2UTX0IE0R/W

USART0 发送中断使能。

0:中断禁止                        1:中断使能

1P2IE0R/W

USART0 发送中断使能。

0:中断禁止                        1:中断使能

0RFIE0R/W

RF 一般中断使能。

0:中断禁止                        1:中断使能

位寻址:可以通过位名称来修改其值,如IEN0 中断使能寄存器 0中有个位名称为EA,直接

EA=1;

就行了,

 上面三个是关于中断的使能位寄存器,涵盖了18个中断源,再来看看端口使能的中断寄存器,上面的寄存器是具体到某个端口,而下面的寄存器则是具体到某个引脚。

P0IEN P0 端口中断使能寄存器

位名称复位值操作描述
7:0P0_[7:0]IEN0x00R/W

端口 P0_7 到 P0_0 中断使能。

0:中断禁止        1:中断使能

P1IEN P1 端口中断使能寄存器

位名称复位值操作描述
7:0P1_[7:0]IEN0x00R/W

端口 P1_7 到 P1_0 中断使能。

0:中断禁止        1:中断使能

P2IEN P2 端口中断使能寄存器

位名称复位值操作描述
7:6--00R0不使用,读为 0
5DPIEN0R/WUSB D+中断使能
4:0P2_[4:0]IEN0x00R/W

端口 P2_4 到 P2_0 中断使能。

0:中断禁止        1:中断使能

 PICTL 端口输入信号控制寄存器

位名称复位值操作描述
7PADSC0R/W控制 I/O 引脚输出模式下的驱动能力。
6:4--000R0未使用。
3P2ICON0R/W端口 P2_4 到 P2_0 中断触发方式选择。 0:上升沿触发。 1:下降沿触发
2P1ICONH0R/W端口 P1_7 到 P1_4 中断触发方式选择。 0:上升沿触发。 1:下降沿触发
1P1ICONL0R/W端口 P1_3 到 P1_0 中断触发方式选择。 0:上升沿触发。 1:下降沿触发
0P0ICON0R/W端口 P0_7 到 P0_0 中断触发方式选择。 0:上升沿触发。 1:下降沿触发。

接下来,来看看对于端口外部中断来说很重要的三个标志位

 P0IFG P0 端口中断状态标志寄存器

 (该标志必须在清除端口中断标志 P0IF 之前清除)

位名称复位值操作描述
7:0P0IF_[7:0]0x00R/W0

端口 P0_7 到 P0_0 的中断状态标志。 当输入端口有未响应的中断请求时,相应标志位硬件自动置 1, 需要通过软件人工清 0。

0:无中断请求。         1:有中断请求。

 P1IFG P1 端口中断状态标志寄存器

 (该标志必须在清除端口中断标志 P1IF 之前清除)

位名称复位值操作描述
7:0P1IF_[7:0]0x00R/W0

端口 P1_7 到 P1_0 的中断状态标志。 当输入端口有未响应的中断请求时,相应标志位硬件自动置 1, 需要通过软件人工清 0。

0:无中断请求。         1:有中断请求。

P2IFG P2 端口中断状态标志寄存器

 (该标志必须在清除端口中断标志 P2IF 之前清除)

位名称复位值操作描述
7:6--00R0未使用,读为 0。
5DPIF0R/W0USB D+中断标志位
4:0P2IF_[4:0]0x00R/W0

端口 P2_4 到 P2_0 的中断状态标志。

当输入端口有未响应的中断请求时,相应标志位硬件自动置 1, 需要通过软件人工清 0。

0:无中断请求。         1:有中断请求。

呼~是不是感觉这一章的寄存器有点多呢?其实除了中断的使能寄存器,后面的端口触发的寄存器中断比赛的时候很少很少涉及得到,平常开发项目可能就经常用得到,所以,还是得学了解了解。

了解了概念、原理和寄存器,接下来看代码的了。

来完成这两道题加深对其的理解(PS:题目是欧老师的题库):

3.1完整代码:

#include "ioCC2530.h"

#define D3 P1_0   // 定义 LED 灯的引脚号
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4

#define SW1 P0_1   // 定义按键的引脚号
#define SW2 P1_2

void Init_port()   // 初始化端口
{
  P1SEL &= ~0x1b;   // 配置 P1_0、P1_1、P1_3、P1_4 为数字 IO 口
  P1DIR |= 0x1b;    // 配置 P1_0、P1_1、P1_3、P1_4 为输出口
  P1 &= ~0x1b;      // 初始化 P1_0、P1_1、P1_3、P1_4 为低电平状态
  
  P1SEL &= ~0x04;   // 配置 P1_2 为数字 IO 口
  P1DIR &= ~0x04;   // 配置 P1_2 为输入口
  P1INP &= ~0x04;   // 配置 P1_2 的输入缓冲区范围
  P2INP &= ~0x40;   // 配置 P1_2 所在的管脚的输入缓冲区范围
  
  P0SEL &= ~0x02;   // 配置 P0_1 为数字 IO 口
  P0DIR &= ~0x02;   // 配置 P0_1 为输入口
  P0INP &= ~0x02;   // 配置 P0_1 的输入缓冲区范围
  P2INP &= ~0x20;   // 配置 P0_1 所在的管脚的输入缓冲区范围
  
  P1IEN |= 0x04;    // 配置 P1_2 为外部中断口
  PICTL |= 0x02;    // 配置外部中断的边缘触发方式(上升沿触发)
  IEN2 |= 0x10;     // 开启外部中断
  EA=1;             // 开启总中断允许位
}

void Delay(unsigned int t)   // 实现简单的延时函数
{
  while(t--);
}

#pragma vector=P1INT_VECTOR   // 定义中断服务程序函数
__interrupt void SW_1()      // 当按键被按下引起外部中断时,执行该函数
{
  D5 = ~D5;                 // 翻转 LED D5 的状态
  P1IFG &= ~0x04;           // 清除中断标志位
  P1IF=0;
}

void main()
{
  Init_port();   // 调用初始化函数
  while(1)
  {
    D4=1;       // 点亮 LED D4
    Delay(0xffff);   // 延时一段时间
    D4=0;           // 关闭 LED D4
    Delay(0xffff);   // 延时一段时间
  }
}

 3.2完整代码:

#include "ioCC2530.h"

#define D3 P1_0   // 定义 LED 灯的引脚号
#define D4 P1_1
#define D5 P1_3
#define D6 P1_4

#define SW1 P0_1   // 定义按键的引脚号
#define SW2 P1_2

unsigned int keys=0;   // 定义按键状态变量

void Init_port()   // 初始化端口
{
  P1SEL &= ~0x1b;   // 配置 P1_0、P1_1、P1_3、P1_4 为数字 IO 口
  P1DIR |= 0x1b;    // 配置 P1_0、P1_1、P1_3、P1_4 为输出口
  P1 &= ~0x1b;      // 初始化 P1_0、P1_1、P1_3、P1_4 为低电平状态
  
  P1SEL &= ~0x04;   // 配置 P1_2 为数字 IO 口
  P1DIR &= ~0x04;   // 配置 P1_2 为输入口
  P1INP &= ~0x04;   // 配置 P1_2 的输入缓冲区范围
  P2INP &= ~0x40;   // 配置 P1_2 所在的管脚的输入缓冲区范围
  
  P0SEL &= ~0x02;   // 配置 P0_1 为数字 IO 口
  P0DIR &= ~0x02;   // 配置 P0_1 为输入口
  P0INP &= ~0x02;   // 配置 P0_1 的输入缓冲区范围
  P2INP &= ~0x20;   // 配置 P0_1 所在的管脚的输入缓冲区范围
  
  P0IE = 1;         // 允许 P0_1 的中断功能
  P0IEN |= 0x02;    // 配置 P0_1 为外部中断口
  PICTL |= 0x01;    // 配置外部中断的边缘触发方式(下降沿触发)
  
  P0IFG &= ~0x02;   // 清除中断标志位
  P0IF=0;           // 清除中断标志位
  EA=1;             // 开启总中断允许位
}

void Delay(unsigned int t)   // 实现简单的延时函数
{
  while(t--)
  {
    while(keys==1);   // 如果按键被按下,则进入等待状态
  }
}

#pragma vector=P0INT_VECTOR   // 定义中断服务程序函数
__interrupt void key2()      // 当按键被按下引起外部中断时,执行该函数
{
  EA=0;              // 关闭总中断允许位
  
  if(keys==0)       // 如果按键状态为未按下,则将按键状态变量设为已按下
  {
    keys=1;
  }else
  {
    keys=0;        // 如果按键状态为已按下,则将按键状态变量设为未按下
  }
  
  P0IFG &= ~0x02;   // 清除中断标志位
  P0IF = 0;         // 清除中断标志位
  EA=1;             // 开启总中断允许位
}

void led()   // 控制 LED 灯的函数
{
  D4=1;       // 点亮 LED D4
  D3=0;
  D5=0;
  D6=0;
  Delay(0xffff);   // 延时一段时间
  D4=0;           // 关闭 LED D4
  D3=1;           // 点亮 LED D3
  D5=0;
  D6=0;
  Delay(0xffff);   // 延时一段时间
  D4=0;
  D3=0;
  D5=0;
  D6=1;
  Delay(0xffff);
  D4=0;
  D3=0;
  D5=1;
  D6=0;
  Delay(0xffff);
}
void main()
{
  Init_port();
  while(1)
  {
    led();
  }
}

另外简单的运用下新大陆库函数的调用(因为很少用到这里就不过多的讲解):

#include "hal_defs.h"
#include "hal_cc8051.h"
#include "hal_int.h"
#include "hal_mcu.h"
#include "hal_board.h"
#include "hal_led.h"
#include "hal_rf.h"
#include "basic_rf.h"
#include "hal_uart.h" 
#include "sensor_drv/sensor.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "hal_digio.h"
/*****点对点通讯地址设置******/
#define RF_CHANNEL                11         // 频道 11~26
#define PAN_ID                    0x0001     //网络id 
#define MY_ADDR                   0x0002     //本机模块地址
#define SEND_ADDR                 0x0003     //发送地址
/**************************************************/
static basicRfCfg_t basicRfConfig;
// 无线RF初始化
void ConfigRf_Init(void)
{
    basicRfConfig.panId       =   PAN_ID;
    basicRfConfig.channel     =   RF_CHANNEL;
    basicRfConfig.myAddr      =   MY_ADDR;
    basicRfConfig.ackRequest  =   TRUE;
    while(basicRfInit(&basicRfConfig) == FAILED);
    basicRfReceiveOn();
}

#define D3 P1_0   // 定义 LED 灯的引脚号
#define D4 P1_1

digioConfig dig;

#pragma vector = P1INT_VECTOR   // 定义中断服务程序函数
__interrupt void P1_D()   // 当按键被按下引起外部中断时,执行该函数
{
    D3 = ~D3;   // 翻转 LED 灯的状态
    halDigioIntClear(&dig);   // 清除中断标志
    P1IF = 0;   // 清除中断标志
}

void init_led()
{
    P1SEL &= ~0x1b;   // 配置 P1_0、P1_1 为数字 IO 口
    P1DIR |= 0x1b;    // 配置 P1_0、P1_1 为输出口
    P1 &= ~0x1b;      // 初始化 P1_0、P1_1 为低电平状态
}

/********************MAIN************************/
void main(void)
{
    halBoardInit();   // 板级初始化函数,选手不得在此函数内添加代码
    ConfigRf_Init();  // RF 配置初始化函数,选手不得在此函数内添加代码
    
    dig.port = 1;
    dig.pin = 2;
    dig.pin_bm = 0x04;
    dig.dir = HAL_DIGIO_INPUT;
    dig.initval = 1;
    halDigioConfig(&dig);   // 配置数字 IO 为输入口
    halDigioIntEnable(&dig);   // 允许数字 IO 的中断功能
    halDigioIntSetEdge(&dig,HAL_DIGIO_INT_FALLING_EDGE);   // 配置数字 IO 的中断类型为下降沿触发
    
    EA = 1;   // 开启总中断允许位
    init_led();   // 初始化 LED 灯
    D4 = 1;   // 设置 D4 引脚为高电平状态
    
    while(1)
    { 
        /* 用户代码开始 */
        /* 用户代码结束 */
    }
}
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曦&渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值