前言
独立按键是移植的嵌入式的程序,准备嵌入式的时候参考一位博主的思路写的,通过状态机判断按键的状态,然后判别长按键和短按键,这种写法不同于使用延时会产生阻塞浪费cpu资源。
矩阵按键还是老思路,进行行列扫描读取电平数据后再判断是否有按键按下。只是国信长天这块开发板的矩阵按键接在单片机的P3、P4上所以读取起来会复杂一些些。这个矩阵按键如果按我之前那篇博客那样写会有点复杂,比赛时如果紧张忘记或算错了就麻烦了。这里介绍的是之前准备蓝桥杯单片机比赛的时候和实验室的一位小伙伴学的,这种写法简单直接(感觉和她性格一样够直接的)而且不易出错,我在此基础上加了防连按功能,其他的比如长按也能加......
思路
程序
key.c
#include "key.h"
char KeyValue=0,KeyFlag=0;
/*
函数功能 : 矩阵按键扫描函数,将此函数定时执行,可识按键按下并在按键松开时返回按键的编号
函数参数 : 空
返 回 值 : 按键编号 on 0
*/
char scankey16(){
unsigned int key=0;
static char keynum=0;
P42=1;P44=1;P3=0x2f;//扫描第一列的四个按键
key = P3&0x0f;//记录下扫描的值
key<<=4;//整体向左移四位
P42=1;P44=1;P3=0x1f;//扫描第二列的四个按键
key |= P3&0x0f;//记录下扫描的值
key<<=4;//整体向左移四位
P42=0;P44=1;P3=0x3f;//扫描第三列的四个按键
key |= P3&0x0f;//记录下扫描的值
key<<=4;//整体向左移四位
P42=1;P44=0;P3=0x3f;//扫描第四列的四个按键
key |= P3&0x0f;//记录下扫描的值
if(KeyFlag==1)//如果已经完成了按键按下判断,并记录了按下的按键
{
if(key==0xffff)//如果按键被释放了,则返回记录了按下的按键
{
KeyFlag=0;//清除标志位
return KeyValue;//返回键值
}
else return 0;//如果按键还被按着,则返回0
}
if(key!=0xffff)keynum++;//如果扫描到的数据不是全高,则代表有按键被按下
else keynum=0;
if(keynum>5)//如果连续扫描到多次有按键按下,则进行按键按下判断
{
keynum=0;//清除扫描次数
KeyFlag=1;//将按键按下标志位置1
// 将扫描得到的数据按位取反,因为如果被按下就会读到低电平,取反后为1
//一下子哪个按键下是不是就一目了然了
switch(~key){
case 0x0008:KeyValue=4;break;//按键的编号
case 0x0004:KeyValue=5;break;
case 0x0002:KeyValue=6;break;
case 0x0001:KeyValue=7;break;
case 0x0080:KeyValue=8;break;
case 0x0040:KeyValue=9;break;
case 0x0020:KeyValue=10;break;
case 0x0010:KeyValue=11;break;
case 0x0800:KeyValue= 12;break;
case 0x0400:KeyValue= 13;break;
case 0x0200:KeyValue= 14;break;
case 0x0100:KeyValue= 15;break;
case 0x8000:KeyValue= 16;break;
case 0x4000:KeyValue= 17;break;
case 0x2000:KeyValue= 18;break;
case 0x1000:KeyValue= 19;break;
}
}
return 0;
}
//定义按键的引脚
sbit S7=P3^0;
sbit S6=P3^1;
sbit S5=P3^2;
sbit S4=P3^3;
Key Bsp_key[4] = {0};
/*
函数功能 : 独立按键扫描函数,将此函数定时执行,可识别长短按键
函数参数 : 空
返 回 值 : 空
*/
void KeyScan(void)
{
char i=0;
Bsp_key[0].Pin = S7;
Bsp_key[1].Pin = S6;
Bsp_key[2].Pin = S5;
Bsp_key[3].Pin = S4;
for(i=0;i<4;i++)
{
switch(Bsp_key[i].State)
{
case 0:{//扫描是否有按键被按下
if(Bsp_key[i].Pin == 0)
{
Bsp_key[i].State = 1;
}
}break;
case 1:{//按键消抖
if(Bsp_key[i].Pin == 0)
{
Bsp_key[i].State = 2;//按键消抖状态
}
else
{
Bsp_key[i].State = 0;//回到按键扫描状态
}
}break;
case 2:{//记录按键触发时间长度
if(Bsp_key[i].Pin == 0)
{
Bsp_key[i].LongTim++;//如果按键还未松开则一直记录时间(可加一个判断如果按键按下时间超过某个值时强行退出)
}
else
{
Bsp_key[i].State = 3;//判断是长按键还是短按键状态
}
}break;
case 3:{//判断是长按键还是短按键
if(Bsp_key[i].LongTim >= LongTim_Data)
{
Bsp_key[i].LongFlag = 1;//长按键标志位
}
else
{
Bsp_key[i].Flag = 1;//短按键标志位
}
Bsp_key[i].LongTim = 0;//清除记录的按键按下时间值
Bsp_key[i].State = 0;//回到按键扫描状态
}break;
}
}
}
key.h
#ifndef __KEY_H
#define __KEY_H
#include <STC15F2K60S2.H>
typedef struct
{
char Pin;//记录引脚电平
unsigned char State;//记录按键扫描的状态
char Flag;//记录短按键标志位
char LongFlag;//记录长按键标志位
unsigned int LongTim;//记录按键按下时间
}Key;
#define LongTim_Data 70//设置长按键判断时间
extern Key Bsp_key[4];
void KeyScan(void);
char scankey16();
#endif
main
#include "key.h"
/**** 应用 ******/
void main(void)
{
char i=0,j=0;
LED_Init();//初始化LED,LED全灭
Relay_BUZZ_Init();//初始化关闭蜂鸣器、蜂鸣器
while(1)
{
i = scankey16();
if(i != 0)//如果返回值不是零
{
j = i;
}
smg_SetOne(1,j/10);//显示按键序号的十位
smg_SetOne(2,j%10);//显示按键序号的个位
}
}