2017-07-23 16:33:16 mr_bean_1031 阅读数 5062
  • 51单片机综合项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

搬运到CSDN的旧文档


众所周知,51单片机一般的键盘检测原理为非编码键盘检测,没有专门用来产生键编码号或键值的电路芯片;而我们使用的电脑键盘为编码键盘,通过编码电路芯片为每个按键产生一个编码号,可以通过串行总线把键值传输给电脑。在进行矩阵键盘检测时,书本或老师一般教的都是扫描检测,即一行一行地检测或者一列一列地检测,代码繁琐复杂,且缺点很多(例如执行效率较低)。
举例电路:
这里写图片描述
矩阵键盘与8051连接如上图所示,首先,令P3=0x0f,检测P30、P31、P32、P33哪一行被按下,将此时P3的值存入寄存器1。然后,令P3=0xf0 | 寄存器1,检测P34、P35、P36、P37哪一列被按下,将此时P3的值存入寄存器2。最后,把寄存器1的值和寄存器2的值组合起来即可得到矩阵键盘的编码。

代码如下:

#include<reg52.h>
unsigned char NUM=1;
/*-----------------------------
  特殊功能位定义
-----------------------------*/
sbit L1=P0^0;
sbit L2=P0^1;
sbit L3=P0^2;
sbit L4=P0^3;
sbit L5=P0^4;
sbit L6=P0^5;
sbit L7=P0^6;
sbit L8=P0^7;
sbit DUAN=P2^6;
sbit WEI=P2^7;
/*-----------------------------
  定时器0初始化函数
-----------------------------*/
void init()
{
    EA=1;
    ET0=1;
    TMOD=0X01;
    TH0=(65536-10000)/256;
    TL0=(65536-10000)%256;
}
/*-----------------------------
  中断服务函数
-----------------------------*/
void timer0()interrupt 1
{
    TR0=0;  //定时终止
    TH0=(65536-10000)/256;  //定时器0初值重装
    TL0=(65536-10000)%256;
    NUM--;
}
/*--------------------------------------------------
  矩阵键盘检测兼编码函数 
--------------------------------------------------*/ 
unsigned char matrixkeyscan()
{
    unsigned char temp,reg1=0,reg2=0,key=0;  //temp为临时变量,reg1为寄存器1,reg2为寄存器2,key为键盘编码号 
    P3=0x0f;
    temp=P3&0x0f;
    if(temp!=0x0f)  //按键检测兼行坐标检测 
    {
        TR0=1;        //-------------------
        while(NUM);   //  10ms去抖动延时  
        NUM=1;        //-------------------
        temp=P3&0x0f;
        if(temp!=0x0f)  //二次检测 
        {
            reg1=temp;     //把行坐标存入寄存器1
            P3=reg1|0xf0;  //关键,没有这句将导致整个函数出错
            temp=P3&0xf0;
            if(temp!=0xf0)  //检测列坐标
            {
                reg2=temp;  //把列坐标存入寄存器2 
                key=reg1|reg2;  //将寄存器1和寄存器2进行按位或,作用是组合坐标,格式为八位二进制的"列坐标行坐标" 
                while(temp!=0xf0)  //等待按键释放
                    temp=P3&0xf0;
            }
        }
    }
    return key;
}

/*--------------------------------------------------
  按键功能实现函数 
--------------------------------------------------*/ 
void keyfunction()
{
    unsigned char kvalue=0;
    kvalue=matrixkeyscan();
    switch(kvalue)
    {
        case 0xee: L1=~L1;/*按键01功能*/ break; 
        case 0xde: L2=~L2;/*按键02功能*/ break;
        case 0xbe: L3=~L3;/*按键03功能*/ break;
        case 0x7e: L4=~L4;/*按键04功能*/ break;
        case 0xed: L5=~L5;/*按键05功能*/ break;
        case 0xdd: L6=~L6;/*按键06功能*/ break;
        case 0xbd: L7=~L7;/*按键07功能*/ break;
        case 0x7d: L8=~L8;/*按键08功能*/ break;
        case 0xeb: /*按键09功能*/ break;
        case 0xdb: /*按键10功能*/ break;
        case 0xbb: /*按键11功能*/ break;
        case 0x7b: /*按键12功能*/ break;
        case 0xe7: /*按键13功能*/ break;
        case 0xd7: /*按键14功能*/ break;
        case 0xb7: /*按键15功能*/ break;
        case 0x77: /*按键16功能*/ break;
        default: ;//空语句 
    }
}
/*-----------------------------
  主函数
-----------------------------*/
void main()
{
    DUAN=0;
    WEI=0;
    init();  //定时器初始化,装入初值10ms
    while(1)
    {
            keyfunction();  //按键循环检测
    }
}
2019-07-02 20:00:59 weixin_45280176 阅读数 64
  • 51单片机综合项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

#include<reg52.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit a=P1^0;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
void delay(uint x);
uchar temp,key,disnum;
void main()
{
a=0; //接通第一个数码管
disnum=16; //在没按按键时,数码管什么都不显示
while(1) //大循环
{
P3=0xf0; //P3=11110000 列全为1,行全为0
temp=P3; //在没有按键按下时temp=11110000,当有按键被按下时,temp!=11110000
temp=temp&0xf0; //将temp的低四位全为0
if(temp!=0xf0) //检测是否有按键被按下
{
delay(10); //延时,消抖
if(temp!=0xf0) //检测是否有按键被按下
{
temp=P3; //将P3口实时的值赋给temp,此时的temp高四位有一位为0,低四位全为0
temp=temp|0x0f; //将temp低四位全置1
P3=temp; //将temp值赋给P3口
key=P3; //用key读取P3口的值
switch(key) //拿key的值与case后面的值进行对比
{
case 0xee : disnum=0;break; //当key=0x00时,把disnum=0并退出switch语句
case 0xde : disnum=1;break;
case 0xbe : disnum=2;break;
case 0x7e : disnum=3;break;
case 0xed : disnum=4;break;
case 0xdd : disnum=5;break;
case 0xbd : disnum=6;break;
case 0x7d : disnum=7;break;
case 0xeb : disnum=8;break;
case 0xdb : disnum=9;break;
case 0xbb : disnum=10;break;
case 0x7b : disnum=11;break;
case 0xe7 : disnum=12;break;
case 0xd7 : disnum=13;break;
case 0xb7 : disnum=14;break;
case 0x77 : disnum=15;break;
}
}

}
P0=table[disnum]; //把数组中的第disnum位的真值赋给P0
}
}
void delay(uint x) //延时函数,延时时间为x次所花费的时间
{
while(x–); //x进行自减,直到x=0时才跳出延时函数
}

2015-12-28 00:45:44 yhcfsr 阅读数 797
  • 51单片机综合项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

关于矩阵键盘的扫描,这个简单的问题居然困扰了我一天。扫描原理:输入行值,读取列值;输入列值,读取行值。这是很常用的方法。代码如下:

 //=======================================
  //       矩阵键盘扫描,返回按键码
  //=======================================
  unsigned char KeyScan()
  {
    /*低四位为行线值,高四位为列线值*/
    unsigned char code_h,code_l;
    KeyPort = 0xf0;     //令行线值为0
    code_l=KeyPort&0xf0; //读取列线值
    if(code_l!=0xf0)
    {
       DelayMs(10);//延时10毫秒
       if((KeyPort&0xf0)==code_l)
       { 
         KeyPort=0x0f;//令列线值为0
         code_h=KeyPort&0x0f;//读取行线值
         while(code_h==(KeyPort&0x0f));//while(KeyPort!=0xff); //等待松开按键
         return (code_h|code_l);   //返回组合码
       }
    }
    return 0xff;
  }

困扰我的就是KeyPort = 0xf0 ,我在想为什么用KeyPort &= 0xf0 就不可以。这是一个魔咒,根源是不熟悉矩阵的物理结构以及它和单片机的关系。这没什么必要详述,中咒之人一看便知。但明慧的人自然不会着道,因此也没有必要了解。
以下内容仅提供给和我一样犯迷糊的人。

1.矩阵的结构
矩阵结构示意图

2.矩阵所连接的单片机端口
假如所用端口P3,在扫描过程中P3仅仅是用来检测矩阵的按键状态,P3原有的状态没有任何意义。我就是怕赋值语句改变端口状态才那么纠结。
3.顺便做个笔记
关于16位定时器0初值赋值:

TH0=(65536-3000)>>8;      //重新赋值 3ms,高8
TL0=(65536-3000);         //低8位

网上提到许多取16位数据高8位和低8位的方法,综合比较了一下,还是上面这种简单实在效率。常用的也有下面这种,效率略逊。

TH0=(65536-3000)/256;     //重新赋值 3ms,高8
TL0=(65536-3000)%256;         //低8位
2014-04-21 22:30:26 xiaofeige567 阅读数 6915
  • 51单片机综合项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

      设计一个4X4的矩阵键盘,键盘的号码0~15,要求编写出一个键盘输入扫描程序,要求单片机能根据键盘排列顺序,能将按下去键盘号正确识别出来,并采用两个数码管分别键盘号码的个位和十位。

实验参考电路图如下:


参考代码:

#include<reg51.h>   //包含51单片机寄存器定义的头文件
sbit P14=P1^4;      
sbit P15=P1^5;     
sbit P16=P1^6;      
sbit P17=P1^7;      
unsigned char code Tab[ ]={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   
  {
     TR0=0;                 
     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;   
           if(P15==0)      
             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;   
 }

修改实验电路图和实验程序和设计电路,改成静态显示


调试后的程序代码:

#include<reg51.h>   //包含51单片机寄存器定义的头文件
sbit P14=P1^4;      
sbit P15=P1^5;     
sbit P16=P1^6;      
sbit P17=P1^7;      
unsigned char code Tab[ ]={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=0x3f;         ///////////////   
P0=Tab[k/10];  
     P3=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   
  {
     TR0=0;                 
     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;   
           if(P15==0)      
             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;   
 }


2018-10-17 11:07:08 qq_27131611 阅读数 1177
  • 51单片机综合项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3414 人正在学习 去看看 朱有鹏

STC单片机按键扫描程序

最近在做一个电子秤相关项目,使用STC系列单片机作为主控芯片,项目第一阶段直接使用IAP15W4K58S4驱动两个矩阵键盘,一切调试顺利,在项目即将结束时老板要求使用另一块单片机驱动矩阵键盘,读取键值后通过串口传回之前的IAP主控(理由是为了节省从矩阵键盘到主控板之间的长排线的成本,16P+10P);OK ,老板发话了,还能说什么呢,做呗,于是问题出现了。下面先简单介绍矩阵键盘的检测原理,然后说一说一些容易遇到的问题。

1.先简单介绍下矩阵键盘的扫描原理

对于N*M的矩阵键盘(N>=M),我们在编写程序的过程中,为提高扫描效率与降低程序的复杂程度,常设计N为列检测,M为行扫描,对应于程序上的检测输入与扫描输出。下图为矩阵键盘的示意图。

矩阵键盘示意图

检测原理:在上图示意键盘中,规定竖向为列,即是P10,P11,P12,P13为列检测;P14,P15,P16,P17为行扫描。没有按键按下是,列检测为到电平(一般为准双向IO,弱上拉),行扫描为低电平输出。当按键S5被按下后,P10与P15接通,P10由高电平变为低电平,单片机检测到P10-P13有任何一位被拉低时,认为有按键按下,此时程序应记录下哪一列按键被按下(得到按键的列坐标),然后按序拉高P14-P14,直到P10-P13全为初始状态(高电平),此时拉高的行即为被按下的按键的行坐标。例如:S5被按下后,P10为0,得到列坐标为1,当P15拉高后,P10-P14均为1,得到行坐标为2,最后得到按键坐标为2行1列--S5。其他按键检测原理相同。

单片机驱动扫描按键原理很简单,但是在实际使用中对不同单片机的配置有要求,配置不当容易检测到错误的键值。一下简要说明几个容易遇到的问题。

1.现在市面上的单片机IO基本都有4种标准模式(准双向IO、推挽输出、开漏输出、高阻输入)详解见:(https://blog.csdn.net/jbh18401/article/details/76048843)。一般列检测配置为准双向IO,但准双向IO的输出为弱上拉啊,拉电流弱,抗干扰性差,所以在列检测IO外部,应外加上拉电阻(10-100K),一确保按键的稳定性。

2.在按键扫描的程序中,由于单片机程序执行速度快,在检测按键行坐标时,拉高对应行后应适当延时,等待IO端口稳定后再检测行输入是否改变(程序如下)。若不加入延时,会导致因IO还没来得及完全拉高,列检测程序已经执行完毕,最终导致按键动作检测不到或者误检。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

获取键盘键值

阅读数 453

没有更多推荐了,返回首页