单片机基础知识 07

一. 键盘检测

键盘分为编码键盘非编码键盘

编码键盘 :键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或者键值,如计算机键盘。

非编码键盘:靠软件编程来识别。

在单片机组成的各种系统中,用的较多的是非编码键盘。编码键盘又分为独立键盘行列式键盘矩阵式键盘)。

1. 独立键盘

单片机系统中常见的几种按键:弹性按键,贴片按键,自锁按键

编写单片机的键盘检测程序时,一般在检测按下时加入去抖延时,检测松手时就不用加了。
在这里插入图片描述
案例1:用数码管的前两位显示一个十进制数,变化范围为00-59,开始时显示00,每按下S2键1次,数值加1;每按下S3键1次,数值减1;每按下S4键1次数值归零;按下S5键1次,利用定时器功能使数值开始自动每秒加1,再次按下S5键,数值停止自动加1,保持显示原数。

#include <reg52.h>
#define  uchar unsigned char
#define uint unsigned int

sbit key1 = P3^4;
sbit key2 = P3^5;
sbit key3 = P3^6;
sbit key4 = P3^7;
sbit dula = P2^6;  //U1锁存器的锁存端
sbit wela = P2^7;  //U2锁存器的锁存端

uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

void delayms(uint);
uchar numt0, num;

/***数码管显示函数***/
void display(uchar numdis)
{
	uchar shi,ge;
	shi = numdis/10;
	he = numdis%10;
	
	dula = 1;
	P0 = table[shi]; //送十位段选数据
	dula = 0;
	P0 = 0xff;/*送位选数据前关闭所有显示,
		防止打开位选锁存时原来段选数据通过位选锁存器造成混乱*/
	wela = 1;
	P0 = 0xfe; //送位选数据
	wela = 0;
	delayms(5); 

	dula = 1;
	P0 = table[ge]; //送个位段选数据
	dula = 0;
	P0 = 0xff;
	wela = 1;
	P0 = 0xfd;
	wela = 0;
	delayms(5);	
}

/***延时函数***/
void delayms(uint xms)
{
	uint i ,j;
	for(i= xms; i>0 ; i--)
	{
		for(j =110;i>0;j--);
	}
}

/***初始化函数***/
void init()
{
	TMOD = 0x01; //设置定时器0为工作方式1
	TH0 = (65536-45872)/256; //装初值50ms一次中断
	TL0 = (65536-45872)%256; 
	EA = 1; //开总中断
	ET0 = 1; //开定时器0中断
} 

/***键盘扫描函数***/
void keyscan()
{
	if(0 == key1)
	{
		delayms(10);
		if(0 == key1)
		{
			num++;
			if(60 == num)
			{
				num = 0
			}
			while(!key1); //等待按键释放
		}
	}

	if(0 == key2)
	{
		delayms(10);
		if(0 == key2)
		{
			if(0 == num)
			{
				num = 60
			}
			num--;
			while(!key2); 
		}
	}

	if(0 == key3)
	{
		delayms(10);
		if(0 == key3)
		{
			num = 0;
			while(!key3);
		}
	}

	if(0 == key4)
	{
		delayms(10);
		if(0 == key4)
		{
			while(!key4); 
			TR0 = ~TR0;  //启动或者停止定时器0
		}
	}
}

void main()
{
	init();
	while(1)
	{
		keyscan();
		display(num);
	}
}

/***定时器中断函数***/
void T0_time() interrupt 1
{
	TH0 = (65536-45872)/256; //重装初值
	TL0 = (65536-45872)%256; 
	numt0++;
	if(20 == numt0)
	{
		numt0 = 0;
		num++; 
		if(60 == num)
		{
			num = 0;
		}	
	}
}

2. 矩阵键盘

独立键盘有一端固定为低电平,单片机写程序检测时比较方便。而矩阵键盘两端都与单片机I/O口相连,因此在检测时需人为通过单片机I/O口送出低电平。

检测时,先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们可以确定当前被按下的键是哪一行哪一列的。用同样的方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有按键被按下时便可判断出按下的键是哪一个键。

案例2:实验板上电时,数码管不显示,顺序按下矩阵键盘后,在数码管上依次显示0-F,6个数码管同时静态显示即可。
其中,矩阵键盘的4行分别与单片机的P3.0-P3.3相连,4列分别与P3.4-P3.7相连。

#include <reg52.h>
#define  uchar unsigned char
#define uint unsigned int

sbit dula = P2^6;  //U1锁存器的锁存端
sbit wela = P2^7;  //U2锁存器的锁存端

uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

/***延时函数***/
void delayms(uint xms)
{
	uint i ,j;
	for(i= xms; i>0 ; i--)
	{
		for(j =110;i>0;j--);
	}
}

/***数码管显示函数***/
void display(uchar num)
{
	P0 = table[num]; //显示函数只送段选数据
	dula = 1;
	dula = 0; 
}

/***矩阵键盘扫描函数***/
void matrixkeyscan()
{
	 uchar temp,key;

	//第一行
	 P3 = 0xfe;
	 temp = P3;
	 temp = temp & 0xf0;  //用于判断temp高4位是否有0
	 if(0xf0 != temp)  /*temp的高4位数据实际上就是矩阵键盘的
				 4个列线,若temp不等于0xf0,说明有键被按下*/
	 {
		delayms(10); //延时去抖
		temp = P3;
		temp = temp & 0xf0;
		if(0xf0 != temp)
		{
			temp =P3;
			switch(temp)
			{
				case 0xee:
					key = 0;
					break;
			    case 0xde:
			    	key = 1;
			    	break;
			    case 0xbe:
			    	key =2;
			    	break;
			    case 0x7e:
			    	key = 3;
			    	break;
			}
			while(temp!=0xf0) //等待按键释放
			{
				temp = P3;
				temp = temp & 0xf0;
			}
			display(key); //显示
		}
	 }
		
	 //第2行
	 P3 = 0xfd;
	 temp = P3;
	 temp = temp & 0xf0;
	 if(0xf0 != temp)
	 {
		delayms(10);
		temp = P3;
		temp = temp & 0xf0;
		if(0xf0 != temp)
		{
			temp =P3;
			switch(temp)
			{
				case 0xed:
					key = 4;
					break;
			    case 0xdd:
			    	key = 5;
			    	break;
			    case 0xbd:
			    	key =6;
			    	break;
			    case 0x7d:
			    	key = 7;
			    	break;
			}
			while(temp!=0xf0) //等待按键释放
			{
				temp = P3;
				temp = temp & 0xf0;
			}
			display(key); //显示
		}
	 }

	//第3行
	 P3 = 0xfb;
	 temp = P3;
	 temp = temp & 0xf0;
	 if(0xf0 != temp)
	 {
		delayms(10);
		temp = P3;
		temp = temp & 0xf0;
		if(0xf0 != temp)
		{
			temp =P3;
			switch(temp)
			{
				case 0xeb:
					key = 8;
					break;
			    case 0xdb:
			    	key = 9;
			    	break;
			    case 0xbb:
			    	key = 10;
			    	break;
			    case 0x7b:
			    	key = 11;
			    	break;
			}
			while(temp!=0xf0) //等待按键释放
			{
				temp = P3;
				temp = temp & 0xf0;
			}
			display(key); //显示
		}
	 }

	//第4行
	P3 = 0xf7;
	 temp = P3;
	 temp = temp & 0xf0;
	 if(0xf0 != temp)
	 {
		delayms(10);
		temp = P3;
		temp = temp & 0xf0;
		if(0xf0 != temp)
		{
			temp =P3;
			switch(temp)
			{
				case 0xe7:
					key = 12;
					break;
			    case 0xd7:
			    	key = 13;
			    	break;
			    case 0xb7:
			    	key =14;
			    	break;
			    case 0x77:
			    	key = 15;
			    	break;
			}
			while(temp!=0xf0) //等待按键释放
			{
				temp = P3;
				temp = temp & 0xf0;
			}
			display(key); //显示
		}
	 }	
}

void main()
{
	P0 = 0; //关闭所有数码管段选
	dula = 1;
	dula = 0;
	P0 = 0xc0; //位选中所有数码管
	wela = 1;
	wela = 0;

	while(1)
	{
      matrixkeyscan(); //不停调用键盘扫描程序
	}
}
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值