按键篇
经过一短时间的学习,下面,亲自动手编写一下程序吧。
程序的目的是:按下按键,控制 LED 的亮和灭。短按键,则小灯亮 1 秒,然后灭;
长按键,小灯常亮。
首先,完成键盘的扫描程序。
第一点:如果是扫描,就要用到定时器。我想设计定时器每隔 10ms 扫描一次按
键。
定时器,我选用定时器 A。它的定时中断函数如下:
函数名称:TimerA_ISR
功 能:定时器 A 的中断服务函数
参 数:无
返回值 :无
********************************************/
#pragma vector = TIMERA0_VECTOR
__interrupt void TimerA_ISR(void)
{
GetKey();
}
上面这个定时中断函数的意思就是:每当定时时间到了以后,就调用 GetKey()
函数一次。GetKey()函数就是扫描键盘按键的函数了。在 GetKey()函数中,会
根据按键类型(长按/短按)返回不同的数值。根据返回的数值,做小灯亮法的
操作。那么,返回的这个值,我们需要保存在一个变量中,在这里定义一个变量
uchar FlagLcd ; 来保存返回值。这个变量在全局变量中定义,以保证它的作用
域。
那么定时函数就变为
#pragma vector = TIMERA0_VECTOR
__interrupt void TimerA_ISR(void)
{
FlagLcd =GetKey();
}
定时器中断的时间间隔,我在主函数中定义。
这样写:
CCTL0 = CCIE; //使能 CCR0 中断
CCR0 = 40; //设定周期 0.01S
TACTL = TASSEL_1 + ID_3 + MC_1; //定时器 A 的时钟源选择 ACLK,增计数模
式
这样,定时器这块就算完工了。那么,下面进行按键扫描程序。
按键的定义是这样的,根据我板子的按键原理图如下
这是一个矩阵键盘。其中 KEY 就是外部高电平 3.3V。我只想用其中的 P1.0 作为
这次试验的按键。那么,做些设置就可以了。将 P1.7 方向设置为输出,并输出
电平为低。这样,才能实现当 K1 按下时,P1.0 输入为低;当 K1 抬起时,P1.0
输入为高 的效果。
对 P1 口进行初始化:
void Init_Keypad(void)
{
P1DIR = 0xfe; //P1.0 设置为输入状态, P1.1~P1.7 设置为输出状态
P1OUT &= 0x7f; // P1.0~P1.6 输出高电平,P1.7 输出低电平
}
下面是键盘扫描函数:
unsigned char GetKey()
{
unsigned char keyRetu=0; //返回的按键值
static unsigned char s_keyState=0,keyTime=0; //按键状态,按键按下的时间
计数器
switch (s_keyState)
{
case 0:
if((P1IN&0x01)==0) //检测到有按键,转到状态 1,相当于是消抖过程。
((P1IN&0x01)==0 判断 P1.0 口输
入是高还是低电平
{
s_keyState=1;
}
break;
case 1:
if((P1IN&0x01)==0) //再次检测到有按键,转到状态 2
{
s_keyState=2;
keyTime=0; //清零按键时间计数器
}
else
{
s_keyState=0; //没有检测到按键,说明状态 0 检测到是一个抖动,重新转到状
态 0
}
break;
case 2:
if((P1IN&0x01)==1) //检测到按键松开
{
s_keyState=0; //状态转到状态 0
keyRetu=1; //输出 1
}
else
{
if(++keyTime>=50) //按下时间>1s
{
s_keyState=3; //转到状态 3
keyTime=0; //清零按键时间计数器
keyRetu=2; // 输出 2
}
}
break;
case 3:
if((P1IN&0x01)==1) //检测到按键松开
{
s_keyState=0; //状态转到状态 0
}
else
{
s_keyState=3; //转到状态 3
}
break;
}
return keyRetu;
}
上面这个扫描函数,根据按键 K1 是长按还是短按,返回不同的值:长按,返回
2;短按,返回 1。
获得了返回值以后,就要对 LED 进行操作了。
我的板子的 LED 如下图
LED 是 LED 供电高电平,这里我只想用其中的 D1 作为实验灯。初始化 P2.0 口:
P2DIR = 0xff; //设置 P2 口方向为输出
P2OUT = 0xff; //设置 P2 口输出高电平
那么 P2OUT = 0xfe,则 LED 亮;P2OUT = 0xff,则 LED 灭。这个很好实现。但
是,怎么样才能持续亮 1s 呢?这个问题还需要定时器来解决。我在这里还利用
定时器 A 来完成这个任务。
在主程序中定义全局变量 unsigned int TIME_1_S=0;然后再定时器中断函数中
做些改动
#pragma vector = TIMERA0_VECTOR
__interrupt void TimerA_ISR(void)
{
FlagLcd =GetKey();
If(FlagLcd==1)
TIME_1_S=1;
If((TIME_1_S>0)&&( TIME_1_S<100))
TIME_1_S++;
Else
TIME_1_S=0;
}
这样,在控制 LED 的时候,可以这样写
If(TIME_1_S>0)
P2OUT = 0xfe;
Else
P2OUT = 0xff;
就实现了亮 1S 的效果。
那么长按键的时候呢,则需要再做一下处理。
在主程序中定义全局变量 unsigned int TIME_L_S=0;然后再定时器中断函数中
做些改动
#pragma vector = TIMERA0_VECTOR
__interrupt void TimerA_ISR(void)
{
FlagLcd =GetKey();
If(FlagLcd==1)
TIME_1_S=1;
If((TIME_1_S>0)&&( TIME_1_S<100))
TIME_1_S++;
Else
TIME_1_S=0;
If(FlagLcd==2)
TIME_L_S=1;
}
If((TIME_1_S>0)||( TIME_L_S==1))
P2OUT = 0xfe;
Else
P2OUT = 0xff;
到这里,基本的实现函数都已经完成了。剩下的事情,就是把相关框架搭建一下
了
第一:是 main.c 文件
#include
#include "key.h"
unsigned char FlagLcd ;
unsigned int TIME_L_S=0;
unsigned int TIME_1_S=0;
void main(void)
{
P1DIR = 0XFF;P1OUT = 0XFF;
P2DIR = 0XFF;P2OUT = 0XFF;
P3DIR = 0XFF;P3OUT = 0XFF;
P4DIR = 0XFF;P4OUT = 0XFF;
P5DIR = 0XFF;P5OUT = 0XFF;
P6DIR = 0XFF;P6OUT = 0XFF;
WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
P6DIR |= BIT2;P6OUT |= BIT2; //关闭电平转换
CCTL0 = CCIE; //使能 CCR0 中断
CCR0 = 40; //设定周期 0.01S
TACTL = TASSEL_1 + ID_3 + MC_1; //定时器 A 的时钟源选择 ACLK,增计数模
式
P2DIR = 0xff; //设置 P2 口方向为输出
P2OUT = 0xff; //设置 P2 口输出高电平
Init_Keypad();
_EINT();//使能全局中断
while(1)
{
if((TIME_1_S>0)||( TIME_L_S==1))
P2OUT = 0xfe;
else
P2OUT = 0xff;
}
}
#pragma vector = TIMERA0_VECTOR
__interrupt void TimerA_ISR(void)
{
FlagLcd =GetKey();
if(FlagLcd==1)
TIME_1_S=1;
if((TIME_1_S>0)&&( TIME_1_S<100))
TIME_1_S++;
else
TIME_1_S=0;
if(FlagLcd==2)
TIME_L_S=1;
}
第二:key.c 文件
#include
void Init_Keypad(void)
{
P1DIR = 0xfe; //P1.0 设置为输入状态, P1.1~P1.7 设置为输出状态
P1OUT &= 0x7f; // P1.1~P1.7 输出高电平
}
unsigned char GetKey()
{
unsigned char keyRetu=0; //返回的按键值
static unsigned char s_keyState=0,keyTime=0; //按键状态,按键按下的时间
计数器
switch (s_keyState)
{
case 0:
if((P1IN&0x01)==0) //检测到有按键,转到状态 1,相当于是消抖过程
{
s_keyState=1;
}
break;
case 1:
if((P1IN&0x01)==0) //再次检测到有按键,转到状态 2
{
s_keyState=2;
keyTime=0; //清零按键时间计数器
}
else
{
s_keyState=0; //没有检测到按键,说明状态 0 检测到是一个抖动,重新转到状
态 0
}
break;
case 2:
if((P1IN&0x01)==1) //检测到按键松开
{
s_keyState=0; //状态转到状态 0
keyRetu=1; //输出 1
}
else
{
if(++keyTime>=50) //按下时间>1s
{
s_keyState=3; //转到状态 3
keyTime=0; //清零按键时间计数器
keyRetu=2; // 输出 2
}
}
break;
case 3:
if((P1IN&0x01)==1) //检测到按键松开
{
s_keyState=0; //状态转到状态 0
}
else
{
s_keyState=3; //转到状态 3
}
break;
}
return keyRetu;
}
第三:key.h 文件
void Init_Keypad(void);
unsigned char GetKey();