找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10367|回复: 15
收起左侧

4个独立按键控制4个LED亮灭的单片机程序问题

  [复制链接]
ID:17109 发表于 2017-10-29 21:05 | 显示全部楼层 |阅读模式
本帖最后由 ll13536121668 于 2017-11-2 17:32 编辑

阿里旺旺图片20171102103509.jpg 4只独立按键控制4只LED亮和灭,按下按键,LED亮,再按下,LED灭。因为我们很多都是按完按键,松开手LED才亮。 我现在是想一按按键,LED就亮或灭,这个又怎么写呢?while(!key1)   ,while(!key2)   ,while(!key3)   ,while(!key4  )这句是松手之后,LED亮或灭,但是,如果去掉这一句松手检测,那按键就不灵活了,有时行,有时不行,有时要按很多次才亮或者灭,请朋友们帮帮忙,要怎样改才正确?谢谢。下面是程序

#include <reg52.h>
//定义一下,方便使用
#define uchar unsigned char
#define uint  unsigned int
sbit key1=P2^4;                //按键1定义
sbit key2=P2^5;                //按键2定义
sbit key3=P2^6;                //按键3定义
sbit key4=P2^7;                //按键4定义
sbit led1=P3^0;                //led1端口
sbit led2=P3^1;                //led2端口
sbit led3=P3^2;                //led3端口
sbit led4=P3^3;            //led4端口
/**************************临时变量定义****************************/
uchar keyflag_1=0;   //按键标志位        
uchar keyflag_2=0;   //按键标志位        
uchar keyflag_3=0;   //按键标志位        
uchar keyflag_4=0;   //按键标志位         
/*************************毫秒延时函数****************************/
void delayms(uint z)
{
        uint x,y;
        for(x=0;x<=76;x++)
                for(y=0;y<=z;y++);
}
/**************************按键扫描子程序****************************/
void keyscan()
{
        if(key1==0)                                //第一个按键按下
        {
                delayms(5);                        //进行短暂延时消除按键的抖动
                if(key1==0)                        //第一个按键确实按下
                {
               
                        keyflag_1++;   //键一按下,标志位加一
                        while(!key1);        //松手检测
                }
        }
        if(keyflag_1==1){led1=0;} //点亮LED1        
        if(keyflag_1==2){led1=1;keyflag_1=0; } //关闭LED1

        if(key2==0)                                //第二个按键按下
        {
                delayms(5);                        //进行短暂延时消除按键的抖动
                if(key2==0)                        //第二个按键确实按下
                {
                           keyflag_2++;   //键一按下,标志位加一
                        while(!key2);        //松手检测
                }
        }
    if(keyflag_2==1){led2=0;} //点亮LED2        
        if(keyflag_2==2){led2=1;keyflag_2=0; } //关闭LED2

        if(key3==0)                                //第三个按键按下
        {
                delayms(5);                        //进行短暂延时消除按键的抖动
                if(key3==0)                        //第三个按键确实按下
                {
                        keyflag_3++;   //键一按下,标志位加一
                        while(!key3);        //松手检测
                }
        }
        if(keyflag_3==1){led3=0;} //点亮LED3        
        if(keyflag_3==2){led3=1;keyflag_3=0; } //关闭LED3

        if(key4==0)                                //第四个按键按下
        {
                delayms(5);                        //进行短暂延时消除按键的抖动
                if(key4==0)                        //第四个按键确实按下
                {
                        keyflag_4++;   //键一按下,标志位加一
                        while(!key4);        //松手检测
                }
        }
        if(keyflag_4==1){led4=0;} //点亮LED4        
        if(keyflag_4==2){led4=1;keyflag_4=0; } //关闭LED4
}
void main()
{
        while(1)        //程序循环执行
        {
                keyscan();                //按键扫描,子函数

        }
}


学习4路无线开关.zip

68.86 KB, 下载次数: 14

遥控学习.pdf

50.62 KB, 下载次数: 9

回复

使用道具 举报

ID:10193 发表于 2017-10-29 22:12 | 显示全部楼层
每次按键被识别后,执行lled1-4取反不就可以了吗?
回复

使用道具 举报

ID:10193 发表于 2017-10-29 22:15 | 显示全部楼层
uchar keyflag_1=0;   //按键标志位        
uchar keyflag_2=0;   //按键标志位        
uchar keyflag_3=0;   //按键标志位        
uchar keyflag_4=0;   //按键标志位       这些变量定义的类型也有问题,第三次key_flag==3怎么执行?
回复

使用道具 举报

ID:242952 发表于 2017-10-29 22:23 | 显示全部楼层
很好,很好,很好啊。
回复

使用道具 举报

ID:17109 发表于 2017-10-30 09:12 | 显示全部楼层
gb302 发表于 2017-10-29 22:12
每次按键被识别后,执行lled1-4取反不就可以了吗?

要什样取反执行lled1-4 呢
回复

使用道具 举报

ID:212797 发表于 2017-10-30 09:12 | 显示全部楼层
学习了新思路。在这我也分享一下我通常处理这种问题的方法:
1、如果只有亮灭两种情况的话,可以考虑使用LED = ~LED;
2、如果情况大于三种以上,可以考虑求余方法,key_count % 3 == 0;key_count % 3 == 1;key_count % 3 == 2;
回复

使用道具 举报

ID:17109 发表于 2017-10-30 09:16 | 显示全部楼层
gb302 发表于 2017-10-29 22:12
每次按键被识别后,执行lled1-4取反不就可以了吗?

可以俢改后截图看看吗
回复

使用道具 举报

ID:213173 发表于 2017-10-30 11:29 | 显示全部楼层
不用写那么多,给你改了一下,你试试。
#include <reg52.h>
//定义一下,方便使用
#define uchar unsigned char
#define uint  unsigned int
//sbit key1=P2^4;                //按键1定义
//sbit key2=P2^5;                //按键2定义
//sbit key3=P2^6;                //按键3定义
//sbit key4=P2^7;                //按键4定义
sbit led1=P3^0;                //led1端口
sbit led2=P3^1;                //led2端口
sbit led3=P3^2;                //led3端口
sbit led4=P3^3;                    //led4端口

void keyscan()                                        //按键扫描程序
{
        static bit sign=0;                //按键有效标志
        static uint count=0;                //消抖计数变量                       
        uchar num=0;                                //临时变量
        if((P2&0xf0)!=0xf0)        //检测按键有效
        {
                count++;                                //消抖计数
                if(count>=500)                        //100~1000,根据主循环周期调整约10~20ms
                {                       
                        count=500;
                        if(sign==0)                //测试按键有效标志0
                        {
                                sign=1;                                //按键有效标志置1
                                num=(P2&0xf0);                //保存P2高4位值xxxx 0000,x为0或1
                                switch(num)
                                {
                                        case 0xe0: led1=~led1; break;
                                        case 0xd0: led2=~led2; break;
                                        case 0xb0: led3=~led3; break;
                                        case 0x70: led4=~led4; break;
                                        default: break;
                                }
                        }
                }
        }
        else                                                //键抬起
        {
                sign=0;                                //按键有效标志清0
                count=0;                                //消抖计数清0
        }
}

void main()
{

        while(1)        //程序循环执行
        {
                keyscan();   //按键扫描,子函数

        }
}
回复

使用道具 举报

ID:123289 发表于 2017-10-30 19:47 | 显示全部楼层
有此一问,说明楼主并未真正掌握防止键弹动的原理,或者是学习太死板。
建议楼主好好回顾并弄清这个原理,再出手,估计你自己就能解决了。
想不通,可以语音问我。
画出框图,再写程序,试试。
回复

使用道具 举报

ID:244379 发表于 2017-10-30 21:49 | 显示全部楼层
去单片机的书上找
回复

使用道具 举报

ID:244582 发表于 2017-10-31 15:40 | 显示全部楼层
楼主在学习的过程中过于死板了,应灵活的去变通,可以用流程图去分析!
回复

使用道具 举报

ID:213173 发表于 2017-11-2 11:25 | 显示全部楼层
无标题.jpg
回复

使用道具 举报

ID:213173 发表于 2017-11-2 14:07 | 显示全部楼层
//这个程序是按你的电路图和元件编号重新改的,简洁明了,有详细注释。没有读懂前不要改变电路和程序。
#include <reg52.h>
#define uchar unsigned char
#define uint  unsigned int
#define key (P1 & 0x0f)                                //按键端口宏定义(P1的低4位)
//sbit key1=P1^3;                //按键1定义
//sbit key2=P1^2;                //按键2定义
//sbit key3=P1^1;                //按键3定义
//sbit key4=P1^0;                //按键4定义
sbit led1=P1^4;                //led1端口
sbit led2=P1^5;                //led2端口
sbit led3=P1^6;                //led3端口
sbit led4=P1^7;                //led4端口

void keyscan()                //按键扫描程序
{
        static bit sign=0;        //按键有效标志
        static uint count=0;      //消抖计数变量                        
        uchar num=0;              //临时变量
        if(key!=0x0f)                        //检测有键按下
        {
                count++;              //消抖计数
                if(count>=1000)        //100~1000,根据主循环周期调整约10~20ms
                {                        
                        count=1000;                        //防止溢出
                        if(sign==0)       //测试按键有效标志0
                        {
                                sign=1;         //按键有效标志置1
                                num=key;        //保存P1低4位值0000 xxxx ,x为0或1
                                switch(num)
                                {
                                        case 0x0e: led4=~led4; break;
                                        case 0x0d: led3=~led3; break;
                                        case 0x0b: led2=~led2; break;
                                        case 0x07: led1=~led1; break;
                                        default: break;
                                }
                        }
                }
        }
        else                    //键抬起
        {
                sign=0;              //按键有效标志清0
                count=0;             //消抖计数清0
        }
}

void main()
{       
        while(1)        //程序循环执行
        {
                keyscan();   //按键扫描,子函数       
        }
}
回复

使用道具 举报

ID:243394 发表于 2017-11-2 15:29 | 显示全部楼层
C语言不会,汇编的话是在判断按键有没有放开,没有放开就去执行亮灯程序,然后在回来判断按键有没有放开,放开就执行下一条程序。
回复

使用道具 举报

ID:47286 发表于 2017-11-2 15:53 | 显示全部楼层
不用while等待按键松开 直接写个死延时 用for 死等20ms然后看按键状态 如果还是按下 就认为有效 然后执行led亮或灭 这样就和你是否松开按键没关系了
回复

使用道具 举报

ID:17109 发表于 2017-11-4 20:57 | 显示全部楼层
dzbj 发表于 2017-11-2 15:53
不用while等待按键松开 直接写个死延时 用for 死等20ms然后看按键状态 如果还是按下 就认为有效 然后执行le ...

这个程序什样改才精准运行呢    楼主能够修改程序粘贴上传看看吗谢谢
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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