4X4矩阵键盘扫描程序
实验07:4X4键盘阵列扫描输入.pdf
键盘阵列扫描输入一、实验目的1. 进一步学习并掌握Quartus II设计的方法及步骤;2. 熟悉VHDL语言电路设计方法;3. 熟悉EACF型FPGA开发板,参见6.1节;4. 学习并掌握利用VHDL描述并设计电路的方法及步骤;5. 学习并掌握键盘阵列的扫描输入的方法及实现过程。
二、实验原理键盘阵列是一个由4×4的按键开关组成的阵列,可实现16种状态的输入。
4×4按键阵列的硬件连接原理如下图所示。
4X4键盘阵列其中VCC3.3为3.3V的正电源;BUTTON为4×4共16个按键,R为电阻。
而K_H_1、K_H_2、K_H_3、K_H_4为4×4按键阵列连接到FPGA通用IO引脚的行信号;K_V_1、K_V_2、K_V_3、K_V_4为4×4按键阵列连接到FPGA通用IO引脚的列信号,如下图所示。
键盘阵列与FPGA的连接另外,连接到FPGA的行列信号圴为3.3V的LVTTL电平标准:即电压小于0.8V为低电平,高于2.0V为高电平。
通过上述4×4按键阵列的硬件连接原理图可看出,行和列信号都通过10K的电阻上拉到3.3V的电源,也就是说如果FPGA通过对应的IO引脚来读取4×4按键阵列的行和列信号,得到的全部为高电平“1”,即使按键按下时,读到的依然是高电平“1”。
那么如何在FPGA中判断4×4按键阵列中的哪个键按下呢?当然我们要实现按键输入的功能,就不能全部读取行和列的信号。
而应通过不断地输出扫描行(或列),再通过读取列(或行)的信号来判断哪个按键按下。
即:通过对4×4键盘阵列的4个行(或列)控制信号循环输出”1110、1101、1011、0111”,来驱动键盘阵列,紧接着读取相应的4个列(或行)信号。
通过读取的数据或状态来判断16个按键中哪个键被按下,并对其状态做编码输出。
此电路不停的工作,以便实时准确地获取键盘的输入状态,以供其它电路使用,从而实现了键盘阵列的扫描输入。
4×4键盘扫描程序开启原理及实例(精心整理)
4×4键盘扫描程序开启原理及实例(精心整理)单片机4*4键盘扫描程序时如何开启的?按照行顺序,一行一行的开启,如下图:4*4共16键,假设P0.0-P0.3为H0-H3,P0.4-P0.7为L0-L3(列) L0 L1 L2 L3(行) H0 0 1 2 3H1 4 5 6 7H2 8 9 A BH3 C D E F首先让H0 = 0,然后依次检测L0-L3,看那个键按下了,则对应的L0-L3为0,这样第一行检测结束。
比如扫描H0行时第一个键按下了,则L0=0,获得的P0=0xee,你也可以返回一个值,比如就是0,来代表第一个键(0)被按下,这样依次检测就扫描满16个键就行了。
4*4键盘扫描程序#include //包含头文件#define uchar unsigned char#define uint unsigned intunsigned char const dofly[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f, 0x77,0x7c,0x39,0x5e,0x79,0x71};//0-Fuchar keyscan(void);void delay(uint i);void main(){uchar key;P2=0x00;//1数码管亮按相应的按键,会显示按键上的字符while(1){key=keyscan();//调用键盘扫描,switch(key){case 0x7e:P0=dofly[0];break;//0 按下相应的键显示相对应的码值case 0x7d:P0=dofly[1];break;//1case 0x7b:P0=dofly[2];break;//2case 0x77:P0=dofly[3];break;//3case 0xbe:P0=dofly[4];break;//4case 0xbd:P0=dofly[5];break;//5case 0xbb:P0=dofly[6];break;//6case 0xb7:P0=dofly[7];break;//7case 0xde:P0=dofly[8];break;//8case 0xdd:P0=dofly[9];break;//9case 0xdb:P0=dofly[10];break;//acase 0xd7:P0=dofly[11];break;//bcase 0xee:P0=dofly[12];break;//ccase 0xed:P0=dofly[13];break;//dcase 0xeb:P0=dofly[14];break;//ecase 0xe7:P0=dofly[15];break;//f}}}uchar keyscan(void)//键盘扫描函数,使用行列反转扫描法{uchar cord_h,cord_l;//行列值P3=0x0f; //行线输出全为0cord_h=P3&0x0f; //读入列线值if(cord_h!=0x0f) //先检测有无按键按下{delay(100); //去抖if(cord_h!=0x0f){cord_h=P3&0x0f; //读入列线值P3=cord_h|0xf0; //输出当前列线值cord_l=P3&0xf0; //读入行线值return(cord_h+cord_l);//键盘最后组合码值}}return(0xff); //返回该值}void delay(uint i)//延时函数{while(i--);}以下为详细解释:假设按下的是S1键进行如下检测(4*4键盘)先在P3口输出p3 00001111低四位行会有变化cord_h =00001111&00001110 =00001110if !=00001111延时0.1uscord_h=00001110&00001111=00001110if !=00001111P3再输出11111110P3 =00001110|11110000=11111110输出高四位cord_l=P3&0xf0 //此时P3口就是输入值01111110 而不是上面的11111110cord_l=01111110&11110000=01110000cord_h+cord_l=00001110+01110000=01111110=0x7e //此编码即为S1的编码#include //包含头文件#define uchar unsigned char#define uint unsigned intunsigned char const table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f, 0x77,0x7c,0x39,0x5e,0x79,0x71};//0-Fuchar keyscan(void);void delay(uint i);void main(){uchar key;P2=0x00;//1数码管亮按相应的按键,会显示按键上的字符while(1){key=keyscan();//调用键盘扫描,switch(key){case 0x7e:P0=table[0];break;//0 按下相应的键显示相对应的码值case 0x7d:P0=table[1];break;//1case 0x7b:P0=table[2];break;//2case 0x77:P0=table[3];break;//3case 0xbe:P0=table[4];break;//4case 0xbd:P0=table[5];break;//5case 0xbb:P0=table[6];break;//6case 0xb7:P0=table[7];break;//7case 0xde:P0=table[8];break;//8case 0xdd:P0=table[9];break;//9case 0xdb:P0=table[10];break;//acase 0xd7:P0=table[11];break;//bcase 0xee:P0=table[12];break;//ccase 0xed:P0=table[13];break;//dcase 0xeb:P0=table[14];break;//ecase 0xe7:P0=table[15];break;//f}}}uchar keyscan(void)//键盘扫描函数,使用行列反转扫描法{ uchar cord_h,cord_l;//行列值P3=0x0f; //行线输出全为0cord_h=P3&0x0f; //读入列线值if(cord_h!=0x0f) //先检测有无按键按下{delay(100); //去抖cord_h=P3&0x0f; //读入列线值if(cord_h!=0x0f){P3=cord_h|0xf0; //输出当前列线值cord_l=P3&0xf0; //读入行线值return(cord_h+cord_l);//键盘最后组合码值}}return(0xff); //返回该值}void delay(uint i)//延时函数{while(i--);}在P3口做的键盘你的去抖检测没有做好通过电平输入来引发中断,必须是由P3.2或P3.3引脚输入,这样才能触发中断。
实验四4×4键盘输入
实验四: 4 × 4键盘输入实验一、实验目的:1.学习非编码键盘的工作原理和键盘的扫描方式。
2.学习键盘的去抖方法和键盘应用程序的设计。
二、实验原理:键盘是单片机应用系统接受用户命令的重要方式。
单片机应用系统一般采用非编码键4*4矩阵盘,需要由软件根据键扫描得到的信息产生键值编码,以识别不同的键。
本板采用键盘,行信号分别为P1.0-P1.3 ,列信号分别为P1.4-P1.7 。
具体电路连接见下图对于键的识别一般采用逐行(列)扫描查询法,判断键盘有无键按下,由单片机I/O口向键盘送全扫描字,然后读入列线状态来判断。
程序及流程图:ORG 0000HAJMP MAINORG 0000HAJMP MAINORG 0030HMAIN:MOV P2,#0F7HMOV P1,#0F0HMOV R7,#100DJNZ R7,$MOV A,P1ANL A,#0F0HXRL A,#0F0HJZ MAINLCALL D10MSMOV A,#00HMOV R0,AMOV R1,AMOV R2,#0FEH SKEY0:MOV A,R2MOVP1,AMOVR7,#10DJNZ R7,$MOVA,P1ANLA,#0F0HXRLA,#0F0HJNZ LKEYINC R0MOVA,R2RL AMOVR2,AMOVA,R0CJNE A,#04H,SKEY0AJMP MAIN LKEY:JNB ACC,4,NEXT1MOVA,#00HMOVR1,AAJMP DKEYNEXT1:JNB ACC.5,NEXT2MOVA,#01HMOVR1,AAJMP DKEYNEXT2:JNB ACC.6,NEXT3MOVA,#02HMOVR1,AAJMP DKEYNEXT3:JNB ACC.7,MAINMOVA,#03HMOVR1,AAJMP DKEY DKEY:MOV A,R0MOVB,#04HMULABADDA,R1AJMP SQRSQR:MOVDPTR,#TABMOVC A,@A+DPTRMOVP0,AAJMP MAINTAB:DB0C0H,0F9H,0A4H,0B0H,99H, 92H, 82H, 0F8H DB 80H, 90H, 88H, 83H, 0C6H,0A1H,86H, 8EH D10MS:MOV R6,#10L1:MOV R5,#248DJNZ R5,$DJNZ R6,L1RETEND流程图:结束三、思考题:总结 FPGA是如何识别按键的?与单片机读取键值有何不同?答:FPGA的所有 I/O 控制块允许每个 I/O 引脚单独配置为输入口 , 不过这种配置是系统自动完成的。
4X4矩阵式键盘输入程序
4*4键盘程序readkeyboard:begin: acall key_onjnz delayajmp readkeyboarddelay:acall delay10msacall key_onjnz key_numajmp beginkey_num:acall key_panl a,#0FFhjz beginacall key_ccodepush akey_off:acall key_onjnz key_offpop aretkey_on: mov a,#00horl a,#0fhmov p1,amov a,p1orl a,#0f0hcpl aretkey_p: mov r7,#0efhl_loop:mov a,r7mov p1,amov a,p1orl a,#0f0hmov r6,acpl ajz nextajmp key_cnext: mov a,r7jnb acc.7,errorrl amov r7,aajmp l_looperror:mov a,#00hretkey_c:mov r2,#00hmov r3,#00hmov a,r6mov r5,#04hagain1:jnb acc.0,out1rr ainc r2djnz r5, again1out1: inc r2mov a,r7mov r5,#04hagain2:jnb acc.4,out2rr ainc r3djnz r5,again2out2: inc r3mov a, r2swap aadd a,r3retkey_ccode:push aswap aanl a,#0fhdec arl a ;行号乘4rl amov r7,apop aanl a,#0fhdec aadd a,r7retdelay10ms:anl tmod,#0f0horl tmod,#01hmov th0,#0d8hmov tl0,#0f0hsetb tr0wait:jbc tf0,overajmp waitclr tr0over:ret单片机键盘设计(二)从电路或软件的角度应解决的问题软件消抖:如果按键较多,硬件消抖将无法胜任,常采用软件消抖。
4_4矩阵键盘扫描
//4*4矩阵式键盘扫描程序module keyscan(row, col, clk, key_buf);input [3:0] col; //列线定义input clk; //150MHZoutput [3:0] row; //行线定义output [7:0] key_buf; //键值输出口reg [3:0] row;reg [7:0] key_buf; //键值输出缓冲寄存器reg [7:0] key_buf1; //键值暂存器reg [3:0] count1;reg [14:0] count2;reg [3:0] state;reg [3:0] state_temp;reg sec, en;/*********************产生5MHZ方波****************/ always@(posedge clk )beginif(count1 == 4'd15)beginsec <= ~sec;count1 <= 4'd0;endelsecount1 <= count1+1'b1;endalways@(negedge sec)beginif(en)begincase(state)/******************** 准备进入行扫描状态*************/4'd0://KEY //开始扫描beginrow[3:0] <= 4'b0000; //行线全部置零state_temp = 4'd1;state = 4'd9; //5ms消抖end/*********************扫描第一行**********************/4'd1://KEYTEMPbeginif(col[3:0] == 4'b1111) //判断是否有键按下?state = 4'd0; //没有就重新扫描elsebeginrow[3:0] <= 4'b1110;state_temp = 4'd2;state = 4'd9; //如果有就延时去抖endend/********************检测第一行键值*******************/4'd2://ROW1begincase({row[3:0],col[3:0]}) //第一行判断8'b1110_1111: //无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd3; //进入第二行扫描end8'b1110_1110: //键值1beginkey_buf1 <= 8'b1111_1110; //键值放入key_buf1state = 4'd10; //等待弹起end8'b1110_1101: //键值2beginkey_buf1 <= 8'b1111_1101;state = 4'd10;end8'b1110_1011: //键值3beginkey_buf1 <= 8'b1111_1011;state = 4'd10;end8'b1110_0111: //键值4beginkey_buf1 <= 8'b1111_0111;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd3; //进入第二行扫描endendcaseend/*********************第二行扫描*********************/4'd3://ROW2TEMPbeginrow[3:0] <= 4'b1101;state_temp = 4'd4;state = 4'd9;end/***********************检测第二行键值***************/4'd4://ROW2begincase({row[3:0], col[3:0]})8'b1101_1111: //若无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd5; //进入第三行扫描end8'b1101_1110: //键值5beginkey_buf1 <= 8'b1110_1111;state = 4'd10; //等待弹起end8'b1101_1101: //键值6beginkey_buf1 <= 8'b1101_1111;state = 4'd10;end8'b1101_1011: //键值7beginkey_buf1 <= 8'b1011_1111;state = 4'd10;end8'b1101_0111: //键值8beginkey_buf1 <= 8'b0111_1111;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd5; //进入第三行扫描endendcaseend/**********************第三行扫描********************/4'd5://ROW3TEMPbeginrow[3:0] <= 4'b1011;state_temp = 4'd6;state = 4'd9;end/*********************检测第三行键值*****************/4'd6://ROW3begincase({row[3:0], col[3:0]})8'b1011_1111: //若无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd7; //进入第四行扫描end8'b1011_1110: //键值9beginkey_buf1 <= 8'b1111_1110;state = 4'd10; //等待弹起end8'b1011_1101: //键值10beginkey_buf1 <= 8'b1111_1100;state = 4'd10;end8'b1011_1011: //键值11beginkey_buf1 <= 8'b1111_1000;state = 4'd10;end8'b1011_0111: //键值12beginkey_buf1 <= 8'b1111_0000;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd7; //进入第四行扫描endendcaseend/********************第四行扫描**********************/4'd7://ROW4TEMPbeginrow[3:0] <= 4'b0111;state_temp = 4'd8;state = 4'd9;end/*********************检测第四行键值******************/ 4'd8://ROW4begincase({row[3:0], col[3:0]})8'b0111_1111: //若无键按下beginkey_buf1 <= 8'b1111_1111;state = 4'd0; //重新进入扫描end8'b0111_1110: //键值13beginkey_buf1 <= 8'b1110_0000;state = 4'd10; //等待弹起end8'b0111_1101: //键值14beginkey_buf1 <= 8'b1100_0000;state = 4'd10;end8'b0111_1011: //键值15beginkey_buf1 <= 8'b1000_0000;state = 4'd10;end8'b0111_0111: //键值16beginkey_buf1 <= 8'b0000_0000;state = 4'd10;enddefault:beginkey_buf1 <= 8'b1111_1111;state = 4'd0; //重新进入扫描endendcaseend/***********************去抖延时********************/ 4'd9://DELAYbeginif(count2 ==15'd25000)beginstate = state_temp;count2 <= 0;endelsecount2 <= count2+1'b1;end/************************等待弹起******************/ 4'd10://WAITbeginif(col[3:0] == 4'b1111)beginkey_buf <= key_buf1;state <= 4'd0;endelsestate = 4'd10;endendcaseend/*******************否则,变量初始化****************/ elsebeginstate = 4'd0;count2 <= 0;key_buf <= 8'b0000_0000;row[3:0] <= 4'b0000;en <= 1;endendendmodule附:程序配套的4*4矩阵键盘电路图其中:P2.3 ~P2.0对应row[3:0];P3.7 ~P3.4对应line[3:0]。
4X4扫描式矩阵键盘课程设计
4x4矩阵键盘识别设计班级:1221201专业:测控技术与仪器姓名:涂勇学号:2012 2012 0110指导老师:钟念兵东华理工大学2016年1月1日摘要随着21世纪的到来,电子信息行业将是人类社会的高科技行业之一,电子式设施现代化的基础,也是人类通往科技巅峰的直通路。
电子行业的发展从长远来看很重要,但最主要的还是科技问题。
矩阵式键盘提高效率进行按键操作管理有效方法,它可以提高系统准确性,有利于资源的节约,降低对操作者本身素质的要求。
是它能准时、实时、高效地显示按键信息,以提高工作效率和资源利用率。
矩阵式键盘乃是当今使用最为广泛的键盘模式,该系统以N个端口连接控制N*N 个按键,显示在LED数码管上。
单片机控制依据这是键盘显示系统,该系统可以对不同的按键进行实时显示,其核心是单片机和键盘矩阵电路部分,主要对按键与显示电路的关系、矩阵式技术及设备系统的硬件、软件等各个部分进行实现。
4*4矩阵式键盘采用STM32嵌入式微处理器为核心,主要由矩阵式键盘电路、硬件电路、显示电路等组成,软件选用C语言编程。
STM32将检测到的按键信号转换成数字量,显示于LED显示器上。
该系统灵活性强,易于操作,可靠性高,将会有更广阔的开发前景。
目录第一章:系统功能要求-------------------------------------------------------- 1.1 4*4 矩阵式键盘系统概述------------------------------------------------ 1.2 本设计任务和主要容--------------------------------------------------- 第二章:系统硬件电路的设计------------------------------------------------2.1 硬件系统主要思路和电路原理图- --------------------------------------2.2 硬件上键盘规划- --------------------------------------------------------- 第三章:系统程序的设计------------------------------------------------------3.1 程序的编写步骤-----------------------------------------------------------3.2 编写的源程序-------------------------------------------------------------- 第四章:心得体会---------------------------------------------------------------第一章:系统功能要求1.1 4*4 矩阵式键盘系统概述利用STM32对4*4矩阵键盘进行动态扫描,当有按键盘的键时,可将相应按键值(0~F)实时显示在数码管上。
矩阵键盘扫描汇编程序
4*4矩阵键盘扫描汇编程序(基于51单片机)// 程序名称:4-4keyscan.asm;// 程序用途:4*4矩阵键盘扫描检测;// 功能描述:扫描键盘,确定按键值。
程序不支持双键同时按下,;// 如果发生双键同时按下时,程序将只识别其中先扫描的按键;// 程序入口:void;// 程序出口:KEYNAME,包含按键信息、按键有效信息、当前按键状态;//================================================================== ====PROC KEYCHKKEYNAME DATA 40H ;按键名称存储单元;(b7-b5纪录按键状态,b4位为有效位,;b3-b0纪录按键)KEYRTIME DATA 43H ;重复按键时间间隔SIGNAL DATA 50H ;提示信号时间存储单元KEY EQU P3 ;键盘接口(必须完整I/O口) KEYPL EQU P0.6 ;指示灯接口RTIME EQU 30 ;重复按键输入等待时间KEYCHK:;//=============按键检测程序========================================= ====MOV KEY,#0FH ;送扫描信号MOV A,KEY ;读按键状态CJNE A,#0FH,NEXT1 ;ACC<=0FH; CLR C ;Acc等于0FH,则CY为0,无须置0NEXT1:; SETB C ;Acc不等于0FH,则ACC必小于0 FH,;CY为1,无须置1MOV A,KEYNAMEANL KEYNAME,#1FH ;按键名称屏蔽高三位RRC A ;ACC带CY右移一位,纪录当前按键状态ANL A,#0E0H ;屏蔽低五位ORL KEYNAME,A ;保留按键状态;//=============判别按键状态,决定是否执行按键扫描=================== =====CJNE A,#0C0H,NEXT2 ;110按键稳定闭合,调用按键检测子程序SJMP KEYSCANNEXT2:CJNE A,#0E0H,NEXT3 ;111按键长闭合,重复输入允许判断SJMP WAITNEXT3:CJNE A,#0A0H,EXIT ;101干扰,当111长闭合处理ORL KEYNAME,#0E0HWAIT:MOV A,KEYRTIMEJNZ EXIT ;时间没到,退出;//=============键盘扫描程序========================================= =====KEYSCAN:MOV R1,#0 ;初始化列地址MOV R3,#11110111B ;初始化扫描码LOOP:MOV A,R3RL AMOV R3,A ;保留扫描码MOV KEY,A ;送扫描码MOV A,KEY ;读键盘ORL A,#0F0H ;屏蔽高四位CJNE A,#0FFH,NEXT31 ;A不等于FFH,说明该列有按键动作INC R1 ;列地址加1,准备扫描下一列CJNE R1,#4,LOOP ;列地址不等于4,扫描下一列SJMP EXIT ;没有按键,退出;//=============按键判断对应位等于零,说明该行有按键按下============= =====NEXT31:JB ACC.0,NEXT32MOV R2,#0 ;第0行有按键SJMP NEXT5NEXT32:JB ACC.1,NEXT33MOV R2,#1 ;第1行有按键SJMP NEXT5NEXT33:JB ACC.2,NEXT34MOV R2,#2 ;第2行有按键SJMP NEXT5NEXT34:MOV R2,#3 ;第3行有按键NEXT5: ;计算按键地址MOV A,R1RL ARL A ;列地址乘4(每列对应4行)ADD A,R2 ;加行地址MOV DPTR,#KEYTABMOVC A,@A+DPTRANL KEYNAME,#0E0HORL KEYNAME,A ;送按键(送值的时候已经置按键有效)MOV KEYRTIME,#RTIME ;送重复按键等待时间CLR KEYPL ;打开指示灯MOV SIGNAL,#10 ;送信号提示时间(每次按键闪10 0ms)EXIT:MOV KEY,#0FFH ;置键盘接口高电平RET ;退出;//=============按键名称表=========================================== =====KEYTAB:DB 1AH ;扫描码0,对应A ************************************ ******DB 1BH ;扫描码1,对应B ** **DB 1CH ;扫描码2,对应C ** I/O口 PX.4 PX.5 PX.6 PX.7 **DB 1DH ;扫描码3,对应D ** **DB 11H ;扫描码4,对应1 ** PX.0 A(0) 1(4) 2(8) 3 (C) **DB 14H ;扫描码5,对应4 ** **DB 17H ;扫描码6,对应7 ** PX.1 B(1) 4(5) 5(9) 6 (D) **DB 1EH ;扫描码7,对应E ** **DB 12H ;扫描码8,对应2 ** PX.2 C(2) 7(6) 8(A) 9 (E) **DB 15H ;扫描码9,对应5 ** **DB 18H ;扫描码A,对应8 ** PX.3 D(3) E(7) 0(B) F(F) **DB 10H ;扫描码B,对应0 ** **DB 13H ;扫描码C,对应3 ************************************ ******DB 16H ;扫描码D,对应6DB 19H ;扫描码E,对应9DB 1FH ;扫描码F,对应FEND第二种解法ORG 0000HSTART: MOV R0,#00H ;初始化程序,开始的延时是为了使硬件能够准备好DJNZ R0,$LOOP: MOV SP,#60HCALL KEYDISPLAY:MOV A,R4MOV DPTR,#TABLE ;定义字形表的起始地址MOVC A,@A+DPTR ;TABLE为表的起始地址MOV P2,ASJMP LOOP;子程序内容,P1口的低四位为行线,高四位为列线KEY: PUSH PSWPUSH ACCMOV P1,#0F0H ;令所有的行为低电平,全扫描字-P1.0-P1.3,列为输入方式;这一段只是验证有键按下,并不能判断是哪一行MOV R7,#0FFH ;设置计数常数,作为延时KEY1: DJNZ R7, KEY1MOV A,P1 ;读取P1口的列值ANL A,#0F0H ;判别有键值按下吗(当有键按下时,P1口的高四位就不全为1了,底四位还是都为0的);这个地方进行相或的原因,是因为要把底四位的0000变成1111,以便下一步进行求反ORL A,#0FH //这个地方原版上没有,这是又加了,如果不加的的话,是不对的********CPL A ;求反后,有高电平就有键按下JZ EKEY;累加器为0则转移(意为求反后本来全为0的,如果有键按下时,求反后高四位就有1了),退出LCALL DEL20ms ;有键按下,进行处理;下面进行行行扫描,1行1行扫SKEY: MOV A,#00HMOV R0,A ;R0作为行计数器,开始初值为0MOV R1,A ;R1作为列计数器,开始初值为0MOV R2,#0FEH ;R2作为扫描暂存字,开始初值为1111 1110,(第四位作为行扫描字)SKEY2: MOV A,R2MOV P1,A ;输出行扫描字,1111 1110NOPNOPNOP ;3个NOP操作使P1口输出稳定MOV A,P1 ;读列值(和开始一样)MOV R1,A ;暂存列值(第一次为**** 1110,既高四位有一位"可能"会为0)ANL A,#0F0H ;取高四位,ORL A,#0FH ;使第四位全部置1CPL ABIAOZHI:JNZ SKEY3 ;累加器为非0则转移指令(意思是判断到按键在这一行),转去处理INC R0 ;如果按键没在这一行,行计数器加1SETB C ;进位标志位加1,为了在左移的时候开始的低位0不在出现在低(循环一圈后)MOV A,R2RLC A ;带进位左移1位(形成下一行扫描字,再次扫描)MOV R2,AMOV A,R0;把加1后的行计数器R0和总共扫描次数(4次比较)CJNE A,#04H,SKEY2 ;(扫描完了么)书本上这个地方也有错误,书本上写的是:SKEY1AJMP EKEY ;如果没有的话,退出;有键按下后行扫描过后,此为确列行SKEY3: MOV A,R1 ;JNB ACC.4,SKEY5 ;直接寻址位为0咋转移指令JNB ACC.5,SKEY6JNB ACC.6,SKEY7JNB ACC.7,SKEY8AJMP EKEY //我自己感觉到这命令没有用处SKEY5: MOV A,#00H ;存0列号MOV R3,AAJMP DKEYSKEY6: MOV A,#01H ;存1列号MOV R3,AAJMP DKEYSKEY7: MOV A,#02H ;存2列号MOV R3,AAJMP DKEYSKEY8: MOV A,#03H ;存3列号MOV R3,AAJMP DKEY;取出具体的行号,再加上列号,最终确认按键的号码DKEY: //MOV R4,#00HMOV A,R0MOV B,#04HMUL AB ;让行号*4,第四位放在A中(总共就4行,相乘后一定<16,也就是只有第四位有值)ADD A,R3 ;让行号和列号相加,最终确认任按键的具体号MOV R4,AEKEY: POP ACCPOP PSWRET ;按键扫描处理函数DEL20ms:MOV R7,#2DL2: MOV R6,#18DL1: MOV R5,#255DJNZ R5,$DJNZ R6,DL1DJNZ R7,DL2RET;此为共阴极数码管的数字表TABLE: DB 3FH ;0DB 06H ;1DB 5BH ;2DB 4FH ;3DB 66H ;4DB 6DH ;5DB 7DH ;6DB 27H ;7DB 7FH ;8DB 6FH ;9DB 77HDB 7CHDB 39HDB 5EHDB 79HDB 71HEND第三种PIC单片机键盘扫描汇编程序;本程序用于PIC外接键盘的识别,通过汇编程序,使按下K1键时第一个数码管显示1,按下K2键时第一;个数码管上显示2,按下K3键时第一个数码管上显示3,按下K4键时第一个数码管上显示4,;汇编程序对键盘的扫描采用查询方式LIST P=18F458INCLUDE "P18F458.INC";所用的寄存器JIANR EQU 0X20FLAG EQU JIANR+1 ;标志寄存器DEYH EQU JIANR+2DEYL EQU JIANR+3F0 EQU 0 ;FLAG的第0位定义为F0ORG 0X00GOTO MAINORG 0X30;*************以下为键盘码值转换表****************** CONVERT ADDWF PCL,1RETLW 0XC0 ;0,显示段码与具体的硬件连接有关RETLW 0XF9 ;1RETLW 0XA4 ;2RETLW 0XB0 ;3RETLW 0X99 ;4RETLW 0X92 ;5RETLW 0X82 ;6RETLW 0XD8 ;7RETLW 0X80 ;8RETLW 0X90 ;9RETLW 0X88 ;ARETLW 0X83 ;BRETLW 0XC6 ;CRETLW 0XA1 ;DRETLW 0X86 ;ERETLW 0X8E ;FRETLW 0X7F ;"."RETLW 0XBF ;"-"RETLW 0X89 ;HRETLW 0XFF ;DARKRETURN;***************PIC键盘扫描汇编程序初始化子程序***************** INITIALBCF TRISA,5 ;置RA5为输出方式,以输出锁存信号BCF TRISB,1BCF TRISA,3BCF TRISE,0BCF TRISE,1BSF TRISB,4 ;设置与键盘有关的各口的输入输出方式BCF TRISC,5BCF TRISC,3 ;设置SCK与SDO为输出方式BCF INTCON,GIE ;关闭所有中断LW 0XC0WF SSPSTAT ;设置SSPSTAT寄存器LW 0X30WF SSPCON1 ;设置SPI的控制方式,允许SSP方式,并且时钟下降;沿发送数据,与"74HC595当其SCLK从低到高电平;跳变时,串行输入数据(DI)移入寄存器"的特点相对应LW 0X01WF JIANR ;显示值寄存器(复用为键值寄存器)赋初值CLRF FLAG ;清除标志寄存器RETURN ;返回;**************显示子程序*****************DISPLAYCLRF PORTAWF SSPBUFAGAINBTFSS PIR1,SSPIFGOTO AGAINNOPBCF PIR1,SSPIFBSF PORTA,5 ;详细的程序语句请参考 pic教程语句部分,可在首页搜索。
4×4键盘扫描程序
键盘程序假设P2.0-P2.3为H0-H3,P2.4-P2.7为L0-L3 (列) L0 L1 L2 L3(行) H0 0 1 2 3H1 4 5 6 7H2 8 9 A BH3 C D E F首先,行为P2口的低四位,而列为高四位。
P0口为数码管输出口。
第一种思路就是逐行逐列判断法。
#include<reg51.h>#include<intrins.h>#define uint unsigned int#define uchar unsigned charuchar code table[17] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf};//八段数码管对应0-F值. uchar temp;void Delay_1ms(uint i)//1ms延时{uint x, j;for(j=0;j<i;j++)for(x=0;x<=148;x++);}void delay()//消除按键抖动延时{int i,j;for(i=0; i<=10; i++)for(j=0; j<=2; j++);}uchar Keyscan(void){uchar i,j,row,col;temp=P2&0xf0;for(i=0; i<4; i++){if(!(temp&(0x10<<i)))row=i;}P2=0x0f;temp=P2&0x0f;for(j=0; j<4; j++){if(!(temp&(0x01<<j)))col=j;}return (row+col*4);}void Main(void){uchar Key_Value=16; //读出的键值uchar i=0;while(1){P2 = 0xf0;temp=P2;if(temp != 0xf0){Delay_1ms(80); //按键消抖if(temp != 0xf0){Key_Value = Keyscan();}Delay_1ms(350); //按键消抖}P0 = table[Key_Value];//P0口输出数据到数码管}次读取结果组合起来就可以得到当前按键的特征编码。
4x4矩阵键盘扫描原理
4x4矩阵键盘扫描原理
4x4矩阵键盘扫描原理是一种常用的键盘扫描方法,也称为矩阵键盘扫描。
它可以将多个按键连接在一起并使用较少的引脚来检测按键的状态。
4x4矩阵键盘由4行和4列组成,共有16个按键。
通常使用单片机或电路来进行扫描,以下是简要的原理:
1. 行扫描:首先,将行引脚设置为输出,同时将列引脚设置为输入,并将其上拉或下拉。
所有行引脚中只有一个为低电平,其余为高电平。
然后逐行检测按键状态。
2. 列检测:对于每一行,将对应的行引脚置为低电平后,检测列引脚的电平状态。
如果有按键按下,则相应的列引脚会变为低电平。
通过读取列引脚的状态,可以确定按键的位置。
3. 组合键:由于只能一次检测一行,因此当同时按下多个按键时,可能会导致误检。
为了解决这个问题,可以在检测到按键按下时,延迟一段时间,并再次检测按键的状态。
如果在第二次检测时仍然检测到按键按下,则确认按键有效。
4. 反向扫描:为了检测按键的释放状态,可以将行引脚设置为输入,列引脚设置为输出,并将其置为低电平。
然后逐列检测行引脚的电平状态,如果有按键释放,则相应的行引脚会变为高电平。
通过不断地循环扫描所有的行和列,可以实时检测按键的状态,并根据需要进行相应的处理。
4x4键盘的程序有扫描法与线反法
4x4键盘的程序有扫描法与线反法,但我个人认为用线反法较好,用扫描法得依次扫描所有行或列,如果用线反法就简单多了。
先使键盘的行置为低、列置为高(或列置为高、行置为低),接着读回端口的值。
比如:如果使用P0为键盘接口就先使低四位为低、高四位为高即P0=0xf0然后就读回P0口的值赋给一个变量,a=P0;紧接就给行列赋相反的值行置为高、列置为低(或列置为低、行置为高)即P0=0x0f然后就读回再与a运算就能得到唯一的识别码下面的程序就是用线反写一个4x4键盘识别程序:#include<AT89X52.H>#include<delay.h>#define KEY_SCAN P1#define uchar unsigned char//char num;/********************************//*函数名称:KEY_DOWN() *//*函数功能:延时子函数 *//*参数:无 *//*返回:返回1或0 *//*备注:1表示有键按下,0则无*//********************************/bit KEY_DOWN(){KEY_SCAN=0x0f; //先给键盘口赋个初值if(KEY_SCAN!=0x0f) //判断是有按键按下,即KEY_SCAN不等于初值时有键按下{delayms(10); //消抖if(KEY_SCAN!=0x0f) //再次判断是否真有键按下return 1; //真有就返回1没有返回零elsereturn 0;}elsereturn 0;}/********************************//*函数名称:SCAN_GET() *//*函数功能:键盘值函数 *//*参数:无 *//*返回:返回1或0 *//*备注:无 *//********************************/uchar SCAN_GET(){char button;uchar key_code;button=KEY_SCAN;KEY_SCAN=0xf0;button=(button|KEY_SCAN);while(KEY_SCAN!=0xf0);delayms(10);switch(button){case 0xd7: key_code='1';break;case 0xdb: key_code='2';break;case 0xdd: key_code='3';break;case 0xb7: key_code='4';break;case 0xbb: key_code='5';break;case 0xbd: key_code='6';break;case 0x77: key_code='7';break;case 0x7b: key_code='8';break;case 0x7d: key_code='9';break;case 0xeb: key_code='0';break;case 0xee: key_code=0xee;break;default : break;}return key_code;}////////////////////////////////////////////////////////////// //此程序是上两个程序结合的/********************************//*函数名称:Key_Get() *//*函数功能:键盘扫描函数 *//*参数:无 *//*返回:无 *//*备注:无 *//********************************/void Key_Get(){char button;KEY_SCAN=0x0f;if(KEY_SCAN!=0x0f){delayms(5);if(KEY_SCAN!=0x0f)button=KEY_SCAN;KEY_SCAN=0xf0;button=(button|KEY_SCAN);while(KEY_SCAN!=0xf0);switch(button){case 0xd7: num='1';P0=0x00;break; case 0xdb: num='2';P0=0x0f;break; case 0xdd: num='3';break;case 0xb7: num='4';break;case 0xbb: num='5';break;case 0xbd: num='6';break;case 0x77: num='7';break;case 0x7b: num='8';break;case 0x7d: num='9';break;case 0xeb: num='0';break;case 0xe7: num='a';break;case 0xed: num='b';break;case 0xee: num='c';break;case 0xde: num='d';break;case 0xbe: num='e';break;case 0x7e: num='f';break;default : break;}}}}qinglei120713的分享分享矩阵键盘C51程序(4*4)(来自互联网) 1111111111111111111111111111111111111111111111 11111111111111111111111111111111111111#include <reg51.h>#include <intrins.h>#define key_port P0 //键盘接口定义sbit key_port_0=key_port^0;sbit key_port_1=key_port^1;sbit key_port_2=key_port^2;sbit key_port_3=key_port^3;/*******************************STC89C59 单片机一毫秒延时函数*******************************/void delay_ms(unsigned int ms){unsigned int i,j;for( i=0;i<ms;i++)for(j=0;j<332;j++); //1947是STC89C58在22.1184MHz晶振下,通过软件仿真反复实验得到的数值}/**************************串口发送一个字符**************************/void com_send_dat( unsigned char dat){SBUF=dat;while (TI== 0);TI= 0 ;}/**************************串口初始化**************************/void init_com( void ){SCON=0x50 ; //SCON: serail mode 1, 8-bit UART, enable ucvr //UART为模式1,8位数据,允许接收TMOD|=0x20 ; //TMOD: timer 1, mode 2, 8-bit reload //定时器1为模式2,8位自动重装TH1=0xfa ; //Baud:19200 fosc="22.1184MHzTL1=0xfa;PCON|=0x80; //SMOD=1;波特率加倍;ES=1; //Enable Serial InterruptTR1 = 1 ; // timer 1 run}/**************************键盘扫描函数**************************/unsigned char keyscan(void){unsigned char key,i;unsigned char co de key_table[16]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,0xbd,0x bb,0xb7,0x7e,0x7d,0x7b,0x77};key_port=0x0f; //确定行列位置if(key_port==0x0f)return(0);//无键按下返回0delay_ms(10); //调用延时函数,目的是去前沿键抖。
4X4键盘扫描程序
4X4键盘扫描程序,采用查表方式,适用于AVR单片机。
此处为4X4键盘软件部分,硬件部分设计请参照:4X4键盘扫描电路分析。
此程序对应的键盘电路为:键盘状态扫描函数/*键盘扫描函数读取当前键盘的状态有按键按下返回相应按键值无按键按下返回"0x00"*/unsigned char key_read(void){unsigned char i;DDRA = 0x00;/*获取列地址*/PORTA = 0x0F;DDRA = 0xF0;此处应加入几uS延时;i = PINA;DDRA = 0x00;/*获取行地址*/PORTA = 0xF0;DDRA = 0x0F;此处应加入几uS延时;i |= PINA;DDRA = 0x00;/*输出复位*/PORTA = 0xFF;switch (i) {/*将按键码转换成键值*/ case 0x00: return 0x00;case 0xEE: return '1';case 0xDE: return '2';case 0xBE: return '3';case 0x7E: return 'A';case 0xED: return '4';case 0xDD: return '5';case 0xBD: return '6';case 0x7D: return 'B';case 0xEB: return '7';case 0xDB: return '8';case 0xBB: return '9';case 0x7B: return 'C';case 0xE7: return '*';case 0xD7: return '0';case 0xB7: return '#';case 0x77: return 'D';default : return 0x00;}}键盘读取函数/*按键获取函数获取按键信号,其中包含有状态记录及按键去颤抖。
STM32-矩阵键盘程序4×4
STM32-矩阵键盘程序4×4/*--------------------------------------------------------------------------------------* 矩阵键盘驱动* 文件: keyboard.c* 编写人:LiuHui* 描述:扫描4x4 矩阵键盘输入,并返回键值* 适用范围:驱动采用ST3.5 库编写,适用于STM32F10x 系列单片机* 所用引脚:PA0-PA7* 编写时间:2014 年5 月20 日--------------------------------------------------------------------------------------*/#include "stm32f10x.h"#include "keyboard.h"#include "dealy.h"/*--------------------------------矩阵键盘初始化----------------------------------------* 功能:初始化stm32 单片机GPIO //PA0-PA7* 参数传递:* 输入:无* 返回值:无--------------------------------------------------------------GPIO_Pin_2 | GPIO_Pin_3);switch(GPIO_ReadInputData(GPIOA)&0xff) {case 0x11: KeyValue = 1; break;case 0x21: KeyValue = 5; break;case 0x41: KeyValue = 9; break;case 0x81: KeyValue = 13;break;}GPIO_SetBits(GPIOA, GPIO_Pin_1);GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3);switch(GPIO_ReadInputData(GPIOA)&0xff) {case 0x12: KeyValue = 2; break;case 0x22: KeyValue = 6; break;case 0x42: KeyValue = 10;break;case 0x82: KeyValue = 14;break;}GPIO_SetBits(GPIOA, GPIO_Pin_2);GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_3);{case 0x14: KeyValue = 3; break;case 0x24: KeyValue = 7; break;case 0x44: KeyValue = 11;break;case 0x84: KeyValue = 15;break;}GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2);switch(GPIO_ReadInputData(GPIOA)&0xff) {case 0x18: KeyValue = 4; break;case 0x28: KeyValue = 8; break;case 0x48: KeyValue = 12;break;case 0x88: KeyValue = 16;break;}GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3); GPIO_ResetBits(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 |GPIO_Pin_7);0x0f);return KeyValue;}}return 0;}/*--------------------------------THEEND--------------------------------------------*//*--------------------------------------------------------------------------------------* 矩阵键盘驱动* 文件: keyboard.h* 编写人:LiuHui* 描述:扫描4x4 矩阵键盘输入,并返回键值* 适用范围:驱动为ST3.5 库编写,适用于STM32F10x 系列单片机* 所用引脚:PA0-PA7* 编写时间:2013 年11 月22 日* 版本:1.0--------------------------------------------------------------------------------------*/#ifndef __KEYBOARD_H#define __KEYBOARD_Hvoid KeyBoard_Init(void);u8 Read_KeyValue(void);#endif/*----------------------------------THEEND------------------------------------------*#include "stm32f10x.h"void KeyBoard_Init(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6); GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);}//³õʼ»¯PA,PBvoid Delay_ms(int time){int i=0;while(time--){i=12000;while(i--);}}u8 Read_KeyValue(void){u8 KeyValue=1;if((GPIO_ReadInputData(GPIOB)&0xff)!=0x 0f){Delay_ms(10);if((GPIO_ReadInputData(GPIOB)&0xff)!=0x 0f){GPIO_SetBits(GPIOB, GPIO_Pin_3);GPIO_ResetBits(GPIOB, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6);switch(GPIO_ReadInputData(GPIOB)&0xff)case 0x11: KeyValue = 7; break;case 0x21: KeyValue = 4; break;case 0x41: KeyValue = 1; break;case 0x81: KeyValue = 0; break;}GPIO_SetBits(GPIOB, GPIO_Pin_4);GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_6);switch(GPIO_ReadInputData(GPIOB)&0xff) {case 0x12: KeyValue = 8; break;case 0x22: KeyValue = 5; break;case 0x42: KeyValue = 2; break;case 0x82: KeyValue = 0; break;}GPIO_SetBits(GPIOB, GPIO_Pin_5);GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6);switch(GPIO_ReadInputData(GPIOB)&0xff)case 0x14: KeyValue = 9; break;case 0x24: KeyValue = 6; break;case 0x44: KeyValue = 3; break;case 0x84: KeyValue = 0; break;}GPIO_SetBits(GPIOB, GPIO_Pin_6);GPIO_ResetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5);switch(GPIO_ReadInputData(GPIOB)&0xff) {case 0x18: KeyValue = 0; break;case 0x28: KeyValue = 0; break;case 0x48: KeyValue = 0;break;case 0x88: KeyValue = 0;break;}GPIO_SetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6); GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);//while((GPIO_ReadInputData(GPIOB)&0xff)! =0x0f);return KeyValue;}}return 0;}uint16_ttable[]={0xEB,0x28,0xB3,0xBA,0x78,0xDA,0xD B,0xA8,0xFB,0xFA};int main(){RCC_APB2PeriphClockCmd(RCC_APB2Perip h_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Perip h_GPIOB,ENABLE);KeyBoard_Init();int keyvalue=Read_KeyValue();GPIO_Write(GPIOA, table[keyvalue]); /*while(1){int i;for(i=0;i<10;i++){GPIO_Write(GPIOA, table[i]);Delay_ms(500);}}*//*u8 keyvalue;for(int i=0;;i++){KeyBoard_Init();keyvalue=Read_KeyValue();GPIO_Write(GPIOA,table[keyvalue]);Delay_ms(500);}*/}#include "stm32f10x.h"void KeyBoard_Init(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_ Pin_6|GPIO_Pin_7|GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPD;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6); GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);}void Delay_ms(int time){int i=0;while(time--){i=12000;while(i--);}}u8 Read_KeyValue(void){if((GPIO_ReadInputData(GPIOB)&0xff)!=0x 73)//在这个程序下为什么无论是GPIO_ReadInputData(GPIOB)&0xff)!=0x73还是GPIO_ReadInputData(GPIOB)&0xff)==0x73都能往下运行,而在屏蔽Delay_ms(10)后则只能运行一种,是因为这个Delay_ms(10)对if里的判断有影响吗?{Delay_ms(10);GPIO_Write(GPIOA,0x33);}return 0;}int main(){RCC_APB2PeriphClockCmd(RCC_APB2Perip h_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);KeyBoard_Init();Read_KeyValue(); }。
4x4矩阵键盘扫描例程
//4x4矩阵键盘扫描例程(C51)//使用P0口上的LED灯显示键盘扫描得到的键值//===============#include<reg51.h> //51系列单片机头文件#define uchar unsigned char#define uint unsigned int#define key_4x4_port P3 //定义4x4键盘使用的单片机端口uchar key; //存放扫描得到的键值void delayms(uint xms); //声明延时子程序void key_4x4_scan(); //声明4x4键盘扫描子程序,得到的键值送全局变量key //=====================void main(){P0=0xff; //P0开机初始化Key=0xff; //键盘值开机初始化为ff(检测到的键值应为0-15)while(1){key_4x4_scan(); //不停调用键盘扫描子程序P0=key; //用P0来显示键值}}//========================void delayms(uint xms) //延时子程序{ uint i, j;for (i=xms; i>0; i--)for (j-110; j>0; j--);}//======================void key_4x4_scan() //4x4键盘扫描子程序,得到的键值送全局变量key{ uchar temp;key_4x4_port=0xfe; //送出P3.0位0电平去扫描temp= key_4x4_port; //读出整个口得到的值temp=temp&0xf0; //屏蔽低4位if (temp!=0xf0) //假如高4位不全是1{ delayms(10); // 延时消抖再读temp=key_4x4_port;temp=temp&0xf0;if (temp!=0xf0) //消抖后如果再次高4位确定不是全1{ temp=key_4x4_port; //读出此次按键的值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=key_4x4_port;temp=temp&0xf0;}}}//====次高位送0==========key_4x4_port=0xfd; //送出P3.1位0电平去扫描temp= key_4x4_port; //读出整个口得到的值temp=temp&0xf0; //屏蔽低4位if (temp!=0xf0) //假如高4位不全是1{ delayms(10); // 延时消抖再读temp=key_4x4_port;temp=temp&0xf0;if (temp!=0xf0) //消抖后如果再次高4位确定不是全1{ temp=key_4x4_port; //读出此次按键的值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=key_4x4_port;temp=temp&0xf0;}}}//====第3高位送0==========key_4x4_port=0xfb; //送出P3.2位0电平去扫描temp= key_4x4_port; //读出整个口得到的值temp=temp&0xf0; //屏蔽低4位if (temp!=0xf0) //假如高4位不全是1{ delayms(10); // 延时消抖再读temp=key_4x4_port;temp=temp&0xf0;if (temp!=0xf0) //消抖后如果再次高4位确定不是全1{ temp=key_4x4_port; //读出此次按键的值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=key_4x4_port;temp=temp&0xf0;}}}//====第4高位送0==========key_4x4_port=0xf7; //送出P3.3位0电平去扫描temp= key_4x4_port; //读出整个口得到的值temp=temp&0xf0; //屏蔽低4位if (temp!=0xf0) //假如高4位不全是1{ delayms(10); // 延时消抖再读temp=key_4x4_port;temp=temp&0xf0;if (temp!=0xf0) //消抖后如果再次高4位确定不是全1{ temp=key_4x4_port; //读出此次按键的值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=key_4x4_port;temp=temp&0xf0;}}}}//==========End。
4X4矩阵键盘的测试程序
#include <reg52.h>#define uchar unsigned char#define uint unsigned int#define LCDDATA P0 //数码管数据端口定义#define LCDCS P2 //数码管位选端口定义#define KEYDATA P1 //矩阵键盘接口定义uchar key; //定义键值为全局变量uchar dis_buf; //显示缓存uchar disp_num[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//显示数据列表0---9//功能:延时1毫秒//入口参数:x//出口参数:无void Delay_xms(uint x){uint i,j;for(i=0;i<x;i++)for(j=0;j<112;j++);}//关闭数码管显示,当Q0~Q3均为高电平时,三极管均截止,无电流流过数码管,显示被关闭void tube_off(void){LCDCS|=0xf0;}//数码管数据显示//入口参数:x为需要显示的数据,addr为数码管地址即第几位数码管void tube_disp(uchar addr,uchar x){LCDDATA=disp_num[x];//将显示数据送P0口switch(addr){case 1: //选通第1位数码管LCDCS&=0xef;break;case 2: //选通第2位数码管LCDCS&=0xdf;break;case 3: //选通第3位数码管LCDCS&=0xbf;break;case 4: //选通第4位数码管LCDCS&=0x7f;break;}Delay_xms(2);tube_off();}//键扫描子程序void keyscan(void){uchar temp=0,key=0;KEYDATA=0xF0; //高四位输入行为高电平列为低电平Delay_xms(1);temp=KEYDA TA; //读P1口temp=temp&0xF0; //屏蔽低四位temp=~((temp>>4)|0xF0);if(temp==1) // P1.4 被拉低key=0;else if(temp==2) // P1.5 被拉低key=1;else if(temp==4) // P1.6 被拉低key=2;else if(temp==8) // P1.7 被拉低key=3;elsekey=16;KEYDATA=0x0F; //低四位输入列为高电平行为低电平Delay_xms(1);temp=KEYDA TA; //读P1口temp=temp&0x0F;temp=~(temp|0xF0);if(temp==1)key=key+12;else if(temp==2) // P1.1 被拉低key=key+8;else if(temp==4) // P1.2 被拉低key=key+4;else if(temp==8) // P1.3 被拉低key=key+0;elsekey=16;if(key<16){dis_buf = key; //键值入显示缓存}}//判断键是否按下uchar keydown(void){uchar key_flag;KEYDATA=0xf0;if(KEYDATA!=0xf0){key_flag=1;}else{key_flag=0;}return key_flag;}//定时器中断函数void Timer2() interrupt 5 //定时器2是5号中断{uchar shiwei,gewei;TF2=0;shiwei=dis_buf%100/10;tube_disp(3,shiwei);//第3位数码管显示"十位"gewei=dis_buf%10;tube_disp(4,gewei); //第4位数码管显示"个位"}//定时器2初始化void Init_timer2(void){RCAP2H=0xb1;//赋T2初始值0xb1e0,溢出50次为1秒,则每次溢出时间为1/50=0.02s RCAP2L=0xe0;TR2=1; //启动定时器2ET2=1; //打开定时器2中断EA=1; //打开总中断}//主函数void main(void){Delay_xms(50);//等待系统稳定Init_timer2();//定时器2初始化P2=0xFF; //置P2口tube_off(); //关闭数码管显示while(1){if(keydown()){Delay_xms(20);if(keydown()){keyscan();}}}}。
实验四 键盘扫描实验
一、实验目的、要求设计一个4X4的矩阵键盘,键盘的号码0~15,要求编写出一个键盘输入扫描程序,要求单片机能根据键盘排列顺序,能将按下去键盘号正确识别出来,并采用两个数码管分别键盘号码的个位和十位。
二、实验原理三、源程序清单或实验步骤1.设计电路,并按照电路接线2.编写调试程序:#include<reg51.h> //包含51单片机寄存器定义的头文件sbit P14=P1^4;sbit P15=P1^5;sbit P16=P1^6;sbit P17=P1^7;unsigned char codeTab[ ]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //数字0~9的段码unsigned char keyval;/**************************************************************函数功能:数码管动态扫描延时**************************************************************/void led_delay(void){unsigned char j;for(j=0;j<200;j++);}/**************************************************************函数功能:按键值的数码管显示子程序**************************************************************/void display(unsigned char k){P2=0xbf;P0=Tab[k/10];led_delay();P2=0x7f;P0=Tab[k%10];led_delay();}/**************************************************************函数功能:软件延时子程序**************************************************************/void delay20ms(void){unsigned char i,j;for(i=0;i<100;i++)for(j=0;j<60;j++);}/************************************************************** 函数功能:主函数**************************************************************/ void main(void){EA=1;ET0=1;TMOD=0x01;TH0=(65536-500)/256;TL0=(65536-500)%256;TR0=1;keyval=0x00;while(1){display(keyval);}}/************************************************************** 函数功能:定时器0的中断服务子程序,进行键盘扫描,判断键位**************************************************************/ void time0_interserve(void) interrupt 1 using 1{P1=0xf0;if((P1&0xf0)!=0xf0)delay20ms();if((P1&0xf0)!=0xf0){P1=0xfe;if(P14==0)keyval=1; if(P15==0) keyval=2; if(P16==0) keyval=3;if(P17==0)keyval=4;P1=0xfd;if(P14==0)keyval=5;if(P15==0)keyval=6;if(P16==0)keyval=7;if(P17==0)keyval=8;P1=0xfb;if(P14==0)keyval=9;keyval=10;if(P16==0)keyval=11;if(P17==0)keyval=12;P1=0xf7;if(P14==0)keyval=13;if(P15==0)keyval=14;if(P16==0)keyval=15;if(P17==0)keyval=16;}TR0=1;TH0=(65536-500)/256;TL0=(65536-500)%256;}四、实验结果经过调试:矩阵键盘上的输入按键的键号能够正常显示在LED数码管上。
4×4矩阵键盘原理及其在单片机中的简单应用(基Proteus仿真)
4×4矩阵键盘原理及其在单片机中的简单应用基于Proteus仿真1、4×4矩阵键盘的工作原理如下图所示,4×4矩阵键盘由4条行线和4条列线组成,行线接P3.0-P3.3,列线接P3.4-P3.7,按键位于每条行线和列线的交叉点上。
按键的识别可采用行扫描法和线反转法,这里采用简单的线反转法,只需三步。
第一步,执行程序使X0~X3均为低电平,此时读取各列线Y0~Y3的状态即可知道是否有键按下。
当无键按下时,各行线与各列线相互断开,各列线仍保持为高电平;当有键按下时,则相应的行线与列线通过该按键相连,该列线就变为低电平,此时读取Y0Y1Y2Y3的状态,得到列码。
第二步,执行程序使Y0~Y3均为低电平,当有键按下时,X0~X3中有一条行线为低电平,其余行线为高电平,读取X0X1X2X3的状态,得到行码。
第三步,将第一步得到的列码和第二步得到的行码拼合成被按键的位置码,即Y0Y1Y2Y3X0X1X2X3(因为行线和列线各有一条为低电平,其余为高电平,所以位置码低四位和高四位分别只有一位低电平,其余为高电平)。
也就是说,当某个键按下时,该键两端所对应的行线和列线为低电平,其余行线和列线为高电平。
比如,当0键按下时,行线X0和列线Y0为低电平,其余行列线为高电平,于是可以得到0键的位置码Y0Y1Y2Y3X0X1X2X3为01110111,即0X77。
当5键按下时,行线X1和列线Y1为低电平,其余行列线为高电平,于是可得到5键的位置码Y0Y1Y2Y3X0X1X2X3为10111011,即0XBB。
全部矩阵键盘的位置码如下:2、4×4矩阵键盘在单片机的简单应用举例(一)如下图所示,运行程序时,按下任一按键,数码管会显示它在矩阵键盘上的序号0~F,并且蜂鸣器发出声音,模拟按键的声音。
此处采用线反转法识别按键。
C程序如下:#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit buzzer=P1^0;uchar code dis[]= //0~9,A~F的共阳显示代码{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0X88,0X83,0XC6,0XA1,0X86,0X8E};uchar code tab[]= //矩阵键盘按键位置码{0x77,0xb7,0xd7,0xe7,0x7b,0xbb,0xdb,0xeb,0x7d,0xbd,0xdd,0xed,0x7e,0xbe,0xde,0xee};void delay(uint x) //延时函数{uchar i;while(x--)for(i=0;i<120;i++);}uchar scan() //矩阵键盘扫描函数,得到按键号,采用线反转法{uchar a,b,c,i;P3=0XF0; //P3口输出11110000a=P3; //读取列码delay(10); //防抖延时10msP3=0X0F; //P3口输出00001111b=P3; //读取行码c=a+b; //得到位置码for(i=0;i<16;i++)if(c==tab[i])return i; //查表得到按键序号并返回return -1; //无按键,则返回-1}void beep() //蜂鸣器发出声音,模拟按键的声音{ uchar i;for(i=0;i<100;i++){buzzer=~buzzer;delay(1);}buzzer=0;}void main(){uchar key;buzzer=0; //关闭蜂鸣器while(1){key=scan(); //得到按键号if(key!=-1) //有按键则显示,并且蜂鸣器发出声音{P0=dis[key];beep();delay(100);}}}Proteus仿真运行结果如下:3、4×4矩阵键盘在单片机的简单应用举例(二)如下图所示,运行程序时,按下的按键键值越大,点亮的LED灯越多,例如,按下1号键时,点亮一只LED灯,按下2号键时,点亮两只LED灯,按下16号键时,点亮全部LED 灯。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
temp=P3;temp=temp&0x0f;
if(temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;temp=temp&0x0f;
if(temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;temp=temp&0x0f;
if(temp!=0x0f)
{
case 0x07: key=0;break;
}
temp=P3;temp=temp&0x0f;
while(temp!=0x0f)
{
temp=P3;temp=temp&0x0f;
}
}
P3=0xff;P3_7=0;
temp=P3;temp=temp&0x0f;
if(temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
那么就会出现低电平,从而判断哪个按键按下;
如果没有那么就给P1赋值0xfd,也就是P1^1为低电平,其他为高电平.,
相同方法判断是否有按键按下;
如果没有那么就P1赋值0xfb·····
如此类推,一共四次检测。
/*************************************************/
}
}
}
}
/*****************说明(仅作参考)********************************/
首先,给P1赋值0xf0,
这时P1^4,P1^5,P1^6,P1^7为高电平,
P1^0,P1^1,P1^2,P1^3为低电平。
}
P0=table[key];
}
}
///////////////////////////////////////////////////
P3=0xff;P3_5=0;
temp=P3;temp=temp&0x0f;
switch(temp)
{
case 0x0e: key=3;break;
case 0x0d: key=2;break;
case 0x0b: key=1;break;
if(temp!=0x0f)
{
temp=P3;temp=temp&0x0f;
switch(temp)
{
case 0x0e: key=11;break;
temp=P3;temp=temp&0x0f;
switch(temp)
{
case 0x0e:key=7;break;
case 0x0d:key=6;break;
temp=P3;temp=temp&0x0f;
while(temp!=0x0f)
{
temp=P3;temp=temp&0x0f;
}
P0=table[key];
case 0x0d: key=10;break;
case 0x0b: key=9;break;
case 0x07: key=8;break;
}
case 0x0b:key=5;break;
case 0x07:key=4;break;
}
temp=P3;temp=temp&0x0f;
while(temp!=0x0f)
#include<AT89X51.H>
unsigned char codetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
unsigned char temp;
temp=P3;temp=temp&0x0f;
while(temp!=0x0f)
{
temp=P3;temp=temp&0x0f;
}
P0=table[key];
如果这时候有按键按下那么P1^4,P1^5,P1^6,P1^7就有一个会变成低电平。
因此P1的值就不等于0xf0,这是就可以判断有按键按下。
然后延时一段时间去抖动,
然后给P1赋值0xfe,也就是P1^0为低电平,其他为高电平,
这时如果有在P1^0线上的P1^4,P1^5,P1^6,P1^7有按键按下,
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;temp=temp&0x0f;
if(temp!=0x0f)
{
temp=P3;temp=temp&0x0f;
case 0x0d: key=14;break;
case 0x0b: key=13;break;
case 0x07: key=12;break;
}
{
temp=P3;temp=temp&0x0f;
}
P0=table[key];
}
}
/////////////////////////////////////////////////////////
unsigned char key;
unsigned chari,j;
void main(void)
{
while(1)
{
P3=0xff;P3_4=0;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
temp=P3;temp=temp&0x0f;
if(temp!=0x0f)
{
temp=P3;temp=temp&0x0f;
switch(temp)
{
case 0x0e: key=15;break;