基于状态机的4x4矩阵键盘程序
时间:10-02
整理:3721RD
点击:
在我们初学单片机的时候,每当遇到使用按键我们都会遇到按键的消抖与松手检测的问题。传统的方法一般都是使用ms延时的方法来处理,这样处理是最省事,不需要考虑太多的问题。但是这样做带来的结果是白白浪费了单片机的资源。延时函数会让单片机傻傻的等待,不能去处理其他更重要的事情,这对于实时性要求较高,或者还有更多任务要处理的系统来说,是万万不可接受的,基于这个问题,今天跟大家分享一个基于状态机的按键程序,它不会让单片机处于傻等的尴尬状态。这是转载于马朝老师的一本书籍。
一、传统按键消抖处理方法:
if(按键按下)
delay_ms(10);
if(按键确实按下)
{进行任务处理}
二、基于状态机的按键处理方法:
1、首先是 keyboard.c 文件
//***************************************************************
// File Name : keyboard.c
// Author :
// Created :
// Modified :
// Revision :
//***************************************************************
#ifndef _keyboard_c_
#define _keyboard_c_
#include <reg52.h>
#include <intrins.h>
#include "keyboard.h"
//***************************************************************
//端口定义
//PIN DESCRIPTION
//P17 P16 P15 P14
// | | | |
// \---\---\---\---P10 1 2 3 F1
// \---\---\---\---P11 4 5 6 F2
// \---\---\---\---P12 7 8 9 F3
// \---\---\---\---P13 * 0 # F4
//***************************************************************
#define KeyPort P1
#define key_state_0 0 //定义按键状态(基于状态机)
#define key_state_1 1
#define key_state_2 2
#define key_state_3 3
#define NO_key 0
//***************************************************************
// Function : KeyBoardScan
// Input : none
// Output : Key Number
// 0~9、*、#:ASCII code
// F1、F2、F3、F4: (A、B、C、D) ASCII code
// Description : 4*4 matrix keyboard scanning Function
//
//***************************************************************
uchar KeyBoardScan(void)
{
uchar key_temp;
uchar key_num = NO_key;
static uchar key_status = key_state_0; //按键状态
//线反转法扫描键盘
KeyPort = 0x0f;
key_temp = KeyPort;
KeyPort = 0xf0;
key_temp |= KeyPort;
KeyPort = 0xff;
switch(key_status)
{
case key_state_0: //状态零为初始状态
if(key_temp != 0xff)
key_status = key_state_1;
break;
case key_state_1: //状态一为按键按下状态
if(key_temp == 0xff)
key_status = key_state_0; //若只是抖动,调回状态零
else
{
key_status = key_state_2; //若确实按下,调到状态二
switch(key_temp)
{
case 0x7e: //0111 1110
key_num = '1';
break;
case 0xbe: //1011 1110
key_num = '2';
break;
case 0xde: //1101 1110
key_num = '3';
break;
case 0x7d: //0111 1101
key_num = '4';
break;
case 0xbd: //1011 1101
key_num = '5';
break;
case 0xdd: //1101 1101
key_num = '6';
break;
case 0x7b: //0111 1011
key_num = '7';
break;
case 0xbb: //1011 1011
key_num = '8';
break;
case 0xdb: //1101 1011
key_num = '9';
break;
case 0xb7: //1011 0111
key_num = '0';
break;
case 0x77: //0111 0111
key_num = '*'; //*
break;
case 0xd7: //1101 0111
key_num = '#'; //#
break;
case 0xee: //1110 1110
key_num = 'A'; //F1
break;
case 0xed: //1110 1101
key_num = 'B'; //F2
break;
case 0xeb: //1110 1011
key_num = 'C'; //F3
break;
case 0xe7: //1110 0111
key_num = 'D'; //F4
break;
}
}
break;
case key_state_2: //状态二表示确实有按键按下
if(key_temp == 0xff)
key_status = key_state_3; //若检测到松手,调到状态三
break;
case key_state_3:
if(key_temp == 0xff)
key_status = key_state_0; //若判断确实松手后,调回初始状态零
else
key_status = key_state_2; //若只是抖动并不是真的松手,调回状态二
break;
}
return key_num;
}
#endif
//===============================END OF FILE==================================//
2、其次是 keyboard.h 文件
// File Name : keyboard.h
// Author :
// Created :
// Modified :
// Revision :
//***************************************************************
#ifndef _keyboard_h_
#define _keyboard_h_
#include <reg52.h>
#include "DataType.h"
//***************************************************************
//端口定义
//PIN DESCRIPTION
//P17 P16 P15 P14
// | | | |
// \---\---\---\---P10 1 2 3 F1
// \---\---\---\---P11 4 5 6 F2
// \---\---\---\---P12 7 8 9 F3
// \---\---\---\---P13 * 0 # F4
//***************************************************************
//global functions declaration
extern uchar KeyBoardScan(void);
#endif
//===============================END OF FILE==================================//
使用方法:以上程序代码只要添加到工程的源代码便可以。要利用单片机的定时器资源,每10-15ms中断一次,在中断里面调用 KeyBoardScan() 函数。
好了,以上就是今天要分享的知识,希望可以帮到大家,也留给不爱记录的自己,常温故而知新。
一、传统按键消抖处理方法:
if(按键按下)
delay_ms(10);
if(按键确实按下)
{进行任务处理}
二、基于状态机的按键处理方法:
1、首先是 keyboard.c 文件
//***************************************************************
// File Name : keyboard.c
// Author :
// Created :
// Modified :
// Revision :
//***************************************************************
#ifndef _keyboard_c_
#define _keyboard_c_
#include <reg52.h>
#include <intrins.h>
#include "keyboard.h"
//***************************************************************
//端口定义
//PIN DESCRIPTION
//P17 P16 P15 P14
// | | | |
// \---\---\---\---P10 1 2 3 F1
// \---\---\---\---P11 4 5 6 F2
// \---\---\---\---P12 7 8 9 F3
// \---\---\---\---P13 * 0 # F4
//***************************************************************
#define KeyPort P1
#define key_state_0 0 //定义按键状态(基于状态机)
#define key_state_1 1
#define key_state_2 2
#define key_state_3 3
#define NO_key 0
//***************************************************************
// Function : KeyBoardScan
// Input : none
// Output : Key Number
// 0~9、*、#:ASCII code
// F1、F2、F3、F4: (A、B、C、D) ASCII code
// Description : 4*4 matrix keyboard scanning Function
//
//***************************************************************
uchar KeyBoardScan(void)
{
uchar key_temp;
uchar key_num = NO_key;
static uchar key_status = key_state_0; //按键状态
//线反转法扫描键盘
KeyPort = 0x0f;
key_temp = KeyPort;
KeyPort = 0xf0;
key_temp |= KeyPort;
KeyPort = 0xff;
switch(key_status)
{
case key_state_0: //状态零为初始状态
if(key_temp != 0xff)
key_status = key_state_1;
break;
case key_state_1: //状态一为按键按下状态
if(key_temp == 0xff)
key_status = key_state_0; //若只是抖动,调回状态零
else
{
key_status = key_state_2; //若确实按下,调到状态二
switch(key_temp)
{
case 0x7e: //0111 1110
key_num = '1';
break;
case 0xbe: //1011 1110
key_num = '2';
break;
case 0xde: //1101 1110
key_num = '3';
break;
case 0x7d: //0111 1101
key_num = '4';
break;
case 0xbd: //1011 1101
key_num = '5';
break;
case 0xdd: //1101 1101
key_num = '6';
break;
case 0x7b: //0111 1011
key_num = '7';
break;
case 0xbb: //1011 1011
key_num = '8';
break;
case 0xdb: //1101 1011
key_num = '9';
break;
case 0xb7: //1011 0111
key_num = '0';
break;
case 0x77: //0111 0111
key_num = '*'; //*
break;
case 0xd7: //1101 0111
key_num = '#'; //#
break;
case 0xee: //1110 1110
key_num = 'A'; //F1
break;
case 0xed: //1110 1101
key_num = 'B'; //F2
break;
case 0xeb: //1110 1011
key_num = 'C'; //F3
break;
case 0xe7: //1110 0111
key_num = 'D'; //F4
break;
}
}
break;
case key_state_2: //状态二表示确实有按键按下
if(key_temp == 0xff)
key_status = key_state_3; //若检测到松手,调到状态三
break;
case key_state_3:
if(key_temp == 0xff)
key_status = key_state_0; //若判断确实松手后,调回初始状态零
else
key_status = key_state_2; //若只是抖动并不是真的松手,调回状态二
break;
}
return key_num;
}
#endif
//===============================END OF FILE==================================//
2、其次是 keyboard.h 文件
// File Name : keyboard.h
// Author :
// Created :
// Modified :
// Revision :
//***************************************************************
#ifndef _keyboard_h_
#define _keyboard_h_
#include <reg52.h>
#include "DataType.h"
//***************************************************************
//端口定义
//PIN DESCRIPTION
//P17 P16 P15 P14
// | | | |
// \---\---\---\---P10 1 2 3 F1
// \---\---\---\---P11 4 5 6 F2
// \---\---\---\---P12 7 8 9 F3
// \---\---\---\---P13 * 0 # F4
//***************************************************************
//global functions declaration
extern uchar KeyBoardScan(void);
#endif
//===============================END OF FILE==================================//
使用方法:以上程序代码只要添加到工程的源代码便可以。要利用单片机的定时器资源,每10-15ms中断一次,在中断里面调用 KeyBoardScan() 函数。
好了,以上就是今天要分享的知识,希望可以帮到大家,也留给不爱记录的自己,常温故而知新。
要说状态机的话,推荐看菜农的零耗时按键。
时间片轮询也可以
好用