矩阵键盘——按下矩阵按键,数码管显示出位置对应的字符(0123 4567 89Ab CdEF)

矩阵键盘——按下矩阵按键,数码管显示出位置对应的字符(0123 4567 89Ab CdEF)

2021-01-25,51单片机学习笔记

4*4矩阵键盘

在这里插入图片描述

代码:
/*按下矩阵按键,数码管显示出位置对应的字符(0123 4567 89Ab CdEF)*/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula=P2^6;//数码管段显
sbit wela=P2^7;//数码管位显
uchar disnum,temp,key,num;
//段显编码的下标(返回值),临时变量,键值,段显编码的下标(调用值)
uchar code table_du[]={//共阴极8段数码管段显编码
0x3f,0x06,0x5b,0x4f,0x66,0x6d,  //012345
0x7d,0x07,0x7f,0x6f,0x77,0x7c,  //6789Ab
0x39,0x5e,0x79,0x71,0x00};      //CdEF无

void delay(uchar);//声明 延时函数
uchar keyscan();//声明 矩阵键盘扫描函数
void main()
{	
	disnum=16;//没有按键按下时,默认段显为“无”(不显示)
	
	wela=1;//位显允许写入
	P0=0xfe;//1111 1110,仅点亮第一位数码管
	wela=0;//位显锁存
	
	while(1)
	{	
		P0=table_du[keyscan()];//预写入段显
		/**************************************************************
		其实此语句可由以下段落的语句替代:
		keyscan();            //获取 段显编码的下标(返回值)
		num=disnum;           //段显编码的下标(调用值)
		P0=table_du[num];     //预写入段显
		**************************************************************/
		dula=1;//段显允许写入
		dula=0;//段显锁存
	}
}

/*【我们记 由左到右数第x行,由上到下数第y列 的按键为 key[x,y]】*/
uchar keyscan()//矩阵键盘扫描函数;检测 矩阵按键 中被按下的 按键 的位置信息
{	
	P3=0xf0;//1111 0000,初始化,令高四位(列)=1,低四位(行)=0
	/***********************************************************
	如果 某列中有按键被按下,行列接通而短路,
	那么 对应列的 P3口高四位 就会 强制 变为0,比如:
	若 key[2,3](即S12)被按下,则 P3=1011 0000
	************************************************************/
	temp=P3;//取此时P3的值(此时的temp仅包含了列的位置信息)
	temp=temp&0xf0;//按位与,取高四位(列),低四位(行)置0
	if(temp!=0xf0)//如果高四位不全为1,说明为P3口高四位为0的列有按键被按下
	{
		delay(5);//等10ms,消除 按前 抖动
		if(temp!=0xf0)//如果高四位真的不全为1,说明该列真的有按键被按下
		{
			temp=P3;//取此时P3的值(此时的temp仅包含了列的位置信息)
			temp=temp|0x0f;//按位或,保留高四位(列)的值,低四位(行)置1
			P3=temp;//P3口输出这个数(对应的高低电平)
			/*由于P3高四位中对应该按键的列为0,此时按键还未松开,
			行列接通而短路,那么其对应行的P3口低四位就会 强制 为0*/
			key=P3;//记录此时P3的值(此处key的值已经包含行列的全部位置信息)
			switch(key)
			{//不同的key代表着不同的按键被按下
			//那么,就可以根据key来确定要输出的字符的段显编码的下标
				case 0xee:disnum=0;//key[1,1](S6)	1110 1110
						break;						/*列 行*/
				case 0xde:disnum=1;//key[1,2](S7)	1101 1110
						break;
				case 0xbe:disnum=2;//key[1,3](S8)	1011 1110
						break;
				case 0x7e:disnum=3;//key[1,4](S9)	0111 1110
						break;
				
				case 0xed:disnum=4;//key[2,1](S10) 	1110 1101
						break;
				case 0xdd:disnum=5;//key[2,2](S11)	1101 1101
						break;
				case 0xbd:disnum=6;//key[2,3](S12)	1011 1101
						break;
				case 0x7d:disnum=7;//key[2,4](S13)	0111 1101
						break;
				
				case 0xeb:disnum=8;//key[3,1](S14)	1110 1011
						break;
				case 0xdb:disnum=9;//key[3,2](S15)	1101 1011
						break;
				case 0xbb:disnum=10;//key[3,3](S16)	1011 1011
						break;
				case 0x7b:disnum=11;//key[3,4](S17)	0111 1011
						break;
						
				case 0xe7:disnum=12;//key[4,1](S18)	1110 0111
						break;
				case 0xd7:disnum=13;//key[4,2](S19)	1101 0111
						break;
				case 0xb7:disnum=14;//key[4,3](S20)	1011 0111
						break;
				case 0x77:disnum=15;//key[4,4](S21)	0111 0111
						break;
			}
		}
	}
return disnum;//返回要输出的字符的段显编码的下标
}

void delay(uchar x)//延时函数
{
	uchar a,b;
	for(a=x;a>0;a--)
		for(b=200;b>0;b--);
}


写在最后:
本文仅为个人学习笔记,纰漏之处,欢迎斧正!

  • 6
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,我来为你编写相应的汇编程序。首先,需要了解一下单片机中的中断处理方式和七段数码管的显示方法,这里简单介绍一下: 单片机中的中断处理方式一般是通过设置中断向量表和中断标志位来实现。当中断标志位被置位时,CPU 会跳转到对应的中断处理函数中执行相应的操作。在中断处理函数中,需要注意保存现场和恢复现场,避免中断处理过程中对其他程序的干扰。 七段数码管的显示方法可以参考上一个问题的回答。 下面是相应的汇编代码,可以满足题目要求: ```assembly ; 定义端口地址,具体地址根据硬件设计而定 PORT equ 0x80 ; 定义数字对应的七段码表 CODE_TABLE db 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 ; 定义中断向量表 ORG 0x03 INT0_VECTOR: jmp INT0_ISR ; 定义中断处理函数 INT0_ISR: push ax ; 保存现场 push bx push cx push dx mov si, offset CODE_TABLE + 12 ; 设置起始位置为 C,即显示 CDEF01 mov cx, 6 ; 设置循环次数,显示 6 个数字 loop: mov al, [si] ; 从码表中取对应的七段码 out PORT, al ; 将七段码输到端口,控制数码管显示 inc si ; 指向下一个数字的七段码 cmp si, offset CODE_TABLE + 18 ; 判断是否显示完 6 个数字 jne loop ; 如果没有,继续循环 pop dx ; 恢复现场 pop cx pop bx pop ax reti ; 返回中断处理结束 ; 主程序入口 main: mov cx, 6 ; 设置循环次数,显示 6 个数字 mov si, offset CODE_TABLE + 6 ; 设置起始位置为 6,即显示数字 6 loop: mov al, [si] ; 从码表中取对应的七段码 out PORT, al ; 将七段码输到端口,控制数码管显示 inc si ; 指向下一个数字的七段码 cmp si, offset CODE_TABLE + 12 ; 判断是否显示完 6 个数字 jne loop ; 如果没有,继续循环 ; 中断标志位被置位时,跳转到 INT0_VECTOR 中断向量表中的地址 ; 如果没有中断,程序一直循环显示 6789AB sjmp $ ; 无限循环,不断显示 6789AB jmp loop ``` 以上代码中,通过设置中断向量表和中断标志位来实现对 INT0 中断的响应。当 INT0 中断产生时,CPU 会跳转到 INT0_ISR 中断处理函数中执行相应的操作,即循环显示 CDEF01。在中断处理函数中,需要注意保存现场和恢复现场,避免中断处理过程中对其他程序的干扰。在主程序中,通过循环显示 6789AB 的方式,当没有中断时,程序会一直执行该循环。程序的最后通过 sjmp $ 和 jmp loop 实现无限循环,不断显示 6789AB 或 CDEF01。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值