找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7749|回复: 8
收起左侧

求助一个4*4键盘扫描程序

[复制链接]
ID:245536 发表于 2017-11-3 14:09 | 显示全部楼层 |阅读模式
10黑币
我想用51单片机实现4*4键盘扫描功能,键盘通常有几种可能,一种是抖动,一种是按下,一种是抬起,一种是长按(分辨3000毫秒时长为长按),我们只要实现按下就发送指令到串口,在电脑上通过串口助手可以获取单片机发来的指令,指令形式按照“0-9*ABCD”分别代表16个键。

最佳答案

回复

使用道具 举报

ID:213173 发表于 2017-11-3 14:09 | 显示全部楼层
1606188581 发表于 2017-11-5 11:43
有没有电路图呢?我是小白,麻烦简单画个图纸也行

无标题.jpg
回复

使用道具 举报

ID:245536 发表于 2017-11-3 15:23 | 显示全部楼层
由于我的黑币太少无法悬赏太多,我可以用现金方式悬赏,有意义留言即可
回复

使用道具 举报

ID:82765 发表于 2017-11-3 20:49 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

ID:213173 发表于 2017-11-4 07:20 | 显示全部楼层
送你一个示例,4*4矩阵键盘接在P2(只能接P1或P2,不能接P3,否则与串口冲突。如果接P0要加上拉电阻)。
#include <AT89X52.H>
#define uint unsigned int                 //宏定义无符号整型数据
#define uchar unsigned char         //宏定义无符号字符型数据
uchar key=0xff;                                        //定义键值全局变量
bit flag=0;                                                //定义发送标志

void keyscan()                                        //按键扫描程序
{
        static bit sign=0;                        //按键有效标志
        static uint count=0;                //消抖计数变量                       
        uchar num=0;                                //临时变量
        P2=0xf0;                                                //赋值P2 1111 0000
        if((P2!=0xf0)&&(sign==0))        //检测按键有效
        {
                count++;                                //消抖计数
                if(count>=500)                        //100~1000,根据主循环周期调整约10~20ms
                {                       
                        sign=1;                                //按键有效标志置1
                        num=P2;                                //保存P2值xxxx 0000,x为0或1
                        num|=0x0f;                        //保存num按位或0x0f值xxxx 1111
                        P2=num;                                //赋值P2 xxxx 1111
                        num=P2;                                //保存P2值xxxx xxxx
                        switch(num)
                        {
                                case 0xee: key=0x00; break;
                                case 0xde: key=0x01; break;
                                case 0xbe: key=0x02; break;
                                case 0x7e: key=0x03; break;
                                case 0xed: key=0x04; break;
                                case 0xdd: key=0x05; break;
                                case 0xbd: key=0x06; break;
                                case 0x7d: key=0x07; break;
                                case 0xeb: key=0x08; break;
                                case 0xdb: key=0x09; break;
                                case 0xbb: key=0x0a; break;
                                case 0x7b: key=0x0b; break;
                                case 0xe7: key=0x0c; break;
                                case 0xd7: key=0x0d; break;
                                case 0xb7: key=0x0e; break;
                                case 0x77: key=0x0f; break;
                        }
                        flag=1;
                }
        }
        else                                                //键抬起
        {
                sign=0;                                        //按键有效标志清0
                count=0;                                //消抖计数清0
        }
}
void main()                                                //主函数
{
        TMOD=0x20;//定时器1方式2(8位重载)
        TH1=0xfd; //波特率9600
        TL1=0xfd; //波特率9600
        TR1=1;        //开定时器1
        SM0=0;        //设置串口方式1(8位UART波特率可变)
        SM1=1;        //设置串口方式1(8位UART波特率可变)
        while(1)
        {
                keyscan();                        //按键扫描程序
                if(flag==1)                        //发送标志为1
                {
                        flag = 0;                //发送标志清0
                        SBUF = key;                //发送键值数据
                        while(!TI)                //等待发送中断请求标志位为1
                        TI=0;                                //发送中断请求标志位清0
                }
        }
}
回复

使用道具 举报

ID:111634 发表于 2017-11-4 21:21 | 显示全部楼层
本帖最后由 zl2168 于 2017-11-4 21:32 编辑

介绍你几个短按/长按处理的案例
Proteus仿真一下,确认有效。

实例96  能预置初值的倒计时秒表
实例96 能设置初值的倒计时秒表.rar (40 KB, 下载次数: 8)
99.9秒秒表.jpg

实例95 99.9秒秒表.rar

38.86 KB, 下载次数: 3

回复

使用道具 举报

ID:245536 发表于 2017-11-5 11:43 | 显示全部楼层
wulin 发表于 2017-11-4 07:20
送你一个示例,4*4矩阵键盘接在P2(只能接P1或P2,不能接P3,否则与串口冲突。如果接P0要加上拉电阻)。
#in ...

有没有电路图呢?我是小白,麻烦简单画个图纸也行
回复

使用道具 举报

ID:243738 发表于 2017-11-5 12:42 | 显示全部楼层
  1. #include<reg51.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. #define GPIO_DIG P0
  5. #define GPIO_KEY P1

  6. uchar code DIG_CODE[17]=
  7. {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
  8. 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
  9. //数码管的显示码
  10. uchar KeyValue;
  11. //用来存放读取到的按下的键值
  12. void Delay10ms();
  13. //延时10ms
  14. void KeyDown();
  15. //按键函数
  16. void main(void)
  17. {
  18.         while(1)
  19.         {
  20.                 KeyDown();
  21.                 GPIO_DIG=~DIG_CODE[KeyValue];
  22.                 //数码管显示按键值
  23.         }                               
  24. }
  25. void KeyDown(void)
  26. {
  27.         char a=0;
  28.         GPIO_KEY=0x0f;//P1高四位低电平0000,低四位高电平1111
  29.         if(GPIO_KEY!=0x0f)//读取按键是否按下
  30.         {
  31.         Delay10ms();//延时10ms消抖
  32.                 if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
  33.                 {
  34.                         GPIO_KEY=0x0f;//测试列 00001111
  35.                                 switch(GPIO_KEY)
  36.                                 {
  37.                                         case(0x07): KeyValue=0;break;//00000111,第一列有按键按下  
  38.                                         case(0x0b): KeyValue=1;break;//00001011,第二列有按键按下
  39.                                         case(0x0d): KeyValue=2;break;//00001101,第三列有按键按下
  40.                                         case(0x0e): KeyValue=3;break;//00001110,第四列有按键按下
  41.                                 }
  42.                         GPIO_KEY=0xf0;//测试行 11110000
  43.                                 switch(GPIO_KEY)
  44.                                 {
  45.                                         case(0x70): KeyValue=KeyValue;break;//01110000,第一行有按键按下
  46.                                         case(0xb0): KeyValue=KeyValue+4;break;//10110000,第二行有按键按下
  47.                                         case(0xd0): KeyValue=KeyValue+8;break;//11010000,第三行有按键按下
  48.                                         case(0xe0): KeyValue=KeyValue+12;break;//11100000,第四行有按键按下
  49.                                 }//得到相应的键值
  50.                         while((a<50)&&(GPIO_KEY!=0xf0))//按键松手检测
  51.                                 {
  52.                                 Delay10ms();
  53.                                 a++;
  54.                                 }
  55.                         }
  56.         }
  57. }

  58. void Delay10ms(void)   //误差 0us
  59. {
  60.     uchar a,b,c;
  61.     for(c=1;c>0;c--)
  62.         for(b=38;b>0;b--)
  63.             for(a=130;a>0;a--);
  64. }


  65. /*逐行扫描:高四位轮流输出低电平来对矩阵键盘
  66. 进行逐行扫描,当低四位接收到的数据不全为1时
  67. 说明有按键按下,然后通过接收到的数据是哪一
  68. 位为0来判断哪一个按键被按下*/
  69. /*行列扫描:我们可以通过高四位全部输出低电平,
  70. 低四位输出高电平。当接收到的数据,低四位不全为高电平时,
  71. 说明有按键按下,然后通过接收的数据值,判断是哪一列有
  72. 按键按下,然后再反过来,高四位输出高电平,第四位输出低电平,
  73. 然后根据接收到的高四位的值判断是哪一行有按键按下,这样就能够
  74. 确定是哪一个按键按下了。*/
复制代码
回复

使用道具 举报

ID:245536 发表于 2017-11-5 13:43 | 显示全部楼层

电路图有吗?我不太在行
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表