找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4324|回复: 11
收起左侧

51单片机不同的IO口如何组成类似数组的形式

[复制链接]
ID:188773 发表于 2020-4-28 09:22 | 显示全部楼层 |阅读模式
现在有12个IO口作为输入,接的是自锁按键。程序需要扫描这12个IO口的高低状态来执行后续操作,最简单的写法就是定义每个IO口然后直接去一一扫描。如下代码:
sbit keyin1 = P3^4;                        //自锁按键,0按下
sbit keyin2 = P3^5;
sbit keyin3 = P3^0;
sbit keyin4 = P3^1;
sbit keyin5 = P3^2;
sbit keyin6 = P3^3;
sbit keyin7 = P2^0;
sbit keyin8 = P2^1;
sbit keyin9 = P2^2;
sbit keyin10 = P2^7;
sbit test   = P3^6;
sbit mute   = P3^7;                        //轻触按键,0按下


void KeyScanf()
{
        if(keyin1==0)                  //按键1按下
                 ....
         else            //按键1未按下
                 .....

        if(keyin2==0)                  
         ....
         else           
         ......

        if(keyin3==0)                  
                 .....
         else           
                 .....

但是这样感觉代码特别冗余,想问问有没有办法将keyin1-keyin12放到一个数组之类的结构里面,方便进行for循环,减少代码的数量,如下代码KEY[]中装着所有的IO口。
for(n=0;n<13,n++)
                {
                        if(KEY[n]==0)                  //按键1按下
                        ....
                        else            //按键1未按下
                        .....                               
                }




回复

使用道具 举报

ID:584814 发表于 2020-4-28 09:41 | 显示全部楼层
想法灰常地好,你能确定每个按键按下和不按下的功能一样的话直接并上去就好。
当然你也可以做个函数模块,对每个按键进行赋值方便调用。
回复

使用道具 举报

ID:213173 发表于 2020-4-28 11:12 | 显示全部楼层
宏定义端口组即可

#include <reg51.h>

#define Merge_key ((P2>>4&0x08)|(P2&0x07))<<8|P3

void main(void)
{
        unsigned int num;
        while(1)
        {
                num=Merge_key;
                if(num!=0x0fff)
                {
                        switch(num)
                        {
                                case 0x0ffe: /*任务 1*/ break;
                                case 0x0ffd: /*任务 2*/ break;
                                case 0x0ffb: /*任务 3*/ break;
                                case 0x0ff7: /*任务 4*/ break;
                                case 0x0fef: /*任务 5*/ break;
                                case 0x0fdf: /*任务 6*/ break;
                                case 0x0fbf: /*任务 7*/ break;
                                case 0x0f7f: /*任务 8*/ break;
                                case 0x0eff: /*任务 9*/ break;
                                case 0x0dff: /*任务10*/ break;
                                case 0x0bff: /*任务11*/ break;
                                case 0x07ff: /*任务12*/ break;
                                //其它N组合    任务N
                                //......
                                default: break;
                        }       
                }
        }
}
回复

使用道具 举报

ID:188773 发表于 2020-4-28 14:08 | 显示全部楼层
man1234567 发表于 2020-4-28 09:41
想法灰常地好,你能确定每个按键按下和不按下的功能一样的话直接并上去就好。
当然你也可以做个函数模块, ...

好像C51没有位数组,所以很疑惑能不能这样做
回复

使用道具 举报

ID:188773 发表于 2020-4-28 16:29 | 显示全部楼层
wulin 发表于 2020-4-28 11:12
宏定义端口组即可

#include

您这是个很好的思路,我试试宏定义把不同端口放在一起,但是还是要去检测每一位,因为按键是自锁的,可能出现同时1个、2个甚至12个同时按下的情况,switch列举太麻烦了。
回复

使用道具 举报

ID:213173 发表于 2020-4-28 17:56 | 显示全部楼层
guan1989 发表于 2020-4-28 16:29
您这是个很好的思路,我试试宏定义把不同端口放在一起,但是还是要去检测每一位,因为按键是自锁的,可能 ...

可以把键态列一个unsigned int 数组用查表法。
回复

使用道具 举报

ID:328014 发表于 2020-4-28 18:23 | 显示全部楼层
类似问题的解决方案:http://www.51hei.com/bbs/dpj-186076-1.html
回复

使用道具 举报

ID:332444 发表于 2020-4-28 20:30 | 显示全部楼层
12个按键,用8个IO口能组成矩阵16个按键。
回复

使用道具 举报

ID:188773 发表于 2020-4-28 20:58 | 显示全部楼层
51hei团团 发表于 2020-4-28 18:23
类似问题的解决方案:http://www.51hei.com/bbs/dpj-186076-1.html

位结构体和联合体不能用于循环减少代码的长度吧?我的初衷是减少代码长度。
回复

使用道具 举报

ID:188773 发表于 2020-4-28 22:57 | 显示全部楼层
这是我修改后的代码,实现了十二个按键的循环扫描,试运行了下基本逻辑是对的,希望大家帮我看看有什么需要改进的,初学者还有很多不懂的。

#include<reg52.h>
#define bitRead(Y,X) ( ~Y & (1 << (X-1)) )                                                   // 读取 Y 的X位,其他位屏蔽为0,Y的X位为0则X位置为1,否则置位0
#define bitSet(Y,X) Y |= (1 << (X-1))                // Y的X位置1
#define bitClear(Y,X) Y &= ~(1 << (X-1))              // Y的X位置0
#define Merge_key         ((P2>>4&0x08)|(P2&0x07))<<8|P3                 //16位从高位到低位排序位:0 0 0 0 / P2.7        P2.2        P2.1        P2.0        /        P3.7        P3.6        P3.5        P3.4        /        P3.3        P3.2        P3.1        P3.0
/*------------------------------------------------
函数名称:  KEY_Initialise()
函数功能:         按键初始化
入口参数:        
出口参数:         无
备 注:
------------------------------------------------*/
uint data key_alarm=0xff; //按键按下是否生效标志位:LED1,LED2,...lLED10,test,mute,null,null,null,null
uint data key_value=0x00; //实时存储按键按下标志位:LED1,LED2,LED3...LED10,test,mute,LED_ALARM,buzzer,null,null;用于显示和通讯

void KEY_Initialise()                         //KEY1-KEY10,TEST,MUTE
        {
        static uint KEY        ;
        static uchar uckey_num ;
        static uint code KEY_transient[]={0x0001,0x0002,0x0004,0x0008,                //P3.0  P3.1  P3.2  P3.3
                                                                                                                         0x0010,0x0020,0x0040,0x080,                //P3.4  P3.5  P3.6  P3.7
                                                                                                                         0x0100,0x0200,0x0400,0x0800};        //P2.0  P2.1  P2.2  P2.7
        static uchar data keytime_Y[12]={0,0,0,0,0,0,0,0,0,0,0,0};//timeY按下计时消抖 LED1,LED2,...lLED10,test,mute
        static uchar data keytime_N[12]={0,0,0,0,0,0,0,0,0,0,0,0};//timeN未按下计时消抖LED1,LED2,...lLED10,test,mute
        static uchar code Const_Keysnake_time=200;
                                                                                                                         
       
                KEY = Merge_key ;
                if ( KEY != 0X0FFF )
                {
                        for ( uckey_num = 0 ; uckey_num < 13 ; uckey_num ++ )
                        {        uint abc=bitRead ( KEY,uckey_num+1);
                                if ( bitRead ( KEY,uckey_num+1 ) == KEY_transient[uckey_num] )//函数逻辑不对,需确定
                                {
                                        keytime_Y[uckey_num]++;        //按下消抖计时加1
                                        keytime_N[uckey_num]=0;        //未按下消抖计时清零       
                                        if(keytime_Y[uckey_num]>Const_Keysnake_time) //消抖滤波 ,受程序循环影响延时时间,需要程序完成后校准Const_Keysnake_time值
                                                {
                                                keytime_Y[uckey_num]=0;         //按下消抖计时清零
                                                bitSet(key_value,uckey_num+1);        //是否按下标志位
                                                }
                                        }
                                else            //按键1未按下
                                        {
                                        keytime_N[uckey_num]++;                //未按下消抖计时加1
                                        keytime_Y[uckey_num]=0;          //按下消抖计时清零
                                                if(keytime_N[uckey_num]>Const_Keysnake_time)
                                                {
                                                keytime_N[uckey_num]=0;
                                                bitClear(key_value,uckey_num+1);
                                                }
                                        }
                        }
                }
                }
回复

使用道具 举报

ID:188773 发表于 2020-4-28 22:58 | 显示全部楼层
xianfajushi 发表于 2020-4-28 20:30
12个按键,用8个IO口能组成矩阵16个按键。

我的是自锁按键,矩阵按键在同时按下时侦测不了吧
回复

使用道具 举报

ID:188773 发表于 2020-4-28 22:59 | 显示全部楼层
wulin 发表于 2020-4-28 17:56
可以把键态列一个unsigned int 数组用查表法。

我按这个思路写了个,能否帮我看下有没有什么要改的(代码规范,标准,逻辑都可以)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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