找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 267|回复: 27
打印 上一主题 下一主题
收起左侧

请教51单片机矩阵键盘反转法扫描遇到的无法解决的问题

[复制链接]
跳转到指定楼层
楼主
ID:349276 发表于 2024-10-30 17:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
mcu 是stc8a8k64s4a12单片机,矩阵键盘是带上拉电阻的真实键盘,P1口连接,采用反转法扫描。1.必须设置成开漏模式才能采集到数据。其它模式都不行,不知道啥原因。2.第一次置P1=0xf0,可以正确设置,且能正确采集回按键情况;第二次反转 设置P1=0x0f,然后采集p1口的数据完全是错的,比如只采集p1一次,得到的数据是第一次(反转设置之前)的数据;比如重复写一次采集数据(连续采集两次),得到的数据跟采集一次的又完全不同,且还发现低电平被拉高了(本来应该是高电平被拉低)。
没招数了。请大神指点下迷津。

P1为KEY_ScanPort  要设置这个 初始化 P1M1=0xff;P1M0=0xff;才能读回数据

        
        KEY_ScanPort=0xF0;                 //列线为输入,行线为输出,并置行线输出全为0
        temp=KEY_ScanPort;                 //读P1口       能正确得到数据
        temp=temp&0xF0;
        temp=~((temp>>4)|0xF0);
        if(temp==1)
                key=0;
        else if(temp==2)
                key=1;
        else if(temp==4)
                key=2;
        else if(temp==8)
                key=3;
        KEY_ScanPort=0xFF;//for read  这一句可有可不有,但proteus里那键盘keypad仿真必须得有这个,否则无法采集
        KEY_ScanPort=0x0F;                 //设置反转,行线为输入,列线为输出,并置列线输出全为0
        MDelay(3);        //怀疑引脚电平反转起效果时有一个较长的时间延迟
        temp=KEY_ScanPort;                 //读P1口 读出来跟没有反转之前的采集情况一样,就是高四位有3个1
        temp=KEY_ScanPort;                //重复采集一下发现低四位有4个1 高四位有1~2个1,低电平反而被拉高了。
       temp=KEY_ScanPort;                //再重复采集一下发现低四位有4个1,高四位是4个0,不动了,按键没效果。反正反转后无法采集到正确信息
        temp=temp&0x0F;
        temp=~(temp|0xF0);        
        if(temp==1)
                key=key+0;
        else if(temp==2)
                key=key+4;
        else if(temp==4)
                key=key+8;
        else if(temp==8)
                key=key+12;
                             

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1109793 发表于 2024-10-30 19:07 | 只看该作者
矩阵怎么接的?4*4的?一次拉低4个IO,怎么判断是那个IO上的KEY?
回复

使用道具 举报

板凳
ID:446156 发表于 2024-10-31 09:44 | 只看该作者
反转法矩阵扫描当然要配置成开漏模式啦必须所有用到的IO都是开漏才行,这样你让IO输出高电平的时候该IO可以被外界信号拉低或者拉高方便你检测,这和IIC的SDA要配置成开漏一个原理。我没看明白你是开漏模式下完全正常还是开漏模式下也存在问题。还有设置完IO口状态再去读取IO口电平时中间要间隔一段时间一般情况下1ms完全够了,因为电路存在寄生电容,开漏模式下IO状态从低到高需要上拉电阻给寄生电容充电需要时间不会瞬间变化的。
回复

使用道具 举报

地板
ID:446156 发表于 2024-10-31 09:46 | 只看该作者
xiaobendan001 发表于 2024-10-30 19:07
矩阵怎么接的?4*4的?一次拉低4个IO,怎么判断是那个IO上的KEY?

反转法,先把四个列线拉低检测4个行线电平,然后把4个行线拉低去检测4个列线电平。把两次检测结果或在一起就能知道是哪个按键被按下了
回复

使用道具 举报

5#
ID:619259 发表于 2024-10-31 10:25 | 只看该作者
矩阵键盘反转法扫描实例,以 P1口为例。
1.拉低P1低4位;
2.若P1高4位出现低电平,则读P1的值;
3.反转,释放P1低4位,拉低P1高4位;
4.读P1的值;
5.将步骤2和4的值或运算;
6.对步骤5的值进行判断或查表,执行给定任务。
回复

使用道具 举报

6#
ID:1109793 发表于 2024-10-31 12:51 | 只看该作者
cy009 发表于 2024-10-31 10:25
矩阵键盘反转法扫描实例,以 P1口为例。
1.拉低P1低4位;
2.若P1高4位出现低电平,则读P1的值;

这样就是需要都设置标准IO才行吧,设置开漏就是没有上拉电阻,那么高电平由谁提供?
我还真没试过这种,都是一个IO一个IO的拉低,然后检测另外四个的电平变化。
回复

使用道具 举报

7#
ID:446156 发表于 2024-10-31 14:05 | 只看该作者
xiaobendan001 发表于 2024-10-31 12:51
这样就是需要都设置标准IO才行吧,设置开漏就是没有上拉电阻,那么高电平由谁提供?
我还真没试过这种, ...

外部上拉电阻提供高电平啊,所有的按键电路无论矩阵也好独立按键也好不都得配上拉电阻吗?
回复

使用道具 举报

8#
ID:161164 发表于 2024-10-31 14:57 | 只看该作者
上拉电阻阻值多大?
回复

使用道具 举报

9#
ID:349276 发表于 2024-10-31 15:44 | 只看该作者
xiaobendan001 发表于 2024-10-30 19:07
矩阵怎么接的?4*4的?一次拉低4个IO,怎么判断是那个IO上的KEY?

4*4的,p1低四位接行,高四位接列。每条线都有上拉电阻,上拉电阻电路是放矩阵键盘里面的。反转法是f0   再0f的,按键按下,只会有一个高电平会被拉低的。原理上来说。仿真都没有问题的。就是实际这个键盘,反转后采集不回来数据。
回复

使用道具 举报

10#
ID:349276 发表于 2024-10-31 15:45 | 只看该作者
qinlu123 发表于 2024-10-31 09:46
反转法,先把四个列线拉低检测4个行线电平,然后把4个行线拉低去检测4个列线电平。把两次检测结果或在一 ...

就是行线拉低,采集不回数据。
回复

使用道具 举报

11#
ID:1133081 发表于 2024-10-31 15:45 | 只看该作者
给你一个4*4矩阵按键示例,端口设置为准双向模式。有无外置上拉电阻无所谓。程序放在主函数里查询。key初值为0,键值输出1~16,使用后可以清0.
void keyscan()                                        //按键扫描程序
{
        static bit sign=0;                        //按键状态标志
        static int count=0;                        //消抖计数变量                       
        unsigned char temp=0;                //临时变量
        P1=0xf0;                                        //赋值P1 1111 0000
        if(P1!=0xf0)                                //检测有按键按下
        {
                count++;                                //消抖计数
                if(count>=100 && sign==0)//根据主程序查询周期调整count大小,约10~20ms防抖即可
                {                       
                        sign=1;                                //按键状态标志置1
                        temp=P1;                        //保存P1值xxxx 0000,x为0或1
                        temp|=0x0f;                        //保存temp按位或0x0f值xxxx 1111
                        P1=temp;                        //赋值P1 xxxx 1111
                        switch(P1)
                        {
                                case 0xee: key= 1; break;
                                case 0xde: key= 2; break;
                                case 0xbe: key= 3; break;
                                case 0x7e: key= 4; break;
                                case 0xed: key= 5; break;
                                case 0xdd: key= 6; break;
                                case 0xbd: key= 7; break;
                                case 0x7d: key= 8; break;
                                case 0xeb: key= 9; break;
                                case 0xdb: key=10; break;
                                case 0xbb: key=11; break;
                                case 0x7b: key=12; break;
                                case 0xe7: key=13; break;
                                case 0xd7: key=14; break;
                                case 0xb7: key=15; break;
                                case 0x77: key=16; break;
                        }
                }
        }
        else                                                //键抬起
        {
                sign=0;                                        //按键状态标志清0
                count=0;                                //消抖计数清0
        }
}
回复

使用道具 举报

12#
ID:349276 发表于 2024-10-31 15:46 | 只看该作者
qinlu123 发表于 2024-10-31 09:44
反转法矩阵扫描当然要配置成开漏模式啦必须所有用到的IO都是开漏才行,这样你让IO输出高电平的时候该IO可以 ...

我明天试试,延迟1ms后再采集试试。
回复

使用道具 举报

13#
ID:349276 发表于 2024-10-31 15:50 | 只看该作者
cy009 发表于 2024-10-31 10:25
矩阵键盘反转法扫描实例,以 P1口为例。
1.拉低P1低4位;
2.若P1高4位出现低电平,则读P1的值;

您这步骤完全正确。就是第三步,代码直接用  P1=0x0f,起不了作用。您所谓 释放p1低四位,拉低p1高四位,是不是不使用的P1=0x0f语句?如不使,应该怎么用?
回复

使用道具 举报

14#
ID:349276 发表于 2024-10-31 15:51 | 只看该作者
xiaobendan001 发表于 2024-10-31 12:51
这样就是需要都设置标准IO才行吧,设置开漏就是没有上拉电阻,那么高电平由谁提供?
我还真没试过这种, ...

键盘上提供了上拉结构的,高电平有键盘提供。开漏是可以的。
回复

使用道具 举报

15#
ID:1109793 发表于 2024-10-31 16:39 | 只看该作者
qinlu123 发表于 2024-10-31 14:05
外部上拉电阻提供高电平啊,所有的按键电路无论矩阵也好独立按键也好不都得配上拉电阻吗?

既然要用外部上拉,为何还要关闭内部上拉?还是说这种接法和读取方法需要非常精确的上拉,内部因为制造工艺问题误差太大不能用?那么多少才最好用?
回复

使用道具 举报

16#
ID:349276 发表于 2024-10-31 23:25 来自手机 | 只看该作者
WL0123 发表于 2024-10-31 15:45
给你一个4*4矩阵按键示例,端口设置为准双向模式。有无外置上拉电阻无所谓。程序放在主函数里查询。key初值 ...

这代码也许不错,第二次只有一个低电平线。明天试试效果。
回复

使用道具 举报

17#
ID:349276 发表于 2024-10-31 23:30 来自手机 | 只看该作者
xiaobendan001 发表于 2024-10-31 16:39
既然要用外部上拉,为何还要关闭内部上拉?还是说这种接法和读取方法需要非常精确的上拉,内部因为制造工 ...

是这样的,设置为其它模式,一次数据都读不回来。设置为开漏,立刻就读回来了。原因我不会分析。另外查到stm32,如果是开漏模式,还有几个寄存器要联合配置,比如有个配置低电平究竟是哪个范围,范围不对采集的数据可能会错。不知道是不是因为没配置的原因?我不知道stc8有没有这些寄存器。没看它的说明书。
回复

使用道具 举报

18#
ID:579397 发表于 2024-11-1 00:48 | 只看该作者
        KEY_ScanPort=0xF0;
******
        KEY_ScanPort=0xFF;//for read  这一句可有可不有,但proteus里那键盘keypad仿真必须得有这个,否则无法采集

这里加一个延时试试,我解释不了,但我这样做就正常了
        KEY_ScanPort=0x0F;                 //设置反转,行线为输入,列线为输出,并置列线输出全为0
回复

使用道具 举报

19#
ID:446156 发表于 2024-11-1 08:12 | 只看该作者
xiaobendan001 发表于 2024-10-31 16:39
既然要用外部上拉,为何还要关闭内部上拉?还是说这种接法和读取方法需要非常精确的上拉,内部因为制造工 ...

习惯问题吧,我很少用单片机的内部上拉,51多年不用了不了解,stm32的内部上拉电阻太大很多场合都不合适。看了下51IO设置结合我之前做51时候的经历把IO配置成准双向IO也行即M1=0;M0=0
回复

使用道具 举报

20#
ID:446156 发表于 2024-11-1 08:15 | 只看该作者
万家灯火51 发表于 2024-10-31 15:45
就是行线拉低,采集不回数据。

你先检查IO输入检测有没有问题,把8和IO都输出0读一下IO状态然后都输出1再读一下状态。用万用表量一量是不是对
回复

使用道具 举报

21#
ID:192020 发表于 2024-11-1 14:21 | 只看该作者
temp=KEY_ScanPort;                 //读P1口 读出来跟没有反转之前的采集情况一样,就是高四位有3个1
不知道你是用什么方法来读temp值的?这时候万用表量一下高低电平是不是和读的符合,感觉大概率硬件问题
回复

使用道具 举报

22#
ID:349276 发表于 2024-11-1 18:47 来自手机 | 只看该作者
问题解决!!首先非常感谢各位大佬积极出主意和提供经验。看到您们的回复,一下子觉得很踏实。困惑几周的问题,综合大家的想法突然有了思路。问题出在两个地方:一个是没有等待按键释放就退出扫描,代码又重复进入扫描覆盖了前一次的数据。这个是看到上面大佬代码里搞那么多状态标记惊醒了我。第二个问题是,开漏输出,电平上拉全靠外电路,电阻值大小和是否有旁路电容等,这个拉高过程有点长。电路理论里的三要素法,大致可以判断,时间常数在毫秒级。线反转法第一次设置后,要延时1毫秒,反转后要延时2毫秒再采集数据,就完全正确了。非常感谢大家之外,有几点感触。1是谢谢大家技术上的开放心态。任正非说华为不一定能活下去,但仍非常感谢美国技术的开放支撑华为辉煌了三十年。特别鄙视百度,csdn中文版看两句话就要收钱要么就是各种坑各种牛皮。国内,知识都被锁。2.是遇到问题不要轻易怀疑芯片不可靠,是自己不可靠。3是这个论坛能查到真东西,能解决真问题。到搜这个论坛很难搜到,全是冒充51黑的假网站。国内网络生态太恶心。。广告了
回复

使用道具 举报

23#
ID:1109793 发表于 2024-11-2 07:19 | 只看该作者
万家灯火51 发表于 2024-11-1 18:47
问题解决!!首先非常感谢各位大佬积极出主意和提供经验。看到您们的回复,一下子觉得很踏实。困惑几周的问 ...

不用开漏用标准IO不行吗?要等2MS,这太浪费时间了吧。2US还行
回复

使用道具 举报

24#
ID:349276 发表于 2024-11-2 12:14 来自手机 | 只看该作者
xiaobendan001 发表于 2024-11-2 07:19
不用开漏用标准IO不行吗?要等2MS,这太浪费时间了吧。2US还行

标准口,没有用延时等待不行。改天测一下用了延时,行不行。一般用键盘,按键都要延时5-10毫秒消抖的,正好扫描占用3毫秒,延时消抖3毫秒,效果很好。能满足常规要求。
回复

使用道具 举报

25#
ID:349276 发表于 2024-11-2 12:18 来自手机 | 只看该作者
Graves 发表于 2024-11-1 14:21
temp=KEY_ScanPort;                 //读P1口 读出来跟没有反转之前的采集情况一样,就是高四位有3个1
不 ...

查出来原因了。应该是反复进入扫描循环,等待时间不够,引脚反复处于高低电平变换造成的。
回复

使用道具 举报

26#
ID:349276 发表于 2024-11-2 12:21 来自手机 | 只看该作者
405616736 发表于 2024-11-1 00:48
KEY_ScanPort=0xF0;
******
        KEY_ScanPort=0xFF;//for read  这一句可有可不有,但prote ...

你提醒了我。应该就是延时等待电平稳定。这一句与读准备没关系。就是起了延时作用。
回复

使用道具 举报

27#
ID:1132991 发表于 2024-11-2 13:33 | 只看该作者
万家灯火51 发表于 2024-11-1 18:47
问题解决!!首先非常感谢各位大佬积极出主意和提供经验。看到您们的回复,一下子觉得很踏实。困惑几周的问 ...

当时是搜A2开发板仿真电路才搜到的这个论坛
回复

使用道具 举报

28#
ID:349276 发表于 2024-11-2 23:05 | 只看该作者
hxy52zero 发表于 2024-11-2 13:33
当时是搜A2开发板仿真电路才搜到的这个论坛

用百度白天搜 51黑电子论坛  就能搜到,晚上用这个关键词搜,会出来一堆颜色相关的,且翻几页都找不到这个论坛。我并且截图留证了。百度恶心得很,想搜时又搜不到。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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