通过本次实验,将会清楚如何捕获一个外部中断和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)
{
//中断处理,处理完成后通常需要清除中断标志。
}
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。