面向物联网的CC2530与传感器应用开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

任务5 键盘按键的设计与实现

本任务重点学习微处理器的中断,以及CC2530的外部中断,掌握外部中断的基本原理、功能和驱动方法,通过驱动CC2530的GPIO来实现对键盘按键的检测。

5.1 开发场景:如何检测键盘按键

使用计算机时通常需要通过使用键盘输入需要的信息,但键盘输入信息的时间和每次敲击的按键都是不规律的,键盘要如何处理这些突发的敲击事件呢?键盘使用了中断,当按键按下时触发中断,键盘对按键进行识别和编码,并将结果发送到计算机系统,从而完成一次键值的输入。本项目通过键盘按键来学习和使用微处理器的外部中断。计算机键盘如图5.1所示。

图5.1 计算机键盘

5.2 开发目标

(1)知识要点:微处理器的中断功能和原理;CC2530微处理器的外部中断。

(2)技能要点:掌握中断的功能和原理;掌握CC2530微处理器外部中断的使用。

(3)任务目标:使用CC2530微处理器模拟键盘按键功能,通过编程使用CC2530微处理器的外部中断,实现对连接在CC2530微处理器引脚上按键动作的捕获,由CC2530微处理器开发板上指示灯的变化表示按键动作的反馈。

5.3 原理学习:微处理器中断

5.3.1 中断基本概念与定义

1.中断概念

中断是指微处理器在执行某段程序的过程中,由于某种原因,暂时中止原程序的执行,转去执行相应的处理程序,并在中断服务程序执行完后,再返回来继续执行被中断的原程序的过程。

例如,你正在专心看书,突然电话铃响,去接电话,接完电话后再回来继续看书。电话铃响后接听电话的过程称为中断。正在看书相当于计算机执行程序,电话铃响相当于事件发生(中断请求及响应),接电话相当于中断处理,回来继续看书是中断返回(继续执行程序),因此中断是指微处理器在执行某段程序的过程中,由于某种原因,暂时中止原程序的执行,转去执行相应的处理程序,中断服务程序执行完后,再回来继续执行被中断的原程序的过程。中断事件处理原理如图5.2所示。

图5.2 中断事件处理原理

2.中断的响应过程

中断事件处理指微处理器在程序运行中处理出现的紧急事件的整个过程。在程序运行过程中,如果系统外部、系统内部或者程序本身出现紧急事件,微处理器立即中止现行程序的运行,自动转入相应的处理程序(中断服务程序),待处理完后,再返回原来的程序运行,这个过程称为程序中断。

中断响应过程如图5.3所示,按照事件发生的顺序,中断响应过程包括:

图5.3 中断响应过程

(1)中断源发出中断请求。

(2)判断微处理器是否允许中断,以及该中断源是否被屏蔽。

(3)优先权排队。

(4)微处理器执行完当前指令或当前指令无法执行完,则立即停止当前程序,保护断点地址和微处理器当前状态,转入相应的中断服务程序。

(5)执行中断服务程序。

(6)恢复被保护的状态,执行中断返回指令回到被中断的程序或转入其他程序。

3.中断的作用

在电子应用领域,很多时候需要实时处理各种事件,微处理器进行控制应用时,要处理的数据不仅仅来自程序本身,也要对外部事件做出响应,如某个按键被按下、逻辑电路出现某个脉冲等。为了对外部事件做出快速的响应,微处理器引入了中断,作用如下。

(1)微处理器与外设并行工作:解决微处理器速度快、外设速度慢的矛盾。

(2)实时处理:控制系统往往有许多数据需要采集或输出,实时控制中有的数据难以估计何时需要交换。

(3)故障处理:计算机系统的故障往往随机发生,如电源断电、运算溢出、存储器出错等,采用中断技术,系统故障一旦出现,就能及时得到处理。

(4)实现人机交互:人和微处理器的交互一般采用键盘和按键,可以采用中断的方式实现,采用中断方式时微处理器的执行效率较高,而且可以保证人机交互的实时性,故中断方式在人机交互中得到了广泛的应用。

4.中断优先级

在微处理器的应用中,大部分情况都需要处理多个来自多个中断源的中断申请,需要根据中断请求的紧急度或者系统确定的中断请求次序依次做出响应,所以微处理器会在系统中确定不同中断请求的优先级别,也就是中断优先级。

微处理器在接收到中断请求后,在对中断请求进行响应并执行中断处理指令时,需要知道被执行的中断处理指令的具体位置,也就是中断处理执行的地址,即中断矢量(也称为中断向量)。系统中所有的中断矢量构成了系统的中断矢量表,在中断矢量表中,所有中断类型依次排序。中断矢量表中的每一种中断矢量号代码都连接着相应的操作命令,这些操作命令都放置在系统内的储存单元,中断矢量表所包含的就有这些操作命令的读取地址。在中断请求得到响应时,可以通过查询中断矢量表从而知道对应的中断处理指令并执行操作。例如,C51微处理器有5个中断,分别是外部中断0中断(IE0)、计数/定时器0中断(TF0)、外部中断1中断(IE1)、计数/定时器1中断(TF1)和串行接口中断(TI/RI),如图5.4所示。

图5.4 C51中断优先级

在某一时刻有几个中断源同时发出中断请求时,微处理器只能响应优先权最高的中断源。当微处理器正在运行某个中断服务程序的期间出现了另一个中断源的请求,如果后者的优先权低于前者,则微处理器不予理睬,反之,微处理器立即响应后者,进入所谓的嵌套中断。中断优先权的排序由其性质、重要性以及处理的方便性决定,由硬件的优先权仲裁逻辑或软件的顺序询问程序来实现。中断嵌套如图5.5所示。

图5.5 中断嵌套

5.外部中断

在没有干预的情况下,微处理器的程序会在封闭状态下自主运行,如果在某一时刻需要响应一个外部事件(如键盘或者鼠标),这时就会用到外部中断。具体来讲,外部中断是指在微处理器的一个引脚上,由于外部因素导致了一个电平的变化(如由高变低),而通过捕获这个变化,微处理器内部自主运行的程序就会被暂时中断,转而去执行相应的中断处理程序,执行完后又回到中断的地方继续执行原来的程序。这个引脚上的电平变化,就申请了一个外部中断事件,而这个能申请外部中断的引脚就是外部中断的触发引脚。

外部中断是微处理器实时处理外部事件的一种内部机制,当某种外部事件发生时,中断系统将迫使微处理器暂停正在执行的程序,转而去进行中断事件的处理;中断处理完毕后又返回被中断的程序处,继续执行下去。

6.外部中断触发条件

外部中断触发条件是指在程序运行时,触发外部中断的方式。外部中断的触发方式是由程序定义的,根据微处理器外部电平的变化特性,可将外部中断触发方式分为三种,分别是上升沿触发、下降沿触发、跳变沿触发。由于上升沿触发与下降沿触发都属于电平一次变化触发,因此这两种触发可归结为电平触发方式。

(1)电平触发方式。在数字电路中,电平从低电平变为高电平的一瞬间称为上升沿;相反,从高电平变为低电平的一瞬间称为下降沿。这种电平变化同样可以用微处理器来检测,当配置了外部中断的引脚接收到相应的电压变化后会触发外部中断,从而执行中断服务函数。上升沿、下降沿电平变化如图5.6所示。

图5.6 上升沿、下降沿电平变化

(2)跳变沿触发方式。若外部中断定义为跳变沿触发方式,外部中断申请触发器可以锁存外部中断输入线上的跳变沿,即使微处理器暂时不能响应,中断申请标志也不会丢失。在这种方式中,如果连续两次采样,在一个机器周期采样到外部中断输入为高电平,在下一个机器周期采样为低电平,则置1中断申请触发器,直到微处理器响应此中断后才清0。这样不会丢失中断,但输入的脉冲宽度应至少保持12个时钟周期(晶振频率为12 MHz),才能被微处理器采样到。外部中断跳变沿触发方式适合以脉冲形式输入的外部中断请求。

5.3.2 CC2530与外部中断

中断是CC2530实时处理内部或外部事件的一种机制,当发生某个内部事件或外部事件时,CC2530的中断系统将迫使其暂停正在执行的程序,转而去进行中断事件的处理,中断处理完毕后,再返回被中断的程序位置继续执行下去。中断又分为外部中断和内部中断。

GPIO引脚设置为输入模式后,可以用于产生中断,并设置为外部信号的上升沿或下降沿触发。CC2530的外部中断配置寄存器主要有七个,这七个寄存器分别是P0IFG(端口0中断状态标志寄存器)、P1IFG(端口1中断状态标志寄存器)、P2IFG(端口2中断状态标志寄存器)、P1CTL(端口1中断控制寄存器)、P0IEN(端口0中断屏蔽寄存器)、P1IEN(端口1中断屏蔽寄存器)、P2IEN(端口2中断屏蔽寄存器)。P0、P1和P2都有中断使能位,对于IEN1~IEN2寄存器内的端口所有的位都是公共的,如下所述。

● IEN1.P0IE:P0中断使能。

● IEN2.P1IE:P1中断使能。

● IEN2.P2IE:P2中断使能。

P0~P2的中断屏蔽寄存器如表5.1到表5.3所示。

表5.1 P0中断屏蔽寄存器

表5.2 P1中断屏蔽寄存器

表5.3 P2中断屏蔽寄存器

除了公共中断使能位,每个端口都有位于SFR寄存器P0IEN、P1IEN和P2IEN的单独中断使能位,配置外设I/O或GPIO引脚使能都会有中断产生。

当中断发生时,不管引脚是否设置了它的中断使能位,P0~P2中断状态标志寄存器P0IFG、P1IFG或P2IFG中相应的中断状态标志将被置1;当中断执行时,中断状态标志被清除,该标志清0,且该标志必须在清除微处理器端口中断标志(PxIF)之前清除,功能如下。

● PICTL:P0、P1、P2的触发设置。

● P0IFG:P0中断状态标志。

● P1IFG:P1中断状态标志。

● P2IFG:P2中断状态标志。

P1CTL(端口1中断控制寄存器)如表5.4所示。

表5.4 P1CTL(端口1中断控制寄存器)

P0IFG(端口0中断状态标志寄存器)如表5.5所示。

表5.5 P0IFG(端口0中断状态标志寄存器)

P1IFG(端口1中断状态标志寄存器)如表5.6所示。

表5.6 P1IFG(端口1中断状态标志寄存器)

P2IFG(端口2中断状态标志寄存器)如表5.7所示。

表5.7 P2IFG(端口2中断状态标志寄存器)

5.4 任务实践:键盘按键检测的软/硬件设计

5.4.1 开发设计

1.硬件设计

本任务的硬件架构设计如图5.7所示。

图5.7 硬件架构设计图

按键接口电路如图5.8所示,按键K1的引脚2接GND,引脚1接电阻和CC2530微处理器的引脚P1_2,电阻的另一端连接3.3 V的电源。

图5.8 按键接口电路图

按键的状态检测主要使用CC2530微处理器GPIO的引脚电平读取功能,相关引脚为高电平时引脚电平的读取值为1,反之则为0。而按键是否被按下、按下前后的电平状态则需要按照实际的按键接口电路来确认,如图5.8所示。当按键没有按下时,K1的引脚1和引脚2断开,由于CC2530微处理器引脚在输入模式时为高阻态,所以引脚P1_2的电平为高电平;当K1按键按下时K1的引脚1和引脚2导通,此时引脚P1_2导通接地,所以引脚的电平为低电平。

要实现对键盘按键的检测中断,在于对CC2530微处理器中断的使用。按键没有按下时引脚电平为高电平,当按键按下后电平变为低电平。而针对与外部中断的电平判断,则可以理解为低电平触发外部中断,可以选择外部中断的触发方式为下降沿触发。

本任务用到的是CC2530的外部中断,所涉及的寄存器有P1IEN、POINP、P1INP、PICTL、IEN1和P1IFG,其中,P1IEN用于各个控制口的中断使能,0为中断禁止,1为中断使能,表5.8是P1IEN功能分配表。

表5.8 P1IEN功能分配表

P1INP用于设置各个I/O口的输入模式,0为上拉/下拉,1为三态模式,如表5.9所示。

表5.9 P1INP功能分配表

在PICTL中,D0~D3设置各个端口的中断触发方式,0为上升沿触发,1为下降沿触发;D7控制I/O引脚在输出模式下的驱动能力,选择输出驱动能力增强来补偿引脚DVDD的低I/O电压,确保在较低的电压下的驱动能力和较高电压下相同,0为最小驱动能力增强,1为最大驱动能力增强,如表5.10所示。

表5.10 PICTL I/O口分配表

IEN1用于中断使能1,0为中断禁止,1为中断使能,表5.11为P1CTL功能分配表。

表5.11 P1CTL功能分配表

P1IFG为中断状态标志寄存器,当输入端口有中断请求时,相应的标志位将置1,表5.12是P1IFG功能分配表。

表5.12 P1IFG功能分配表

按键K1所连接的引脚为P1_2,因此中断应配置端口1的通道2的外部中断。按键K1的外部中断配置的步骤如下。

● 通过IEN1初始化引脚端口1的中断使能;

● 通过P1IEN配置端口P1_2的外部中断使能;

● 通过PICTL将中断触发方式配置为下降沿触发;

● 开启总中断EA。

2.软件设计

本任务软件设计思路如下。

(1)初始化系统时钟、LED引脚和外部中断并且打开LED2。

(2)初始化完成之后程序进入主循环,在主循环中,LED2处于常亮状态。

(3)当按键K1被按下时触发外部中断,主函数进入中断服务函数,延时10 ms,待电平稳定后如果按键依旧处于按下状态则确定K1按键被按下。

(4)检测到按键K1被按下时则执行对LED状态操作的程序,本任务对LED1和LED2的状态进行取反。

(5)执行完毕后,中断标志清0,主函数回到主程序中等待中断再次触发。

软件设计流程图如图5.9所示。

图5.9 软件设计流程图

5.4.2 功能实现

1.相关头文件模块

    /****************************************************************************************
    * 文件:led.h
    ****************************************************************************************/
    #define D1   P1_1                        //宏定义D1灯(即LED1)控制引脚P1_1
    #define D2   P1_0                        //宏定义D2灯(即LED2)控制引脚P1_0
    #define ON   0                          //宏定义打开状态ON
    #define OFF   1                          //宏定义关闭状态OFF

2.主函数模块

主函数完成初始化系统时钟、LED引脚和外部中断后,初始化LED2状态,然后进入主循环等待中断触发,主函数代码如下。

    /****************************************************************************************
    * 名称:main()
    * 功能:主函数
    ****************************************************************************************/
    void main(void)
    {
        xtal_init();                             //系统时钟初始化
        led_io_init();                           //LED引脚初始化
        ext_init();                             //外部中断初始化
        LED2=ON;                           //打开LED2
        while(1);                              //进入主循环
    }

3.系统时钟初始化模块

本模块主要启动CC2530系统时钟,初始化系统时钟存在一个等待时钟稳定的过程,因此需要初始化系统时钟,待系统时钟稳定后再执行程序。系统时钟的初始化函数代码如下。

    /****************************************************************************************
    * 名称:xtal_init()
    * 功能:CC2530系统时钟初始化
    ****************************************************************************************/
    void xtal_init(void)
    {
        CLKCONCMD&=~0x40;                     //选择32 MHz的外部晶体振荡器
        while(CLKCONSTA&0x40);                   //晶体振荡器开启且稳定
        CLKCONCMD&=~0x07;                     //选择32 MHz的系统时钟
    }

4.外部中断初始化模块

外部中断初始化为该项目的重要环节,可将外部中断配置为低电平触发(下降沿触发)。外部中断初始化函数代码如下。

    /****************************************************************************************
    * 名称:ext_init()
    * 功能:外部中断初始化
    ****************************************************************************************/
    void ext_init(void)
    {
        IEN2|=0x10;                              //端口1中断使能
        P1IEN|=0x04;                             //端口P1_2外部中断使能
        PICTL|=0x02;                             //端口P1_2低电平触发
        EA=1;                                   //使能总中断
    }

5.中断服务函数模块

任务4中的按键检测与本项目中的外部中断检测按键动作有着本质的区别,通过外部中断检测按键动作具有更高的实时性,同时执行LED操作函数也有所不同,外部中断的LED操作函数是在中断服务函数中完成的。外部中断服务函数(程序)如下:

    /****************************************************************************************
    * 名称:中断服务程序
    * 功能:外部中断
    ****************************************************************************************/
    #pragma vector = P1INT_VECTOR
    __interrupt void P1_ISR(void)
    {
        EA=0;                               //关中断
        if((P1IFG&0x04)>0){                   //按键中断
          P1IFG&=~0x04;                    //中断标志清0
          delay_ms(10);                       //按键防抖
          if(KEY1==ON){                    //判断按键按下
              LED2=~LED2;                  //翻转LED2状态
              LED1=~LED1;                  //翻转LED1状态
          }
        }
        EA=1;                               //开中断
    }

5.5 任务验证

使用IAR开发环境打开任务设计工程,程序通过编译后,由SmartRF下载到CC2530微处理器中,执行程序后,开发平台上LED2点亮,LED1熄灭。按下按键K1后LED2熄灭,LED1点亮;再次按下按键K1后LED2点亮,LED1熄灭,如此循环往复。

5.6 任务小结

通用对按键检测项目的学习与开发,读者可学习CC2530微处理器外部中断的基本原理,并通过按键触发外部中断的开发过程来学习CC2530微处理器的外部中断功能,采用CC2530外部中断响应连接在CC2530处理器上的按键动作,从而达到实时响应按键的目的。

5.7 思考与拓展

(1)简述中断概念、中断作用、中断响应过程。

(2)如何配置CC2530的外部中断?

(3)如何编写CC2530微处理器的外部中断服务函数?

(4)按键在使用过程中除了按下与弹起两种状态,还拥有两种按下的状态,这两种按下的状态分别是长按和短按。例如,智能手机,短按电源键的功能为手机熄屏,长按则为关机或重启功能。以智能手机电源键的功能为例通过查询方式实现长按和短按的功能,即短按按键时开或关一个LED,长按时开或关两个LED。