单片机 键盘显示实验 实验二

实验二    键盘显示实验

实验准备:软件Keil uVision5、Proteus 8 Professional

  • 实验目的

  • 1、掌握矩阵键盘检测的原理和方法;

    2、掌握按键消抖的方法;

    3、再次熟悉数码管的显示。

  • 实验任务

  • 从4×4矩阵键盘输入4位字符(如“15EF”),并显示于4位数码管。

  • 实验原理

  • 在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图2-1所示。在矩阵键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。

    图2-1 矩阵键盘

     矩阵键盘的按健识别方法很多,其中最常见的方法是行扫描法。行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,下面介绍矩阵键盘的扫描过程。

    (1)判断有无键按下

    第一步:向所有的列输出口线输出低电平;

    第二步:然后将行线的电平状态读入;

    第三步:判断读入的行线值。若无键按下,所有的行线仍保持高电平状态;若有键按下,行线中至少应有一条线为低电平。

    (2)去除按键的抖动

    去抖原理:当判断到键盘上有键按下后,则延时一段时间再判断键盘的状态,若仍为有键按下状态,则认为有一个键按下,否则当作按键抖动来处理。

    (3)按键识别(列或行扫描法)

    在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将列(行)线置为低电平,即在置某根列(行)线为低电平时,其列(行)线为高电平,再逐行(列)检测各行(列)线的电平状态。若某行为低电平,则该行线与置为低电平的列线交叉处的按键就是闭合的按键。

    (4)求按键的键值

    根据闭合键的行值row和列值col采用计算法(如健值=行号×4+列号)或查表法将闭合键的行值和列值转换成所定义的键值。

    电路原理图如下图所示。

    图2-2 键盘显示实验电路

    注释:上面的原理是课程设计给的模板,不是我写的,仅供参考,如有相同就是参考的,参考书:单片机原理与接口技术实验指导书、单片机原理与接口技术

  • 程序流程图

  • 图一 程序流程图

  • 实验结果及分析总结

  • 键盘显示实验测试结果

    该电路图根据该实验指导书绘制,使用的软件Proteus 8 Professional,如图二所示,将编写好的代码(代码详情转附录)录入到该电路,从而实现键盘显示实验。(图中数码管输入的内容是本人学号后四位,如需需要输入其他内容可根据按键进行更改)。

    图二 键盘显示电路仿真测试

    编写数码管动态显示代码

    本次实验实验代码模块化的内容,是根据本人在网络视频学习所得(江协科技——51单片机入门教程视频所得),本次实验模块化编程内容如图二所示。

    附录中代码的顺序:main.c(主程序调用函数)、main.h(主程序的header文件)、keyScan.c(按键扫描函数)、keyScan.h、segDisplay.c(数码显示函数)、segDisplay.h、time0_int.c(定时器延迟函数)、time0_int.h。

    图三 模块化代码编写内容

    实验总结

    本次实验运用之前偶然所学的模块编程的知识内容,首先,需要解决的问题是四个数码管输入问题。课程的学习只是一个数码管的编写,因此,使用数组keyValue完成四个数码管的定义,之后进行数码管的移位。其次,需要解决按键扫描的问题,再其次是需要解延时的问题,最后将编写好的程序在主函数中调用。本次的实验,需要结合学习过的知识点进行整合,修改合理的代码内容。在编写代码是需要先画出流程图,将程序模块化。处理的代码内容更加的清晰明了。

  • 程序附录

  • main.c程序

    #include"main.h" 
    							
    void main() 
    { 
     	unsigned char temp=0; 
     	unsigned char keyValue[4]={0};  //定义一个数组,用来存放四个数码管所显示的值
     	while(1){ 
        	temp=keyScan();  //keyScan()为矩阵按键扫描函数
          if(temp!=16) {  //因为矩阵按键所表示的值是0~15(在数码管上是显示0~F),所以要满足temp<16才执行下面滚显的指令
    				//当按键按了后,有新值进入数码管时,数码管的旧值都往左移一位,腾出一个位置给新值显示
    				keyValue[3]=keyValue[2];
    				keyValue[2]=keyValue[1];
    				keyValue[1]=keyValue[0];
    				keyValue[0]=temp;  
          } 
            segDisplay(keyValue);  //显示键值函数
      }  
    } 
     
    

    main.h

    #ifndef __MAIN_H__
    #define __MAIN_H__
    
    	#include"segDisplay.h"
    	#include"keyScan.h" 	
    
    #endif
    

    segDisplay.c

    #include"segDisplay.h"
    
    //显示0~F的值,采用共阳数码管
    //定义中的code代表的是把定义的数据表存储在flash存储器中,如去掉code则存储在RAM中
    unsigned char code sgmduan[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 
    	                            0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
    
    void segDisplay(unsigned char *value){ 
    	unsigned char i; 
        for(i=0;i<4;i++){ 
        	switch(i){           //位选,选择点亮的数码管,  
            	//数码管从右往左排序
    				  case(0): 
                LSA=0;LSB=0;LSC=0;LSD=1; break;//显示第 0 位 
              case(1): 
                LSA=0;LSB=0;LSC=1;LSD=0; break;//显示第 1 位 
              case(2): 
                LSA=0;LSB=1;LSC=0;LSD=0; break;//显示第 2 位 
              case(3): 
                LSA=1;LSB=0;LSC=0;LSD=0; break;//显示第 3 位  
          } 
    	    P0=sgmduan[value[i]];//发送段码 
            
    			//Delay(100); //间隔一段时间扫描 
    		  //定时器延时
    			timer0_init();
    		  while(~TF0);
    			TF0=0;		 
          P0=0xFF;//消隐上次显示的数字,使下次显示更清晰 
        }  
    } 

    segDisplay.h

  • #ifndef __SEGDISPLAY_H__
    #define __SEGDISPLAY_H__
    
    	#include"timer0_init.h"
    	sbit LSA=P1^3; 
    	sbit LSB=P1^2; 
    	sbit LSC=P1^1; 
    	sbit LSD=P1^0;
    	void segDisplay(unsigned char *value);
    
    #endif

    keyScan.c
     

    #include "keyScan.h"
    
    unsigned char keyScan() { 
        unsigned char a = 0;
        unsigned char t; 
        unsigned char KeyValue = 16;
        P2 = 0xF0;
        if (P2 != 0xF0) {
            for (t = 0; t < 10; t++) {
                timer0_init();
                while (~TF0);
                TF0 = 0;				
            }
            if (P2 != 0xF0) {
                P2 = 0xF0; 
                switch (P2) { 
                    case (0x70): KeyValue = 3; break;
                    case (0xB0): KeyValue = 2; break; 
                    case (0xD0): KeyValue = 1; break; 
                    case (0xE0): KeyValue = 0; break; 
                } 
                P2 = 0x0F; 
                switch (P2) { 
                    case (0x07): KeyValue = KeyValue + 12; break;
                    case (0x0B): KeyValue = KeyValue + 8; break; 
                    case (0x0D): KeyValue = KeyValue + 4; break; 
                    case (0x0E): KeyValue = KeyValue; break; 
                } 
                while ((a < 50) && (P2 != 0x0F)) { 
                    for (t = 0; t < 10; t++) {
                        timer0_init();
                        while (~TF0);
                        TF0 = 0;					
                    }
                    a++; 
                } 
            }   
        }
        return KeyValue;

    keyScan.h

    #ifndef __KEYSCAN_H__
    #define __KEYSCAN_H__
    
    	#include"timer0_init.h"
    	unsigned char keyScan();
    	extern unsigned char keyValue[4];  //外部变量声明
    
    #endif
    

    timer0_init.c

    #include"timer0_init.h"
    
    void timer0_init(){  //定时器初始化函数
    	EA=1;  //打开总中断
    	ET0=1;  //中断0控制允许位
    	TR0=1;  //开启中断0
    	TMOD=0x01;//定时器工作模式为1
    	TH0=0xfc;//定时器延时10ms(延时1ms为FC66H)
    	TL0=0x66;
    }
    

    timer0_init.h

    #ifndef __TIMER0_INIT_H__
    #define __TIMER0_INIT_H__
    
    	#include"reg52.h"
    	void timer0_init();
    
    #endif
    

    学习过程中,参考资料网上的,如有侵权删。如有需要自行下载源文件,里面code文件是程序代码,还有一个仿真文件。

  • 作者:RJSJS……

    物联沃分享整理
    物联沃-IOTWORD物联网 » 单片机 键盘显示实验 实验二

    发表回复