一、 cc2530最小系统
二、GPIO概述
三、IO口的输入输出配置
上拉输入:有上拉电阻
按键未按下时端口接高电平,即高电平 1 状态---3.3v
按键按下时端口接低电平,即低电平 0 状态-------0
下拉输入:有下拉电阻
按键未按下时端口接低电平,即低电平 0 状态---0v
按键按下时端口接高电平,即高电平 1 状态------3.3v
四、外部中断
1.什么是外部中断
外部中断是单片机实时地处理外部事件的一种内部机制。当某种外部事件发生时,单片机的中断系统将迫使CPU暂停正在执行的程序,转而去进行中断事件的处理;中断处理完毕后.又返回被中断的程序处,继续执行下去。
2.外部中断的作用
(1)实时处理功能
在实时控制中,现场的各种参数、信息均随时问和现场而变化。这些外界变量可根据要求随时向CPU发出中断申请.请求CPU及时处珲中断请求,如中断条件
(2)故障处理功能
针对难以预料的情况或故障,如掉电、存储出错、运算溢出等,可通过中断系统由故障源向CPU发出中断请求,再由CPU转到相应的故障处理程序进行处理。
3.cc2530的外部中断原理
CC2530 有 21 个数字 I/O 引脚,可以配置为通用数字 I/O 或外设 I/O 信号,配置为连接到 ADC、定时器或 USART 外设。这些 I/O 口的用途可以通过一系列寄存器配置,由用户软件加以实现。
I/O 端口具备如下重要特性:
- 21 个数字 I/O 引脚
- 可以配置为通用 I/O 或外部设备 I/O
- 输入口具备上拉或下拉能力
- 具有外部中断能力
21 个 I/O 引脚都可以用作于外部中断源输入口。因此如果需要外部设备可以产生中断。外部中断功能也可以从睡眠模式唤醒设备。
通用 I/O 引脚设置为输入后,可以用于产生中断。中断可以设置在外部信号的上升或下降沿触发。 P0、 P1 或 P2 端口都有中断使能位,对位于 IENl-2 寄存器内的端口所有的位都是公共的,如下:
IENI.P0IE: P0 中断使能
IEN2.PIIE: P1 中断使能
IEN2.P2IE: P2 中断使能
除了这些公共中断使能之外,每个端口的位都有位于 SFR 寄存器 P0IEN、P1IEN 和 P2IEN 的单独的中断使能。即使配置为外设 I/O 或通用输出的 I/O 引脚使能时都有中断产生。
当中断条件发生在 I/O 引脚之一上面,P0-P2 中断标志寄存器 P0IFG、P1IFG或 P2IFG 中相应的中断状态标志将设置为 1。不管引脚是否设置了它的中断使能位,中断状态标志都被设置。当中断已经执行,中断状态标志被清除,该标志写入 0。这个标志必须在清除 CPU 端口中断标志( PxIF)之前被清除。
用于中断的 SFR 寄存器描述在下一节。寄存器总结如下:
- P0IEN: P0 中断使能
- P1IEN: P1 中断使能
- P2IEN: P2 中断使能
- PICTL: P0、 P1 和 P2 触发沿设置
- P0FG: P0 中断标志
- P1IFG: P1 中断标志
- P2IFG: P2 中断标志
4.外部中断配置步骤
(1)初始化IO口工作在普通IO模式,上拉输入状态
(2)首先打开IO口组中断允许位===>PxIE
- P0IE 是 IEN1(0xB8)的第5位
- P1IE 是 IEN2(0x9A)的第4位
- P2IE 是 IEN2(0X9A)的第1位
(3)打开组内对应的具体某IO口中断====>PxIEN
(4)设置是上升沿还是下降沿触发===>PICTL(0,代表上升沿触发;1,代表下降沿触发)
(5)打开CPU总中断 EA=1;
void exti_init()
{
//(1)初始化IO口工作在普通IO模式,上拉输入状态
key_init();
//(2)首先打开IO口组中断允许位===>PxIE
IEN2 |= 1<<4; //0001 0000 0x10
//(3)打开组内对应的具体某IO口中断====>PxIEN
P1IEN |= 1<<2; //0000 0100 0x40
//(4)设置是上升沿还是下降沿触发===>PICTL(0,代表上升沿触发;1,代表下降沿触发)
PICTL |= 1<<1; //0000 0010 0x02 设置为下降沿触发
//(5)打开CPU总中断 EA=1;
EA = 1;
}
5.外部中断服务程序示例
led_key.c
#include "iocc2530.h"
#include "led_key.h"
/*
@led init:对LED进行初始化
@retval:none
@note:LED对应的引脚是P10和P11,初始化为普通IO,输出模式
*/
void led_init(void)
{
P1SEL &= 0xfc; //1111 1100 把P1_0和P1_1设置为通IO模式
P1DIR |= 0x03; //0000 0011 把P1_0和P1_1设置为输出模式
P1_0 = 0;
P1_1 = 0;
}
/*
@led ctr1:对LED的状态进行控的函数
@led num:指定对哪一盏LED等进行控制,可选择为LEDO,LED1
@led state:指定LED的状态,可选择为 LED ON, LED OFF
@retval:none
*/
void led_ctrl(int led_num,int led_state)
{
switch(led_num)
{
case LED0:
P1_0 = led_state;
break;
case LED1:
P1_1 = led_state;
break;
}
}
/*
@key init:按键的初始化函数
@retval none
@note:按键应的引是P12,应初始化为普通IO,上拉输入模式
*/
void key_init(void)
{
P1SEL &= 0xFB; // 1111 1011 把P12设置为普通IO模式
P1DIR &= 0xFB; // 1111 1011 把P12设置为输入模式
P1INP &= 0xFB; // 1111 1011 把P12设置为上下拉模式
P2INP &= 0xBF; // 1011 1111 把P1组设置为上拉模式
}
int key_status(void)
{
return P1_2;
}
/*
@exti_init:中断初始化函数
@retval none
@note:none
*/
void exti_init()
{
//(1)初始化IO口工作在普通IO模式,上拉输入状态
key_init();
//(2)首先打开IO口组中断允许位===>PxIE
IEN2 |= 1<<4; //0001 0000 0x10
//(3)打开组内对应的具体某IO口中断====>PxIEN
P1IEN |= 1<<2; //0000 0100 0x40
//(4)设置是上升沿还是下降沿触发===>PICTL(0,代表上升沿触发;1,代表下降沿触发)
PICTL |= 1<<1; //0000 0010 0x02 设置为下降沿触发
//(5)打开CPU总中断 EA=1;
EA = 1;
}
void delay_ms(int n)
{
int i;
while(n--)
for(i=0;i<587;i++);
}
#pragma optimize=none //不进行编译优化
#pragma vector=P1INT_VECTOR //P1组引发中断,vector中断矢量表,下面这段代码必须放在这个地方
__interrupt void exint(void)//P1组
{
if(P1IFG & 0X04)//0000 0100
{//确定是P1_2产生了外部中断
delay_ms(20); //按键消抖
if(P1_2 == 0)
{
//中断要做的事情
P1_0 = !P1_0;
P1_1 = !P1_1;
}
}
P1IFG = 0;//把中断状态标志位清0
P1IF = 0; //组中断标志位清0
}
led_key.h
#ifndef __LED_KEY_H__
#define __LED_KEY_H__
#include "iocc2530.h"
enum LED_NUM{LED0,LED1};
enum LED_STATE{LED_OFF,LED_ON};
enum KEY_STATUS{KEY_DOWN,KEY_UP};
extern void led_init(void);
extern void led_ctrl(int led_num,int led_state);
extern void key_init(void);
extern int key_status(void);
extern void exti_init();
extern void delay_ms(int n);
#endif
main.c
#include "iocc2530.h"
#include "led_key.h"
void main(void)
{
led_init();
exti_init();
while(1);
}