- 2.1 多工程管理基础
- 2.2 GPIO输出实验——LED控制
- 芯片的引脚
- LED 简介
- CC2530的引脚简介
- 查阅TI官方数据手册
- IO口的使用方法
- 编写LED控制代码
- 仿真调试
- 2.3 GPIO输入实验——机械按键
- 编写按键代码
- 仿真调试
- 2.4 GPIO输入输出通用配置实验
- 2.5 GPIO外部中断实验
- CC2530的中断体系原理
- 按键中断的配置
- 编写按键中断代码
- pragma是一个编译器预处理指令,其在此处的作用是告诉编译器vector是一个仅编译阶段有效的变量。vector表示一个中断向量,被赋值为P0INT_VECTOR,并且下面紧跟以__interrupt关键字开发头的函数buttonISR,表示该函数为P0引发的中断的处理函数,即P0引发中断后,由此函数处理该中断。在中断处理函数中,必须要清0中断标志位,否则当再次遇到这个中断时,CPU不会再执行中断处理函数。
2.1 多工程管理基础
多工程管理基础
(1)依照上节课讲解的方法新建一个工作空间,然后在工作空间中新建4个工程,分别是 led、key、ioConfig和interrupt。新建完成后,如图所示。单击Overview选项卡可以浏览整个工作空间,可以看到一个空间中包含了4个工程。右击led-Debug可以选中该工程,左上角也会显示当前被选中的工程。也可以单击底部的以工程名名称的选项卡来切换到对应的工程。
(2)为每个工程分别新建相应的组,新建完成后如下图所示。
(3)在工作空间的目录中新建一个code文件夹用来存放源代码,如图所示。工作空间的目录中含有一个以.eww结尾的工作空间文件。
(4)在code文件夹中新建4个与工程名称对应的子文件夹,用来存放相应的源代码,如图所示。
(5)分别在每个文件夹中新建以.c结尾源文件并添加到工程中,添加完成后如下图所示。
(6)接着读者还需要依照上节课讲解的方法配置这几个工程,配置完成后,即可进行开发。
2.2 GPIO输出实验——LED控制
接着上节课的内容,切换到LED工程,如图所示。
计算机的逻辑层与电路层
逻辑层
在计算机逻辑层中,一般是使用二进制数字(0或1)来控制对象或表示对象的状态,例如可以用1来表示开灯,用0来表示关灯,如图所示。
电路层
在计算机电路层中,一般是用高电平(3.3 v)来表示逻辑上的1,用低电平(0 v)来表示逻辑上的0。这个逻辑层和电路层的原理,初学者也许不好理解,但是可以继续往下学习,之后再逐步理解其中的含义。
芯片的引脚
芯片的引脚可以理解为从芯片里面引出来的导线,用于连接外部的元器件。
芯片的引脚一般可以划分为电源引脚、控制引脚还有GPIO。电源引脚一般用于给芯片供电;控制引脚一般和硬件设计有关,我们可以暂时忽略。
GPIO
GPIO的全称是General-Purpose Input / Output,中文意思是通用输入/输出,是我们常用的引脚。
一般来说,一个芯片会有多个GPIO,每个GPIO有两种工作模式,分别是输出信号模式和接收信号模式。
在输出信号模式时,我们可以通过代码来控制这个GPIO输出高电平(3.3 v)或者低电平(0 v)。在输入信号模式时,我们可以通过代码来检测这个GPIO是处于高电平还是低电平状态。
LED 简介
LED是Light Emitting Diode的缩写,中文意思是“发光二极管”,是一种能够把电转化为光的元器件。通俗地讲,LED就是我们常说的灯的一种。ZigBee开发板配备了一盏可以给开发者使用的LED,其原理图如图所示。
其中的D2表示LED,其右端接地(GND),因此右端的电压为0v。LED的左端依次连接着R12和IO_LED。IO_LED是CC2530的一个IO口,能够输出高电平(3.3v)或低电平(0v)。R12是一个稳压电阻,用于防止电路的电压过大而烧坏LED。
- 当IO_LED输出高电平时,LED左端电压为3.3v,右端电压为0v,左端和右端形成了3.3v的电压差,因此LED被点亮;
- 反之,当IO_LED输出低电平时,LED左端和右端电压均为0v,因此LED被熄灭。
如您因缺少硬件原理相关知识导致未能看懂电路图,需先补充相关知识。
CC2530的引脚简介
CC2530 配备了40个IO口,如图所示。
其中的P0_0~P0_7属于P0端口,P1_0~P1_7属于P1端口,P2_0~P2_5属于P2端口,这些IO口都可以通过编程的方式使用,接下来将会结合示例来讲解其使用方法。
查阅TI官方数据手册
(1)可以在本课程配套资源中找到CC2530数据手册,如图所示。
(2)该数据手册的目录如下。
(3)展开《I/O端口》章节,其目录如下。
(4)此数据手册可以用作查阅工具书,供我们随时查阅CC2530的各个细节,例如使用GPIO时就可以找到《I/O 端口》这一小节,使用定时器时就可以找到定时器章节。
IO口的使用方法
相关寄存器简介
可以通过配置相关寄存器的方式来使用IO口,例如配置指定的IO口为输出信号模式并控制其输出高/低电平。CC2530中与IO口配置相关的寄存器如下。
- P0:端口0配置寄存器
- P1:端口1配置寄存器
- P2 :端口2配置寄存器
- PERCFG:外设控制寄存器
- APCFG:模拟外设 I/O 配置寄存器
- P0SEL :端口 0 功能选择寄存器
- P1SEL :端口 1 功能选择寄存器
- P2SEL :端口 2 功能选择寄存器
- P0DIR :端口 0 方向寄存器
- P1DIR :端口 1 方向寄存器
- P2DIR :端口 2 方向寄存器
- P0INP :端口 0 输入模式寄存器
- P1INP :端口 1 输入模式寄存器
- P2INP :端口 2 输入模式寄存器
- P0IFG :端口 0 中断状态标志寄存器
- P1IFG :端口 1 中断状态标志寄存器
- P2IFG :端口 2 中断状态标志寄存器
- PICTL :中断边缘寄存器
- P0IEN :端口 0 中断掩码寄存器
- P1IEN :端口 1 中断掩码寄存器
- P2IEN :端口 2 中断掩码寄存器
- PMUX :掉电信号 Mux 寄存器
- OBSSEL0 :观察输出控制寄存器 0
- OBSSEL1 :观察输出控制寄存器 1
- OBSSEL2 :观察输出控制寄存器 2
- OBSSEL3 :观察输出控制寄存器 3
- OBSSEL4 :观察输出控制寄存器 4
- OBSSEL5 :观察输出控制寄存器 5
使用P0_4 IO口
在ZigBee开发板中,CC2530的 P0_4与LED连接,因此可以通过CC2530的 P0_4来控制LED的亮灭。可以对P0_4相关的寄存器进行配置来控制P0_4 的状态和行为。P0_4相关的寄存器及相应说明见表。
寄存器 | 说明 |
---|---|
P0 | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别用于设置或读取这8个IO口的电平状态 |
P0SEL | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别配置这8个IO口的功能。如果IO口对应的位为0,表示该IO口用于通用输入/输出;如果为1,表示用于特定的功能 |
P0DIR | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别配置这8个IO口的通信方向。如果IO口对应的位为0,表示该IO口处于输入信号模式;如果为1,表示处于输出信号模式 |
根据表格说明,可以按如下方式配置P0_4的相关寄存器和控制其输出电平,代码如下:
// 把P0_4配置为通用输出IO口
P0SEL &= ~(1<<4); // 把P0SEL寄存器的第4位设置为0,表示把P0_4配置为通用IO口
P0DIR |= (1<<4); // 把P0DIR寄存器的第4位设置为1,表示把P0_4配置为输出信号模式
P0_4=0;//输出低电平
P0_4=1;//输出高电平
其中的P0_4是在头文件ioCC2530.h中定义的,在配置好相关寄存器后,给其赋0或1即可控制其输出电平状态。这里简单讲解一下向左位移运算符<<、取反运算符~、按位与运算符&和按位或运算符|,以便加深读者对代码的理解。
(1)向左位移运算符 <<
把所有二进制数字向左移动指定的位数,高位的数字移出(舍弃),低位的空位补0。例如“1<<4”表示把0000 0001中的所有数字向左移动4位,并且高位的0移出舍弃,低位的空位补0,所以运算结果为0001 0000。
(2)取返运算符 ~
把所有二进制数字取反,例如对0001 0000进行取反运算后的结果为1110 1111。
(3)按位与运算符&
按位与运算规则是把两边的数转换为二进值数,然后把两个数的对应位逐位进行与运算,与运算的规则为1&1=1、1&0=0、0&1=0和0&0=0,例如1101 1101和1110 1111进行按位与运算后的结果为1100 1101。
(4)按位或运算符|
按位或运算规则是把两边的数转换为二进值数,然后把两个数的对应位逐位进行或运算,或运算的规则为1&1=1、1&0=1、0&1=1和0&0=0,例如1101 1101和0001 0000进行按位与运算后的结果为1101 1101。
编写LED控制代码
学习了相关原理后,可以编写代码来控制LED,示例代码如下:
//51单片机入门/2.GPIO实验/Workspace/code/led/led.c
#include "ioCC2530.h"
#include <stdio.h>
#include <stdint.h>
//P0_4由头文件ioCC2530.h定义
#define LED P0_4
//定义LED的开关状态和对应的值
#define LED_ON 1
#define LED_OFF 0
static void delayMs(uint16_t nMs);
static void initLed(void);
void main()
{
initLed();//初始化LED
while(1) {
printf("Set led to on!\r\n");
LED = LED_ON;//开启LED
delayMs(500);//延时0.5s后才继续往下执行程序
printf("Set led to off!\r\n");
LED = LED_OFF;//关闭LED
delayMs(500);//延时0.5s后才继续往下执行程序
} /* while */
}
/**
* @fn delayMs
*
* @brief 让程序延后指定的时间才接着运行
*
* @param nMs - 时间长度,以毫秒为单位,值范围:165535
*
* @return none
*/
static void delayMs(uint16_t nMs)
{
uint16_t i,j;
for (i = 0; i < nMs; i++)
//经由实际测试可以得出执行535次循环耗时最接近1ms
for (j = 0; j < 535; j++);
}
/**
* @fn initLed
*
* @brief 初始化LED,完成P0_4相关寄存器的配置
*/
static void initLed()
{
P0SEL &= ~(1<<4);
P0DIR |= (1<<4);
}
以上代码实现了闪烁LED的功能。程序首先通过
initLed对寄存器P0SEL和P0DIR进行初始化,然后对LED值进行定时反转,从而实现了闪烁LED的效果。
仿真调试
注意:
在学习本节课前,需要先掌握基本的程序下载及仿真操作,参考《第二部分:51单片机入门——基于CC2530》→《第1章:CC2530 开发基础实验》→《程序下载及仿真》。
(1)把开发板通过仿真器连接到电脑上。
(2)按一下仿真器的复位按键,如图所示。
(3)打开本实验代码,编译链接通过后,点击“下载仿真”按钮,如图所示。
(4)点击Go按钮,全速运行程序。可以观察到LED闪烁的效果,并且Terminal I/O不断输出对应的状态信息,如图所示。
(5)点击如图所示按钮可以停止运行程序,如图所示。。
2.3 GPIO输入实验——机械按键
接着上节课的内容,切换到按键的工程,如图所示。
按钮原理简介
配套的ZigBee开发板均配备有按键,其原理图如图所示。
如您缺少硬件原理相关知识导致未能看懂本图,需先补充相关知识
图中K5是一个按钮,R11是一枚100KΩ的上拉电阻,P0_1是CC2530的一个IO口,相关原理如下:
(1)当按钮没有按下时,P0_1通过上拉电阻R11接到3v3,所以P0_1的输入电平为高电平。
(2)当按键按下时,P0_1接地,所以P0_1的输入电平为低电平。
由以上分析可知,可以检测P0_1的输入电平状态来检测按钮是否被按下。
P0_1相关寄存器
与LED实验类似,要检测P0_1的输入电平状态,就必须要先配置一下相关寄存器。P0_1的相关寄存器见下表。
寄存器 | 说明 |
---|---|
P0 | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别用于设置或读取这8个IO口的电平状态 |
P0SEL | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别配置这8个IO口的功能。如果IO口对应的位为0,表示该IO口用于通用输入/输出;如果为1,表示用于特定的功能 |
P0DIR | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别配置这8个IO口的通信方向。如果IO口对应的位为0,表示该IO口处于输入信号模式;如果为1,表示处于输出信号模式 |
P0INP | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别配置这8个IO口的输入模式。如果IO口对应的位为0,表示该IO口为上拉/下拉输入模式;如果为1,表示三态模式 |
P2INP[7:5] | P2INP寄存器的第5、6和7位分别用于配置端0、1和2的上拉或下拉模式,如果为0,表示上拉模式;如果为1,表示下拉模式 |
上拉与下拉输入
相关寄存器中涉及到上拉和下拉输入,对其简单讲解一下。通俗地讲,上拉是指在默认的状态下给IO口输入高电平,与之相反,下拉就是低电平。根据上文的按键原理图可知,这是一个上拉输入模式。按键原理示意图如图所示。
当按键没有被按下时,CC2530与3.3v电源连接,其引脚的输入电平为高电平(对应信号1)。当按钮被按下时,CC2530与GND连接,其引脚的输入电平为低电平(对应信号0)。
寄存器配置
通过以上分析,相关寄存器的配置代码如下:
P0SEL &= ~(1<<1);//把P0SEL寄存器的第1位设置为0,即让P0_1用作通用IO口
P0DIR &= ~(1<<1);//把P0DIR寄存器的第1位设置为0,即让让P0_1处于输入信号模式
P0INP &= ~(1<<1);//把P0INP寄存器的第1位设置为0,即让P0_1处于上拉/下拉输入模式
P2INP &= ~(1<<5);//把P2INP寄存器的第5位设置为0,即让端口0处于上拉输入模式
编写按键代码
编写代码实现每按一下按键就翻转一下LED的开关状态,打开Key文件夹中的key.c文件,可以看到如下示例代码:
//2. 51单片机入门/2. GPIO实验/Workspace/code/key/key.c
#include "ioCC2530.h"
#include <stdio.h>
#include <stdint.h>
#define DEBUG
//#define xDEBUG
#ifdef DEBUG
#define DEBUG_LOG(...) printf(__VA_ARGS__)
#else
#define DEBUG_LOG(...)
#endif
#define LED P0_4
#define LED_ON 1
#define LED_OFF 0
/**
* @brief 按钮及其状态的定义。其中,P0_1是在头文件ioCC2530.h,可以检测其值来判断P0_1引脚的电平状态
*/
#define BUTTON P0_1
#define BUTTON_NORMAL 1//按钮的默认状态
#define BUTTON_DOWN 0//按钮被按下
static void delayMs(uint16_t nMs);
static void initLed(void);
static void initButton(void);
void main() {
initLed();//初始化LED
initButton();//初始化按键
while(1) {
if (BUTTON != BUTTON_DOWN)//如果按键没有被按下
continue;//结束本次while循环
else {
/* 以下为对按键的机械抖动的处理处理代码 */
delayMs(10);//延后10毫秒
if (BUTTON != BUTTON_DOWN)//再次检测按钮的状态,如果按键没有被按下
continue;//结束本次while循环
}
while (BUTTON == BUTTON_DOWN);//等待BUTTON != BUTTON_DOWN,即等待按键松开
DEBUG_LOG("Key Pressed!\r\n");
LED = (LED == LED_ON)? LED_OFF : LED_ON;//翻转LED的状态
}
}
static void delayMs(uint16_t nMs)
{
uint16_t i,j;
for (i = 0; i < nMs; i++) for (j = 0; j < 535; j++);
}
static void initLed()
{
P0SEL &= ~(1<<4);
P0DIR |= (1<<4);
}
/*
* @fn initButton
*
* @brief 初始化Button,完成P0_1相关寄存器的配置
*/
static void initButton()
{
P0SEL &= ~(1<<1);//把P0SEL寄存器的第1位设置为0,即让P0_1用作通用IO口
P0DIR &= ~(1<<1);//把P0DIR寄存器的第1位设置为0,即让让P0_1处于输入信号模式
P0INP &= ~(1<<1);//把P0INP寄存器的第1位设置为0,即让P0_1处于上拉/下拉输入模式
P2INP &= ~(1<<5);//把P2INP寄存器的第5位设置为0,即让端口0处于上拉输入模式
}
处理机械按键抖动
上述代码包含了按键抖动的处理,对其简单讲解一下。由于按键内部采用了弹簧,所以当按键被按下或松开的时候,会产生一定的震动,这种震动可以称为机械抖动。这种机械抖动会导致电平的抖动,如图所示。
图中的中的横坐标是电平,纵坐标是时间,展示了按钮从按下到松开这个过程的电平变化。按键被按下时产生的抖动称为前沿抖动,松开时产生的是后沿抖动。这个抖动时间一般持续5~10ms。因此在代码上当检测到按钮被按下后,需要延后10ms后再检测一次按钮是否真的被按下。
使用调试模式
在程序开发调试过程中,可设置一个调试模式。在调试模式下可以输出相关的调试信息来了解程序运行状态。然而在程序开发完成后,可以关闭调试模式,停止输出调试信息。
DEBUG_LOG是一个宏定义,其定义在上述代码的开端处。
- 当代码定义了 DEBUG 这个宏时,表示当前模式是调试模式,此时DEBUG_LOG和printf是一致的。
- 而没有定义DEBUG 这个宏时,表示关闭调试模式,此时DEBUG_LOG什么都不做。所以,当需要关闭调试模式时,可以把DEBUG更改为xDEBUG,表示关闭调试模式。
仿真调试
注意:
在学习本节课前,需要先掌握基本的程序下载及仿真操作,参考《第二部分:51单片机入门——基于CC2530》→《第1章:CC2530 开发基础实验》→《程序下载及仿真》。
(1)把开发板通过仿真器连接到电脑上。
(2)按一下仿真器的复位按键。
(3)打开本实验代码,打开调试模式,编译链接通过后,点击“下载仿真”按钮全速运行程序,每当有按键按下时Terminal I/O中就会输出相应的信息,如图所示。
2.4 GPIO输入输出通用配置实验
GPIO输入输出通用配置API
本小节实验将要实现的效果和上节课的是一样的,即通过按键控制LED翻转。不同的是,本节课使用了GPIO输入输出通用配置API CC2530_IOCTL,开发者不再需要自己查找和配置GPIO的相关寄存器了。
打开头文件cc2530_ioctl.h,找到CC2530_IOCTL定义,代码如下:
//2. 51单片机入门/4. 串口通信实验/Workspace/code/common/cc2530_ioctl.h
/**
* @brief 配置GPIO模式
*
* @param port - CC2530引脚port号
* @param pin - CC2530引脚pin号
* @param mode - 该GPIO的模式
*
* @warning P1_0和P1_1不能配置为输入模式
*/
#define CC2530_IOCTL(port, pin, mode) do {
if (port > 2 || pin > 7) break;
if (mode == CC2530_OUTPUT) CC2530_IO_OUTPUT(port, pin);
else CC2530_IO_INPUT(port, pin, mode);
} while(0)
其中的mode参数可以传入下列参数,表示不同的模式:
//2. 51单片机入门/4. 串口通信实验/Workspace/code/common/cc2530_ioctl.h
/** @brief CC2530 GPIO mode. */
#define CC2530_OUTPUT 0 //输出模式
#define CC2530_INPUT_PULLUP 1 //上拉输入模式
#define CC2530_INPUT_PULLDOWN 2 //下拉输入模式
#define CC2530_INPUT_TRISTATE 3 //3态模式
如果需要把CC2530的P0_4引脚配置为输出信号模式,只需按如下方式调用:
CC2530\_IOCTL(0, 4, CC2530\_OUTPUT);
可见,在使用CC2530_IOCTL后,GPIO口的配置变得非常简单,不再需要另外查找配置P0_4的相关寄存器了!
使用CC2530_IOCTL
使用CC2530_IOCTL前,需要分别定义LED和按键与CC2530引脚的连接。在头文件cc2530_ioctl.h中,可以找到LED和按键与CC2530的引脚连接定义,代码如下:
//2. 51单片机入门/4. 串口通信实验/Workspace/code/common/cc2530_ioctl.h
// LED与GPIO的连接定义
#define LED_PORT 0 //Led port.
#define LED_PIN 4 //Led pin.
#define LED P0_4 //Led GPIO.
// Button与GPIO的连接定义
#define BUTTON_PORT 0 //Button port.
#define BUTTON_PIN 1 //Button pin.
#define BUTTON P0_1 //Button GPIO.
以上代码定义了LED与CC2530的P0_4引脚连接、按键与CC2530的P0_1引脚连接。
这样做的优点在于,如果硬件电路发生改变,例如LED接的不是P0_4、按键接的不是P0_1,那么开发者只需要在这里修改配置,而不需要修改代码。
以下两个初始化函数的效果分别与前面章节的LED和按键初始化函数的效果是相同的。
//2. 51单片机入门/2. GPIO实验/Workspace/code/ioConfig/ioConfig.c
/*
* 初始化LED
*/
static void initLed()
{
CC2530_IOCTL(LED_PORT,//LED的port
LED_PIN,//LED的pin
CC2530_OUTPUT);//配置为输出
LED = LED_OFF;
}
/*
* 初始化按键
*/
static void initButton()
{
CC2530_IOCTL(BUTTON_PORT,//按键的port
BUTTON_PIN,//按键的pin
CC2530_INPUT_PULLUP);//配置为上拉输入
}
仿真调试
注意:
在学习本节课前,需要先掌握基本的程序下载及仿真操作,参考《第二部分:51单片机入门——基于CC2530》→《第1章:CC2530 开发基础实验》→《程序下载及仿真》。
(1)把开发板通过仿真器连接到电脑上。
(2)按一下仿真器的复位按键,如图所示。
(3)打开本实验代码,打开调试模式,编译链接通过后,点击“下载仿真”按钮全速运行程序,每当有按键按下时Terminal I/O中就会输出相应的信息,如图所示。
2.5 GPIO外部中断实验
什么是中断?
通俗地讲,中断是指系统在正常运行的时候突然遇到了一个紧急事件,例如用户突然按下一个按键、火灾传感器监测到起火或者计时结束等,需要先放下当前的工作去处理这个紧急事件。我们通过一张逻辑图来理解一下这个过程。
如图所示,系统在执行主程序的过程中,在某一个时间点(也可以称为断点)遇到了一个紧急事件,这时候通常会发生以下3件事:
(1)中断请求
这个紧急事件请求系统暂停主程序,转而去处理这个紧急事件。
(2)中断响应
系统会执行一个叫中断处理的程序来处理这个紧急事件。
(3)中断返回
处理完这个紧急事件后,系统会返回到刚才的主程序中并且从暂停的位置继续执行主程序。
中断优先级
当有多个中断同时发生时,应该优先处理哪个中断呢?我们可以给每个中断定义一个优先级,告诉系统优先处理优先级较高的中断,延后处理优先级较低的中断。
CC2530的中断体系原理
CC2530的中断体系原理如图所示。
这个中断体系原理图还是比较复杂的,这里以P0端口的中断原理为例讲解一下。上图的最右边是P0端口的中断过程,其相关寄存器依次为P0、PICTL.P0ICON、P0IFG、P0IEN、P0IF、EA和IEN1.P0IE,相关说明见表。
寄存器 | 说明 |
---|---|
PICTL.P0ICON | PICTL是8位的端口中断控制寄存器。P0ICON是PICTL的第0个位,用于配置端口P0中断引发方式。如果P0ICON的值为:0,输入的上升沿引起中断;1,输入的下降沿引起中断 |
P0IFG | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别用于表示P0_7到P0_0引脚的输入中断状态标志。如果产生了中断,相应标志位将置 1 |
P0IEN | 8位寄存器,8个位分别与P0_0~P0_7一一对应,分别用于配置P0_7到P0_0引脚是否允许中断。如果对应位的值为:0,禁用中断;1,允许中断。 |
P0IF | 如果端口0产生了中断,那么值被置1 |
EA | 中断总开关,如果值为:0,禁用所有中断;1:允许所有中断 |
IEN1.P0IE | IEN1是8位的中断使能1寄存器,用于配置是否允许端口中断、定时器中断或DMA中断。P0IE是IEN1的第5个位,用于配置是否允许端口0引起终端,如果值为:0,禁止中断;1,允许中断 |
结合相关寄存器说明,如果需要实现有P0端口引发CPU中断,那么配置步骤如下:
(1)通过PICTL的P0ICON位指定端口0的中断引发方式。
(2)清零P0IFG寄存器,表示默认状态下端口0中的所有IO口均没有引发中断。
(3)把P0IEN的对应位置1,表示对应的IO口被允许引发中断,例如如果需要允许P0_0引发中断,那么把P0IEN的第0位置1即可。
(4)清零P0IF寄存器,表示默认状态下端口0没有引发中断。
(5)EA寄存器置1,表示允许所有中断。
(6)IEN1寄存器的P0IE位置1,表示允许端口0引起中断。
当端口0引发中断后,这个中断便由中断向量IP0_5或IP1_5分发给指定的中断处理函数处理,下文将结合具体的例子讲解。
按键中断的配置
ZigBee开发板的按键与P0_1相连接,并且使用上拉输入的方式,如果需要显示按下按键后引发中断,那么相应的配置代码如下:
PICTL |= 0x01;//P0ICON=1,指定端口0在输入下降沿信号时触发中断,即输入电平由高电平转为低电平时触发中断
P0IFG = 0x00;//清零P0IFG寄存器
P0IEN |= (1<<1);// 把P0\_1设置为允许引发中断
P0IF = 0x00;//清零P0IF寄存器
EA = 1;//允许所有中断
IEN1 |= 0x20;//P0IE=1,允许端口0引起中断
编写按键中断代码
打开本实验代码,main函数的代码如下:
//2. 51单片机入门/2. GPIO实验/Workspace/code/interrupt/interrupt.c
void main()
{
initLed();//初始化LED
initButton();//初始化按键
while(1) {//每隔100ms计数一次
counter_g++;//计数1次
delayMs(100);//延迟100ms
}
}
上述代码中的counter_g是一个计算器,每隔100ms计数一次。在按键初始化函数initButton中把P0_1配置为中断输入,代码如下:
//2. 51单片机入门/2. GPIO实验/Workspace/code/interrupt/interrupt.c
static void initButton(void)
{
PICTL |= 0x01;//P0ICON=1,指定端口0在输入下降沿信号时触发中断,即输入电平由高电平转为低电平时触发中断
P0IFG = 0x00;//清零P0IFG寄存器
P0IEN |= (1<<1);// 把P0\_1设置为允许引发中断
P0IF = 0x00;//清零P0IF寄存器
EA = 1;//允许所有中断
IEN1 |= 0x20;//P0IE=1,允许端口0引起中断
}
中断处理函数的定义如下:
//2. 51单片机入门/2. GPIO实验/Workspace/code/interrupt/interrupt.c
#pragma vector = P0INT_VECTOR
__interrupt void buttonISR(void)
{
delayMs(10); //处理机械按键抖动
if (BUTTON == BUTTON_DOWN) {
DEBUG_LOG("counter_g: %d\r\n", counter_g);//输出计数器的值
LED = (LED == LED_ON)? LED_OFF : LED_ON;//翻转LED灯的状态
}
//处理完中断后,需要清零相关寄存器
P0IFG = 0;
P0IF = 0;
}
pragma是一个编译器预处理指令,其在此处的作用是告诉编译器vector是一个仅编译阶段有效的变量。vector表示一个中断向量,被赋值为P0INT_VECTOR,并且下面紧跟以__interrupt关键字开发头的函数buttonISR,表示该函数为P0引发的中断的处理函数,即P0引发中断后,由此函数处理该中断。在中断处理函数中,必须要清0中断标志位,否则当再次遇到这个中断时,CPU不会再执行中断处理函数。
仿真调试
注意:
在学习本节课前,需要先掌握基本的程序下载及仿真操作,参考《第二部分:51单片机入门——基于CC2530》→《第1章:CC2530 开发基础实验》→《程序下载及仿真》。
利用仿真器与ZigBee开发板,可以观察在ZigBee开发板上的运行结果。仿真调试步骤如下:
(1)把开发板通过仿真器连接到电脑上。
(2)按一下仿真器的复位按键,如图所示。
(3)打开本实验代码,在编译链接通过后,全速运行,如图所示。
当按下按键后,Terminal I/O中会显示计数器的值,并且翻转LED灯的状态。如果需要停止仿真调试,可以点击图中的红色交叉按钮。