//方法1-推荐
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit BEEP = P3^7; //蜂鸣器
//定义数码管0到F
uchar code DSY_CODE[]=
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x00
};
uchar Pre_KeyNO = 16,KeyNO = 16; //1 0000 为了后面的扫描按键
void DelayMS(uint ms)
{
uchar t;
while(ms--)
{
for(t=0;t<120;t++);
}
}
//检查是那个按键被按下
void Keys_Scan()
{
uchar Tmp;
P1 = 0x0f;
DelayMS(1);
Tmp = P1 ^ 0x0f; //
switch(Tmp) //列
{
case 1: KeyNO = 0; break;
case 2: KeyNO = 1; break;
case 4: KeyNO = 2; break;
case 8: KeyNO = 3; break;
default: KeyNO = 16;
}
P1 = 0xf0;
DelayMS(1);
Tmp = P1 ^ 0xf0;
// Tmp = P1 >> 4 ^ 0x0f;
switch(Tmp) //行
{
case 1: KeyNO += 0; break;
case 2: KeyNO += 4; break;
case 4: KeyNO += 8; break;
case 8: KeyNO += 12;
}
}
//蜂鸣器函数
void Beep()
{
uchar i;
for(i=0;i<100;i++)
{
DelayMS(1);
BEEP = ~BEEP;
}
BEEP = 1;
}
void main()
{
P0 = 0x00; //给数码管引脚初始化,数码管全灭
while(1)
{
P1 = 0xf0; //给P1初始化,但按键有一个被按下,P1 != 0xf0
if(P1 != 0xf0)
Keys_Scan();
if(Pre_KeyNO != KeyNO) //当KeyNO不等于16时,有按键被按下,进行数码管点亮
{
P0 = ~DSY_CODE[KeyNO]; //数码管是共阴极的
Beep();
Pre_KeyNO = KeyNO;
}
DelayMS(100);
}
}
方法2
#include <reg52.h>
#define LED_PORT P0//定义数码管接口
#define KEY_PORT P1//定义键盘接口
sbit BEE=P3^0;//定义蜂鸣器接口
char rowValue;//按键所在的行值 从0开始
char columnValue;//按键所在的列值 从0开始
/***********************
**按键键值所对应的编码**
** 0 1 2 3 **
** 4 5 6 7 **
** 8 9 A B **
** C D E F **
***********************/
char keyCode[][4]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
/*******************************************************
函数名:ledDsplay()
功能:根据按键的“行值”和“列值”,把按键的值显示到数码管,
当“行值”和“列值”为“-1”时,数码管灭灯
输入参数:
row:按键的“行值
column:按键的“列值”
输出参数: 无
返回值:无
*******************************************************/
void ledDsplay(char row,char column)
{
if((-1==row) && (-1==column))
LED_PORT = 0;//来数码管
else
LED_PORT = keyCode[row][column];//显示键值
}
void delay(unsigned int d)
{
while(--d);
}
#define BEE_ON BEE=1 //宏定义 蜂鸣器开
#define BEE_OFF BEE=0 //宏定义 蜂鸣器关
/*******************************************************
函数名:findColumn()
功能:根据按键接口所读入的值,判断按键的列值
输入参数:
value:从按键接口读入的值
输出参数: 无
返回值:-1:没有任何列被按下 其它:按键的列值
*******************************************************/
char findColumn(char value)
{
char i;
value=value>>4;
for(i=0;i<4;i++)
{
if(0==((value>>i)&0x01))
return i;
}
return -1;
}
/*******************************************************
函数名:scanKey()
功能:扫描键盘,如果键盘有按键按下,则把按键的
行值和列值保存在全局变量rowValue和columnValue
输入参数:无
输出参数: 当返回值为0时,输出参数为全局变量rowValue和columnValue
返回值:0有按键按下 -1没有按键按下
*******************************************************/
char scanKey()
{
char scanRow;
for(scanRow=0;scanRow<4;scanRow++)
{
KEY_PORT = ~(1<<scanRow);//扫描第0行
if((KEY_PORT&0xf0) != 0xf0)
{
delay(1250);//延时去抖
if((KEY_PORT&0xf0) != 0xf0)//真的有按下
{
BEE_ON;
columnValue=KEY_PORT&0xf0;
while(1)
{
if((KEY_PORT&0xf0) == 0xf0)//按键凝似台起
{
delay(1250);
if((KEY_PORT&0xf0) == 0xf0)//按键确定台起
{
BEE_OFF;
if(-1!=findColumn(columnValue)){
rowValue= scanRow;
columnValue=findColumn(columnValue);
return 0;
}
}
}
}
}
}
}
return -1;
}
void main()
{
BEE_OFF;
ledDsplay(-1,-1);//初始化,数码管灭
while(1)
{
if(0==scanKey())//如果有按键被按下
ledDsplay(rowValue,columnValue);
}
}
用定时器0的中断,进行键盘扫描,判断键位
//实例78:矩阵式键盘按键音
#include<reg52.h> //包含51单片机寄存器定义的头文件
sbit Beep=P3^0; //将sound位定义为P3.0
unsigned char Pre_KeyNO = 16,KeyNO = 16; //1 0000 为了后面的扫描按键
//定义数码管0到F
unsigned char code DSY_CODE[]=
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x00
};
/**************************************************************
函数功能:蜂鸣器发声延时约120ms
**************************************************************/
void delay_sound(void)
{
unsigned char i;
for(i=0;i<250;i++)
;
}
/**************************************************************
函数功能:软件延时子程序约20ms
**************************************************************/
void delay20ms(void)
{
unsigned char i,j;
for(i=0;i<100;i++)
for(j=0;j<60;j++)
;
}
void Beep2(void)
{
unsigned char i;
for(i=0;i<200;i++) //让P3.7引脚电平不断取反输出音频
{
Beep=0;
delay_sound();
Beep=1;
delay_sound();
}
}
/**************************************************************
函数功能:主函数
**************************************************************/
void main(void)
{
EA=1; //开总中断
ET0=1; //定时器T0中断允许
TMOD=0x01; //使用定时器T0的模式1
TH0=(65536-500)/256; //定时器T0的高8位赋初值
TL0=(65536-500)%256; //定时器T0的高8位赋初值
TR0=1; //启动定时器T0
while(1) //无限循环,等待键盘按下
;
}
/**************************************************************
函数功能:定时器0的中断服务子程序,进行键盘扫描,判断键位
**************************************************************/
void time0_interserve(void) interrupt 1 using 1 //定时器T0的中断编号为1,使用第一组寄存器
{
unsigned char i;
unsigned char Tmp;
TR0=0; //关闭定时器T0
P1=0xf0; //所有行线置为低电平“0”,所有列线置为高电平“1”
if((P1&0xf0)!=0xf0) //列线中有一位为低电平“0”,说明有键按下
delay20ms(); //延时一段时间、软件消抖
if((P1&0xf0)!=0xf0) //确实有键按下
{
Tmp = P1 ^ 0x0f;
switch(Tmp) //列
{
case 1: KeyNO = 0; break;
case 2: KeyNO = 1; break;
case 4: KeyNO = 2; break;
case 8: KeyNO = 3; break;
default: KeyNO = 16;
}
P1 = 0xf0;
delay20ms();
Tmp = P1 ^ 0xf0;
// Tmp = P1 >> 4 ^ 0x0f;
switch(Tmp) //行
{
case 1: KeyNO += 0; break;
case 2: KeyNO += 4; break;
case 4: KeyNO += 8; break;
case 8: KeyNO += 12;
}
if(Pre_KeyNO != KeyNO) //当KeyNO不等于16时,有按键被按下,进行数码管点亮
{
P0 = ~DSY_CODE[KeyNO]; //数码管是共阴极的
Beep2();
Pre_KeyNO = KeyNO;
}
}
TR0=1; //关定时器T0
TH0=(65536-500)/256; //定时器T0的高8位赋初值
TL0=(65536-500)%256; //定时器T0的高8位赋初值
}
代码与仿真文件 https://download.csdn.net/download/m0_48459378/23977439