微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 按键扫描程序分析

按键扫描程序分析

时间:10-02 整理:3721RD 点击:
首先声明:程序是从《手把手收教你学51单片机》而来,之所以在这里发帖,是想让更多的单片机高手评论一下这些程序写的到底如何

#include <reg52.h>

sbit KEY_IN_1 = P2^4; //矩阵按键的扫描输入引脚1

sbit KEY_IN_2 = P2^5; //矩阵按键的扫描输入引脚2

sbit KEY_IN_3 = P2^6; //矩阵按键的扫描输入引脚3

sbit KEY_IN_4 = P2^7; //矩阵按键的扫描输入引脚4

sbit KEY_OUT_1 = P2^3; //矩阵按键的扫描输出引脚1

sbit KEY_OUT_2 = P2^2; //矩阵按键的扫描输出引脚2

sbit KEY_OUT_3 = P2^1; //矩阵按键的扫描输出引脚3

sbit KEY_OUT_4 = P2^0; //矩阵按键的扫描输出引脚4

sbit ADDR0 = P1^0;

sbit ADDR1 = P1^1;

sbit ADDR2 = P1^2;

sbit ADDR3 = P1^3;

sbit ENLED = P1^4;

unsigned char code LedChar[] = {

0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,

0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8e

}; //数码管真值表

const unsigned char code KeyCodeMap[4][4] = { //矩阵按键编号到PC 标准键盘键码的映射表

{ '1', '2', '3', 0x26 }, //数字键1、数字键2、数字键3、向上键

{ '4', '5', '6', 0x25 }, //数字键4、数字键5、数字键6、向左键

{ '7', '8', '9', 0x28 }, //数字键7、数字键8、数字键9、向下键

{ '0', 0x1B, 0x0D, 0x27 } //数字键0、ESC 键、回车键、向右键      };

unsigned char KeySta[4][4] = { //全部矩阵按键的当前状态

{1, 1, 1, 1},

{1, 1, 1, 1},

{1, 1, 1, 1},

{1, 1, 1, 1}

}; //由于数组不能定义成bit 型,这里定义成unsigned char 型

unsigned char LedBuf[6] = { //数码管动态扫描显示缓冲区

0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

};   //// 要这个显示缓冲区干嘛?

void DisplayNum(unsigned long num);

void KeyAction(unsigned char keycode);

void main(void)

0{

unsigned char i, j;

unsigned char backup[4][4] = { //按键值备份,保存前一次的值

{1, 1, 1, 1},

{1, 1, 1, 1},

{1, 1, 1, 1},

{1, 1, 1, 1}             };

//选择数码管进行显示

P0 = 0xFF;

ADDR3 = 1;

ENLED = 0;

//配置T0 工作在模式1,定时1ms

TMOD = 0x01;

TH0 = 0xFC;

TL0 = 0x67;

TR0 = 1;

ET0 = 1;

EA = 1;

while(1)

1{ //检索按键状态的变化

for (i=0; i<4; i++)

2{for (j=0; j<4; j++)

3{if (backup[j] != KeySta[j])

4{if (backup[j] == 0) //按键弹起时执行动作

5{KeyAction(KeyCodeMap[j]);}5

backup[j] = KeySta[j];}4  

  }3    }2    }1      }0

void KeyAction(unsigned char keycode)

{

static unsigned long result = 0; //用于保存运算结果

static unsigned long addend = 0; //用于保存输入的加数

if ((keycode>='0') && (keycode<='9')) //输入0-9 的数字

{addend = (addend*10) + (keycode-'0'); //原数据扩大10 倍,由新输入的

字填充其个位

DisplayNum(addend); //运算结果显示到数码管    }

else if (keycode == 0x26) //向上键用作加号,执行加法或连加运算

{result += addend; //进行加法运算

addend = 0;

DisplayNum(result); //运算结果显示到数码管}

else if (keycode == 0x0D) //回车键,执行加法运算(实际效果与加号并无区

别){ result += addend; //进行加法运算

addend = 0;

DisplayNum(result); //运算结果显示到数码管 }

else if (keycode == 0x1B) //Esc 键,清零结果

{addend = 0;

result = 0;

DisplayNum(addend); //清零后的加数显示到数码管}

}

void DisplayNum(unsigned long num)

{

signed char i;

unsigned char buf[6];

for (i=0; i<6; i++) //把长整型数转换为6 位十进制的数组

{buf = num % 10;   num /= 10;   }

for (i=5; i>=1; i--) //从最高位起,遇到0 即转换为空格,遇到非0 即退出

{if (buf == 0)

{LedBuf = 0xFF;}

else

{break;}

}

for ( ; i>=0; i--) //剩余低位都如实转换为数字

{LedBuf = LedChar[buf];}

}

void InterruptTimer0() interrupt 1

{

unsigned char i;

static unsigned char ledcnt = 0; //数码管扫描计数器

static unsigned char keyout = 0; //矩阵按键扫描输出计数器

static unsigned char keybuf[4][4] = { //按键扫描缓冲区,保存一段时间内的扫描值

{0xFF, 0xFF, 0xFF, 0xFF},

{0xFF, 0xFF, 0xFF, 0xFF},

{0xFF, 0xFF, 0xFF, 0xFF},

{0xFF, 0xFF, 0xFF, 0xFF}};

TH0 = 0xFC; //溢出后进入中断重新赋值

TL0 = 0x67;

//将一行的4 个按键值移入缓冲区

keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;

keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;

keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;

keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;

//消抖后更新按键状态

for (i=0; i<4; i++) //每行4 个按键,所以循环4 次

{  if ((keybuf[keyout] & 0x0F) == 0x00)

{ //连续4 次扫描值为0,即16ms(4*4ms)内都只检测到按下状态时,可认为

按键已按下KeySta[keyout] = 0;}

else if ((keybuf[keyout] & 0x0F) == 0x0F)

{ //连续4 次扫描值为1,即16ms(4*4ms)内都只检测到弹起状态时,可认为

按键已弹起KeySta[keyout] = 1;}

}

//执行下一次的扫描输出

keyout++;

keyout &= 0x03;

switch (keyout)

{case 0:  KEY_OUT_4 = 1;   KEY_OUT_1 = 0;    break;

case 1:  KEY_OUT_1 = 1;   KEY_OUT_2 = 0;    break;

case 2:  KEY_OUT_2 = 1;   KEY_OUT_3 = 0;    break;

case 3:   KEY_OUT_3 = 1;   KEY_OUT_4 = 0;     break;

default:   break;              }

//执行数码管动态扫描显示

P0 = 0xFF;

switch (ledcnt)

{

case 0: ADDR0=0; ADDR1=0; ADDR2=0; break;

case 1: ADDR0=1; ADDR1=0; ADDR2=0; break;

case 2: ADDR0=0; ADDR1=1; ADDR2=0; break;

case 3: ADDR0=1; ADDR1=1; ADDR2=0; break;

case 4: ADDR0=0; ADDR1=0; ADDR2=1; break;

case 5: ADDR0=1; ADDR1=0; ADDR2=1; break;

default: break;             }

P0 = LedBuf[ledcnt];

ledcnt++;

if    (ledcnt >= 6)

{ ledcnt = 0; }  }


大家仔细看一下程序,分析一下其功能是什么? 能实现吗?

可以实现一个简单一次运算的计算器

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top