一、实验目的:

  1. 阅读 ZigBee 模块硬件熟悉 ZigBee 模块相关硬件接口。使用 IAR开发环境设计程序,学习CC2530的外部中断的使用,实现用按键(霍尔效应传感器模拟)查询控制 LED 亮灭。
  2. 学习 CC2530 的外部中断的使用,实现用按键(霍尔效应传感器模拟)中断控制 LED 亮灭。

    二、实验原理:

    LED及按键原理图,如下图所示:

    CC2530 的外部中断需要配置三个寄存器 P0IEN、PICTL、P0IFG、IEN1。
    LED 初始化配置:
    P2DIR |= 0x01; //P2_0 定义为输出
    按键初始化配置:
    P0SEL &= ~0X20; //设置 P0_5 为普通 IO 口
    P0DIR &= ~0X20; //按键在 P0_5 口,设置为输入模式
    P0SEL(0XF3) P0[7:0]功能设置寄存器,默认设置为普通 I/O 口
    P0INP(0X8F) P0[7:0]作为输入口时的电路模式寄存器
    P0(0X80) P0[7:0]可为寻址的 I/O 寄存器
    P0DIR(0XFD) P0 口输入输出设置寄存器,0:输入,1:输出
    P0INP &= ~0x20; //打开 P0_5 上拉电阻,不影响
    实验设备与芯片选择

    全代码如下:
#include <ioCC2530.h>
#define uint unsigned int
#define uchar unsigned char
//定义控制 LED 灯的端口
#define LED1 P2_0 //LED1 为 P2_0 口控制
#define KEY1 P0_5 //KEY1 为 P0_5 口控制
//函数声明
void Delayms(uint); //延时函数
void InitLed(void); //初始化 LED1
void KeyInit(); //按键初始化
uchar KeyScan(); //按键扫描程序
/****************************
延时函数
*****************************/
void Delayms(uint xms) //i=xms 即延时 i 毫秒
{
uint i,j;
for(i=xms;i>0;i--)
for(j=587;j>0;j--);
}
/****************************
LED 初始化函数
*****************************/
void InitLed(void)
{
P2DIR |= 0x01; //P2_0 定义为输出
LED1 = 1; //LED1 灯熄灭
}
/****************************
按键初始化函数
*****************************/
void InitKey()
{
P0SEL &= ~0X20; //设置 P0_5 为普通 IO 口
P0DIR &= ~0X20; //按键在 P0_5 口,设置为输入模式
P0INP &= ~0x20; //打开 P0_5 上拉电阻,不影响
}
/****************************
按键检测函数
*****************************/
uchar KeyScan(void)
{
if(KEY1==0)
{Delayms(10);
if(KEY1==0)
{
while(!KEY1); //松手检测
return 1; //有按键按下
}
}
return 0; //无按键按下
}
/***************************
主函数
***************************/
void main(void)
{
InitLed(); //调用初始化函数
InitKey();
while(1)
{
if(KeyScan()) //按键改变 LED 状态
LED1=~LED1;
}
}
LED 初始化配置: 
P0IEN(0XAB) P0[7:0]中断掩码寄存器,0:关中断, 1:开中断 
PICTL(0X8C) P0 口的中断触发控制寄存器 
Bit0 为 P0[0:7]的中断触法配置: 
0:上升沿触发 1:下降沿触发 
P0IFG(0X89) P0[7:0]中断标志位,在中断发生时,相应位置 1 IEN1(0XB8) Bit5 为 P0[0:7]中断使能位,0:关中断 1:开中断
P2DIR |= 0x01; //P2_0 定义为输出 
外部中断初始化配置: 
P0IEN |= 0X20; // P0_5 设置为中断方式 
PICTL &=~ 0X20; // 下降沿触发 
IEN1 |= 0X20; // 允许 P0 口中断; 
P0IFG = 0x00; // 初始化中断标志位 
全代码如下: 
/************************************* 
模块:HALL 模块 功能:使用 KEY1 控制 LED1 亮灭(中断方式) 
**************************************/ 
#include #define uint unsigned int #define uchar unsigned char 
//定义控制 LED 灯的端口 
#define LED1 P2_0 //LED1 为 P2_0 口控制 
#define KEY1 P0_5 //中断口 
//函数声明 
void Delayms(uint); //延时函数 
void InitLed(void); //初始化 LED 
void KeyInit(); //按键初始化 
uchar KeyValue=0; 
/**************************** //延时函数 
*****************************/ 
void Delayms(uint xms) //i=xms 即延时 i 毫秒 
{ uint i,j; for(i=xms;i>0;i--) for(j=587;j>0;j--); } 
/**************************** //LED 初始化程序 
*****************************/
void InitLed(void) { P2DIR |= 0x01; //P2_0 定义为输出 
LED1 = 1; //LED1 灯熄灭 
} 
/**************************** KEY 初始化程序--外部中断方式 
*****************************/ 
void InitKey() { P0IEN |= 0X20; //P0_5 设置为中断方式 
PICTL &=~ 0X20; // 下降沿触发 
IEN1 |= 0X20; // 允许 P0 口中断 
P0IFG = 0x00; // 初始化中断标志位 
EA = 1; //开总中断 
} 
/**************************** 
中断处理函数 
*****************************/ 
#pragma vector = P0INT_VECTOR //格式:#pragma vector = 中断向量, 
__interrupt void P0_ISR(void) //中断处理程序 
{ Delayms(10); //去除抖动 
LED1=~LED1; //改变 LED1 状态 
P0IFG = 0; //清中断标志 
P0IF = 0; //清中断标志 
} 
/*************************** 
主函数 
***************************/ 
void main(void) { InitLed(); //调用初始化函数 
InitKey();
while(1); }

三、步骤:

  1. 将 CC2530 核心板插在 HALL 传感器底板,使用配套方口 USB 线连接PC 机和 DY-WSN-Kit V1.0 物联网综合开发实训平台,给开发实训平台上电,打开 HALL 传感器底板开关(传感器底板左侧开关),传感器底板电源灯亮起。
  2. 使用旋钮开关选择 ZigBee 仿真器要连接的设备模块(根据 LED 指示灯是否亮起判断)。在这个实验中,将旋钮选择到 HALL 传感器底板。
  3. 启动 IAR 开发环境,新建工程,将实验工程中代码拷贝到新建工程中。
  4. 在 IAR 开发环境中编译、运行、调试程序,并把程序下载到 HALL 传感器底板的 CC2530 核心板上,观察实验现象。
  5. 关闭开发平台电源,关闭 HALL 传感器底板电源。
    注:代码为按键查询和按键中断,此过程重复两次。
    初始化时led灯为亮

    初始化时led灯为亮

    当用磁铁模拟按键时候led会反转状态

    四、结果与分析:

    本项目旨在通过按键控制LED灯的亮灭,利用CC2530芯片进行编程,并通过中断方式实现按键的快速响应。该项目的实现不仅可以帮助理解基本的嵌入式系统编程,还能够展示如何在微控制器上处理外部中断。

项目实现概述

  1. 硬件配置
    使用CC2530芯片。
    LED连接至P2_0引脚。
    按键连接至P0_5引脚。

  2. 软件实现
    初始化LED灯和按键。
    配置按键中断触发方式(下降沿)。
    实现延时去抖动。
    在中断服务程序中改变LED灯的状态。

代码分析

延时函数

用于在按键按下时进行去抖动处理,避免误触发。

void Delayms(uint xms) {
    uint i, j;
    for(i = xms; i > 0; i--) 
        for(j = 587; j > 0; j--);
}

LED 初始化函数

将P2_0引脚设置为输出模式,并初始化LED灯为熄灭状态。

void InitLed(void) {
    P2DIR |= 0x01; // P2_0定义为输出
    LED1 = 1; // LED1灯熄灭
}

按键初始化函数

将按键连接的P0_5引脚设置为中断输入模式,并配置为下降沿触发。

void InitKey(void) {
    P0IEN |= 0x20; // P0_5设置为中断方式
    PICTL &=~ 0x20; // 下降沿触发
    IEN1 |= 0x20; // 允许P0口中断
    P0IFG = 0x00; // 初始化中断标志位
    EA = 1; // 开总中断
}

中断处理函数

在按键按下时触发中断,通过延时去抖动后,改变LED灯的状态。

#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR(void) {
    Delayms(10); // 去除抖动
    LED1 = ~LED1; // 改变LED1状态
    P0IFG = 0; // 清中断标志
    P0IF = 0; // 清中断标志
}

主函数

初始化LED和按键,并进入一个空循环,等待中断触发。

void main(void) {
    InitLed(); // 调用初始化函数
    InitKey(); // 调用按键初始化函数
    while(1); // 主循环,等待中断触发
}

结果

通过上述代码的实现,本项目能够成功实现按键控制LED灯的亮灭。按下按键时,LED灯状态改变(亮变灭或灭变亮),且响应迅速,能够正确识别按键动作。

项目分析

  1. 硬件配置
    硬件选择合理,使用CC2530芯片的GPIO和中断功能实现按键控制LED。
    连接简单,易于实现和调试。

  2. 软件设计
    程序结构清晰,模块化设计。
    延时函数有效去抖动,保证了按键检测的准确性。
    中断方式响应按键操作,避免了轮询方式的低效问题。

  3. 优点
    响应迅速,按键控制LED的效果明显。
    代码易于理解和维护,适合嵌入式系统初学者学习。

  4. 改进建议
    增加更多的按键和LED,扩展功能性。
    使用定时器中断进行更精确的延时处理。
    增加按键长按和短按功能的识别,丰富控制方式。

    五、将按键中断程序与按键查询程序进行对比。

按键查询程序

实现原理

按键查询程序通过轮询的方式不断检查按键的状态。如果检测到按键被按下(低电平),则执行相应的操作。

代码实现

#include <ioCC2530.h>
#define uint unsigned int
#define uchar unsigned char

// 定义控制 LED 灯的端口
#define LED1 P2_0 // LED1 为 P2_0 口控制
#define KEY1 P0_5 // KEY1 为 P0_5 口控制

// 函数声明
void Delayms(uint xms); // 延时函数
void InitLed(void); // 初始化 LED1
void InitKey(void); // 按键初始化
uchar KeyScan(void); // 按键扫描程序

/****************************
延时函数
*****************************/
void Delayms(uint xms) {
    uint i, j;
    for(i = xms; i > 0; i--)
        for(j = 587; j > 0; j--);
}

/****************************
LED 初始化函数
*****************************/
void InitLed(void) {
    P2DIR |= 0x01; // P2_0 定义为输出
    LED1 = 1; // LED1 灯熄灭
}

/****************************
按键初始化函数
*****************************/
void InitKey(void) {
    P0SEL &= ~0x20; // 设置 P0_5 为普通 IO 口
    P0DIR &= ~0x20; // 按键在 P0_5 口,设置为输入模式
    P0INP &= ~0x20; // 打开 P0_5 上拉电阻
}

/****************************
按键检测函数
*****************************/
uchar KeyScan(void) {
    if (KEY1 == 0) {
        Delayms(10); // 去抖动
        if (KEY1 == 0) {
            while (!KEY1); // 松手检测
            return 1; // 有按键按下
        }
    }
    return 0; // 无按键按下
}

/****************************
主函数
****************************/
void main(void) {
    InitLed(); // 调用初始化函数
    InitKey(); // 调用按键初始化函数
    while (1) {
        if (KeyScan()) // 按键改变 LED 状态
            LED1 = ~LED1;
    }
}

按键中断程序

实现原理

按键中断程序设置按键为中断输入,配置为下降沿触发。当按键被按下时,触发中断服务程序,执行相应的操作。

代码实现

#include <ioCC2530.h>
#define uint unsigned int
#define uchar unsigned char

// 定义控制 LED 灯的端口
#define LED1 P2_0 // LED1 为 P2_0 口控制
#define KEY1 P0_5 // 中断口

// 函数声明
void Delayms(uint xms); // 延时函数
void InitLed(void); // 初始化 LED1
void InitKey(void); // 按键初始化
uchar KeyValue = 0; 

/****************************
延时函数
*****************************/
void Delayms(uint xms) {
    uint i, j;
    for (i = xms; i > 0; i--)
        for (j = 587; j > 0; j--);
}

/****************************
LED 初始化函数
*****************************/
void InitLed(void) {
    P2DIR |= 0x01; // P2_0 定义为输出
    LED1 = 1; // LED1 灯熄灭
}

/****************************
按键初始化函数 -- 外部中断方式
*****************************/
void InitKey(void) {
    P0IEN |= 0x20; // P0_5 设置为中断方式
    PICTL &= ~0x20; // 下降沿触发
    IEN1 |= 0x20; // 允许 P0 口中断
    P0IFG = 0x00; // 初始化中断标志位
    EA = 1; // 开总中断
}

/****************************
中断处理函数
*****************************/
#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR(void) {
    Delayms(10); // 去除抖动
    LED1 = ~LED1; // 改变 LED1 状态
    P0IFG = 0; // 清中断标志
    P0IF = 0; // 清中断标志
}

/****************************
主函数
****************************/
void main(void) {
    InitLed(); // 调用初始化函数
    InitKey(); // 调用按键初始化函数
    while (1); // 主循环,等待中断触发
}

对比分析

轮询方式(按键查询程序)

优点:

  • 实现简单,易于理解和调试。
  • 不需要配置中断相关的寄存器。

缺点:

  • 效率低,CPU需要不断轮询按键状态,浪费处理器资源。
  • 在复杂系统中,这种方式可能导致响应不及时。

中断方式(按键中断程序)

优点:

  • 响应迅速,按键按下时立即触发中断,无需轮询。
  • CPU资源利用效率高,可以在空闲时处理其他任务。

缺点:

  • 需要配置中断相关的寄存器,程序复杂度较高。
  • 需要注意中断优先级和中断处理时的竞态条件等问题。

涉及中断的代码

中断初始化代码

void InitKey(void) {
    P0IEN |= 0x20; // P0_5 设置为中断方式
    PICTL &= ~0x20; // 下降沿触发
    IEN1 |= 0x20; // 允许 P0 口中断
    P0IFG = 0x00; // 初始化中断标志位
    EA = 1; // 开总中断
}

中断处理函数

#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR(void) {
    Delayms(10); // 去除抖动
    LED1 = ~LED1; // 改变 LED1 状态
    P0IFG = 0; // 清中断标志
    P0IF = 0; // 清中断标志
}

通过对比可以看出,轮询方式适合简单的、对实时性要求不高的应用场景。而中断方式更加高效,适合对响应速度要求较高的应用,能够充分利用CPU资源。