蓝桥杯51单片机设计

发布于:2025-07-07 ⋅ 阅读:(18) ⋅ 点赞:(0)

#矩阵键盘#

IO线与关系

思考,俩个引脚:一个输入高电平一个输入低电平,当俩者接到一起他们的点评情况是什么?

单片机IO口内部等效图

②矩阵键盘原理

判断按键按下的原理:如果未按下时俩个引脚的电平不一样(一高一低),则按下时高电平的引脚为低电平,我们只需要检测高电平引脚是否变为低电平就可以判断按键是否被按下

(总结:发生变化的总是高电平的引脚)

③矩阵键盘逐行扫描法

先让第一行按键的公共引脚为低电平,第二行到第四行公共引脚为高电平,先去检测第一到第四列公共引脚的电平(引脚由于接了上拉电阻,不输出就是高电平),检测到哪个列引脚为低电平,则确定哪个按键被按下,然后检测第二行,第三行,第四行

特点:原理简单,但代码冗长

④行列扫描法(坐标法)

先确定列数n

再确定行数

对应的键盘就是第一行:n

第二行:n+4

第三行:n+8

第四行:n+12

先让按键的列公共引脚电平都为高电平行公共引脚都为低电平,去判断哪个列引脚为低电平可以确定哪一列被按下,记下列号

再让列公共引脚为低电平,行公共引脚为高电平,去判断哪一行被按下,按键值就是

第一行:列号

第二行:列号+4

第三行:列号+8

第四行:列号+12

代码编写

#include "key.h"

uchar key_up=1;
uchar key_scan()
{
	uchar key;
	P44=P42=P35=P34=0;
	P30=P31=P32=P33=1;
	if(key_up==1&&(P30==0||P31==0||P32==0||P33==0))
	{
		key_up=0;
		if(P30==0)key=7;
		else if(P31==0)key=6;
		else if(P32==0)key=5;
		else if(P33==0)key=4;
		 	P44=P42=P35=P34=1;
	    P30=P31=P32=P33=0;
      if(P44==0||P42==0||P35==0||P34==0)
			{
				if(P44==0)key=key;
				else if(P42==0)key=key+4;
				else if(P35==0)key=key+8;
				else if(P34==0)key=key+12;
			}
			return key;
	}
	else if(P30==1&&P31==1&&P32==1&&P33==1)
	{
		key_up=1;
	}
	return 0;
}

⑤比大小代码设计

#include <reg52.h>
#include <intrins.h>
//数码管12显示数字1
//数码管3熄灭
//数码管45显示数字2
//数码管67熄灭
//用0~9输入数字1和2,再按结算即按键S17
//数码管8显示比较结果
//若是num1>num2,显示1,反之为0
//
//初定义
sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sfr P4 = 0xC0;
sbit P30=P3^0;
sbit P31=P3^1;
sbit P32=P3^2;
sbit P33=P3^3;
sbit P44=P4^4;
sbit P34=P3^4;
sbit P35=P3^5;
sbit P42=P4^2;
//后定义
code unsigned int smg_num[]={0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0xff , 0xbf , 0x7f };
unsigned int count;
unsigned char key_up=1;//按键松手标志位
unsigned char buf[]={10,10,10,10};//初始状态为熄灭
unsigned char index;//下标
unsigned char sign=10;//比大小之前,为熄灭状态
//hc573定义
void hc573(unsigned int channel)
{
	switch(channel)
	{
		case 4:P2=P2&0x1f|0x80;break;
		case 5:P2=P2&0x1f|0xa0;break;
		case 6:P2=P2&0x1f|0xc0;break;
		case 7:P2=P2&0x1f|0xe0;break;
	}
	P2=P2&0x1f;
}
//初始化
void init_sys()
{
	P0=0xff;
	hc573(4);
	P0=0x00;
	hc573(5);
}
//定时器初始化
void init_timer0()
{
	TMOD=0X01;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	EA=1;
	ET0=1;
	TR0=1;
}
//定时器中断服务函数
void timer0() interrupt 1
{
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	count++;
	if(count==20)//1s
	{
		count =0;
	}
}
//延时函数
void delay_ms(unsigned int xms)
{
	for( ;xms>0;xms--)
	{
		unsigned char data i, j;

		i = 12;
		j = 169;
		do
		{
			while (--j);
		} while (--i);
	}
}


//数码管显示与消隐
void smg(unsigned int pos,unsigned int seg,unsigned char dot)
{
	P0=0xff;
	hc573(7);
	P0= 0x01<<(pos-1);
	hc573(6);
	
	if(dot==0)
	{
	  P0=smg_num[seg];
	}
	else
	{
		P0=smg_num[seg]&0x7f;
	}
	hc573(7);
	delay_ms(1);
}
//数码管显示
void display()
{
	smg(1,buf[0],0);
	smg(2,buf[1],0);
	smg(3,10,0);
	smg(4,buf[2],0);
	smg(5,buf[3],0);
	smg(6,10,0);
	smg(7,10,0);
	smg(8,sign,0);
}
unsigned char key_scan()
{
	unsigned char key;
	P30=P31=P32=P33=0;//因为有P30和P31,不可以使用dwbug
	P44=P34=P35=P42=1;
	if(key_up==1&&(P44==0||P42==0||P35==0||P34==0))
	{
		key_up=0;
		delay_ms(20);
		if(P44==0) key=1;//第一列
		else if(P42==0) key=2;//2
		else if(P35==0) key=3;//3
		else if(P34==0) key=4;//4
		//判断行
		P30=P31=P32=P33=1;
	  P44=P34=P35=P42=0;
		if(P30==0||P31==0||P32==0||P33==0)
		{
			if(P30==0) key=key;//1
			else if(P31==0) key=key+4;//2
			else if(P32==0) key=key+8;//3
			else if(P33==0) key=key+12;//4
		}
		return key;
	}
	else if(P44==1&&P42==1&&P35==1&&P34==1)
		key_up=1;
	return 0;
}
void key_pro()
{
	unsigned char key;
	key=key_scan();
	switch(key)
	{
		case 1:buf[index]=1;if(++index==5) index=4;break;//数组第一个元素赋值1,每一次按下,index++,边界限制
		case 2:buf[index]=2;if(++index==5) index=4;break;
		case 3:buf[index]=3;if(++index==5) index=4;break;
		case 4:buf[index]=4;if(++index==5) index=4;break;
		case 5:buf[index]=5;if(++index==5) index=4;break;
		case 6:buf[index]=6;if(++index==5) index=4;break;
		case 7:buf[index]=7;if(++index==5) index=4;break;
		case 8:buf[index]=8;if(++index==5) index=4;break;
		case 9:buf[index]=9;if(++index==5) index=4;break;
		case 10:buf[index]=0;if(++index==5) index=4;break;
    case 11:index=0;buf[0]=10;buf[1]=10;buf[2]=10;buf[3]=10;sign=10;break;//清除按键
		case 12:
			if(index==4)//数字输入完毕
		{
			if(buf[0]*10+buf[1]>=(buf[2]*10)+buf[3])
				sign=1;
			else
			{
				sign=0;
			}
		}
		break;
	}
}
//主函数
void main()
{
	init_sys();
	init_timer0();
	key_scan();
	while(1)
	{
	 
		key_pro();
		display();
		
	}
}

⑥方块矩阵键盘

矩阵按键前两行时P30和P31引脚,为串口通行引脚,影响debug功能

                                                       ⬇

用到四个按键的时候,用S5,S4,S8,S9(左下)——未用到P30和P31

//矩阵键盘
unsigned char key_scan()
{
	unsigned char key;
	//判断列
	P32=P33=0;//因为有P30和P31,不可以使用debug
	P44=P42=1;
	if(key_up==1&&(P44==0||P42==0))
	{
		key_up=0;
		delay_ms(20);
		if(P44==0) key=1;//第一列
		else if(P42==0) key=2;//2
		//判断行
		P30=P31=P32=P33=1;
	  P44=P34=P35=P42=0;
		if(P32==0||P33==0)
		{
			
		if(P32==0) key=key;//1
			else if(P33==0) key=key+2;//2
		}
		return key;
	}
	else if(P44==1&&P42==1)
		key_up=1;
	return 0;
}

void key_pro()
{
	unsigned char key;
	key=key_scan();//存储按键值
	switch(key)
	{
		case 1: num=1;break;
		case 2: num=2;break;
		case 3: num=3;break;
		case 4: num=4;break;
	}
}


网站公告

今日签到

点亮在社区的每一天
去签到