找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4347|回复: 46
收起左侧

单片机程序只能顺序点亮LED,不能关闭?怎样能够完成?

  [复制链接]
ID:595237 发表于 2020-8-10 00:34 | 显示全部楼层 |阅读模式
#include<reg51.h>  //包含单片机寄存器的头文件
sbit S1=P1^0;     //将S1位定义为P1.0

/************延时us函数************************/
void delayus(unsigned int j )
{

    while(j--);
}

/*********************************************/
/*****************************
函数功能:主函数
*****************************/
void main(void)
{  
   unsigned char i ;
        i=0;                 //将i初始化为0
         
        while(1)
         {
                  if(S1==0)     //如果S1键按下
                   {
                          delayus(5);  //延时一段时间
                          if(S1==0) //如果再次检测到S1键按下
                            i++;    //i自增1

                if(i==5)  //如果i=5,重新将其置为4
                           i=4;
                                
                   }
                 switch(i)   //使用多分支选择语句
                                 {
                                   case 1: P0=0xfe;  //第一个LED亮
                                          delayus(600);
                                                 break;
                                        case 2: P0=0xfc;  //第二个LED亮
                                        delayus(800);
                             break;
                                        case 3:P0=0xf8;   //第三个LED亮
                                      delayus(1000);
                                  break;
                                        case 4:P0=0xf0;   //第四个LED亮
                                      delayus(1200);
                                          break;
                                
default:break;
                                  }

        
                                    }
                                 }




按住S1=0键点亮:第一个LED亮,第二个LED亮,第三个LED亮,第四个LED亮 ,可以。



放开S1=1键关闭:第四个LED灭,第三个LED灭,第二个LED灭,第一个LED灭,加上什么程序,弄了好久不能完成。


回复

使用道具 举报

ID:10193 发表于 2020-8-10 07:48 | 显示全部楼层
放开后i延时自减
回复

使用道具 举报

ID:687146 发表于 2020-8-10 07:52 | 显示全部楼层
你用的总线操,作写入的16进制格式依次是11111110,11111100,11111000......按照你的描述来看你是低电平点亮LED,所以你要熄灭LED的话只需将对应位改成高电平即可,例如你要熄灭第一个灯点亮第二个灯只需要写入0xFD即可。
回复

使用道具 举报

ID:804115 发表于 2020-8-10 08:25 来自手机 | 显示全部楼层
看到这样的代码,不忍直视,先练习一下如何在大循环中对一个任务进行延时而不采用delay这种干扰其它任务的方式。另外,写代码要逐渐形成分层思想。
回复

使用道具 举报

ID:592807 发表于 2020-8-10 08:26 | 显示全部楼层
可能你硬件没弄好,按照你的代码你的P1.0口输入是GND的时候LED灯亮,输入VCC是LED灭。那你的P1.0口是否有接VCC上拉和GND下拉。你这种情应该是你只是接了GND下拉,就是按下按键后P1.0接到GND上,所以灯正常亮,但是按键弹起来后没有接到VCC上拉,P1.0脚处于悬空状态,所以没法灭掉LED灯。
注意:悬空状态不属于高电平也不属于低电平。
回复

使用道具 举报

ID:812807 发表于 2020-8-10 09:37 | 显示全部楼层
加一个松手检测,之后将全部灯的引脚置1
回复

使用道具 举报

ID:332444 发表于 2020-8-10 09:38 | 显示全部楼层
只要了解其工作原理,你就可以随心所欲地控制IO口输出任意高低点平点亮和关闭。
回复

使用道具 举报

ID:332444 发表于 2020-8-10 09:49 | 显示全部楼层
你这个程序是每按下按键则点亮一个LED直到4个LED都点亮,当初次运行程序时4个LED是不亮的,如何实现释放按键就第4个灯灭?因为本来就没亮又如何去灭,灭是对亮而言的。只有当4个LED都亮才能说再次按下按键后从第4个LED开始灭到第1LED灭。所以说思路不清或描述不清。
回复

使用道具 举报

ID:213173 发表于 2020-8-10 10:23 | 显示全部楼层
  1. #include<reg51.h>  //包含单片机寄存器的头文件
  2. sbit S1=P1^0;     //将S1位定义为P1.0

  3. /************延时us函数************************/
  4. void delayus(unsigned int j )
  5. {
  6.     while(j--);
  7. }

  8. /*****************************
  9. 函数功能:主函数
  10. *****************************/
  11. void main(void)
  12. {  
  13.         unsigned char i=0;//将i初始化为0
  14.         while(1)
  15.         {
  16.                 if(S1==0)     //如果S1键按下
  17.                 {
  18.                         delayus(5000);  //延时一段时间
  19.                         if(S1==0) //如果再次检测到S1键按下
  20.                         {
  21.                                 if(i<4)  //加到4为止
  22.                                 {
  23.                                         i++;
  24.                                         P0<<=1;//P0左移1位低位自动补0
  25.                                 }
  26.                                 delayus(25000);//延时约1/4秒
  27.                         }
  28.                 }
  29.                 else     //如果S1键抬起
  30.                 {
  31.                         delayus(5000);  //延时一段时间
  32.                         if(S1==1) //如果再次检测到S1键抬起
  33.                         {
  34.                                 if(i>0)  //减到0为止
  35.                                 {
  36.                                         i--;
  37.                                         P0=P0>>1|0x80;//P0右移1位高位补1
  38.                                 }
  39.                                 delayus(25000);//延时约1/4秒
  40.                         }
  41.                 }
  42.         }
  43. }
复制代码
回复

使用道具 举报

ID:332444 发表于 2020-8-10 10:28 | 显示全部楼层
  1. #include "reg52.h"
  2. unsigned char code DuLiAnJian[]={255,254,252,248,240};
  3. sbit k1=P1^7;
  4. bit k = 0;
  5. void main()
  6. {
  7.         unsigned char wei=0,Xd=0;
  8.         P2=255;初始化端口
  9.         while(1)
  10.         {
  11.                 if(!k1&&!++Xd)按键消抖
  12.                 {
  13.                         k?--wei:++wei;按键操作变量
  14.                         if(wei>=4||!wei)k=~k;
  15.                         P2=DuLiAnJian[wei];控制LED
  16.                         while(!k1);按键释放
  17.                 }
  18.         }
  19. }
复制代码
录像25_转.gif

是否要这样的效果?
回复

使用道具 举报

ID:478073 发表于 2020-8-10 11:05 | 显示全部楼层
不是加什么程序的问题,是你设的值不对,你的值是依次是原来亮过的反向值
回复

使用道具 举报

ID:280512 发表于 2020-8-10 11:14 | 显示全部楼层
delayus();  p0=0xff; break;可以吧
回复

使用道具 举报

ID:595237 发表于 2020-8-11 08:13 | 显示全部楼层
谢谢你们的帮助,还是不能解决 题目的 要求,看看题目也不是好难的,就是调试不出来。

按键已经上拉10K  接  +   ,

按住按键=0 保持,不放开,  LED1亮,延时, LED2亮,延时, LED3亮,延时, LED4亮。

放开按键=1  , LED4灭,延时, LED3灭,延时, LED2灭,延时, LED1灭。
回复

使用道具 举报

ID:595237 发表于 2020-8-11 08:14 | 显示全部楼层

调试了,只是点亮led1,下面不会递加,没有反应。
回复

使用道具 举报

ID:595237 发表于 2020-8-11 08:14 | 显示全部楼层
xianfajushi 发表于 2020-8-10 10:28
是否要这样的效果?

调试了,按键按一次,点亮一次,点亮完成,按键再按一次 灭一次,

就是不会自动点亮,自动灭。
回复

使用道具 举报

ID:595237 发表于 2020-8-11 08:18 | 显示全部楼层
黄youhui 发表于 2020-8-10 08:26
可能你硬件没弄好,按照你的代码你的P1.0口输入是GND的时候LED灯亮,输入VCC是LED灭。那你的P1.0口是否有接 ...

按键已经上拉10K  接  +   ,

p0口接  LED   - 负    接 电阻 接 +   。
回复

使用道具 举报

ID:595237 发表于 2020-8-11 08:29 | 显示全部楼层
2538076292 发表于 2020-8-10 07:52
你用的总线操,作写入的16进制格式依次是11111110,11111100,11111000......按照你的描述来看你是低电平点亮 ...

111111111,11111110,11111100,11111000,11110000

11110000,11111000,11111100,11111110,111111111
回复

使用道具 举报

ID:332444 发表于 2020-8-11 09:22 | 显示全部楼层
按键按住自动递增,释放自动递减。
  1. #include "reg52.h"
  2. unsigned char code DuLiAnJian[]={255,254,252,248,240};
  3. sbit k1=P1^7;
  4. bit k = 0;
  5. void main()
  6. {
  7.         unsigned char wei=0,Xd=0;
  8.         unsigned int YS=47474;
  9.         P2=255;
  10.         while(1)
  11.         {
  12.                 if(!k1)k=0;else k=1;
  13.                 if(!++YS)
  14.                 {
  15.                         if(wei<4&&!k)++wei;
  16.                         if(wei>0&&k)--wei;
  17.                         P2=DuLiAnJian[wei];
  18.                         YS=k?7474:47474;
  19.                 }
  20.         }
  21. }
复制代码
回复

使用道具 举报

ID:578842 发表于 2020-8-11 11:01 | 显示全部楼层
xianfajushi 发表于 2020-8-11 09:22
按键按住自动递增,释放自动递减。

总工程师厉害,我试过,这个程序对的。
回复

使用道具 举报

ID:332444 发表于 2020-8-11 11:13 | 显示全部楼层
  1. #include "reg52.h"
  2. unsigned char code DuLiAnJian[]={255,254,252,248,240};
  3. sbit k1=P1^7;
  4. bit k = 0;
  5. void main()
  6. {
  7.         unsigned char wei=0,Xd=0;
  8.         unsigned int YS=47474;
  9.         P2=255;
  10.         while(1)
  11.         {
  12.                 if(!++YS)
  13.                 {
  14.                         if(wei<4&&!k1)++wei;
  15.                         else if(wei>0&&k1)--wei;
  16.                         P2=DuLiAnJian[wei];
  17.                         YS=k1?27474:47474;
  18.                 }
  19.         }
  20. }
复制代码

影响延时参数
回复

使用道具 举报

ID:813259 发表于 2020-8-11 16:00 来自手机 | 显示全部楼层
那你就在最后加上P0=0xff就好了
回复

使用道具 举报

ID:595237 发表于 2020-8-11 17:36 | 显示全部楼层

总工程师厉害,调试过了,能够用,就延时改了好久,难调出?
回复

使用道具 举报

ID:332444 发表于 2020-8-11 18:23 | 显示全部楼层
YS=k1?474:747;
回复

使用道具 举报

ID:332444 发表于 2020-8-11 18:34 | 显示全部楼层
如果充分理解程序,调节延时时间这点小技巧不该被难住。
回复

使用道具 举报

ID:332444 发表于 2020-8-11 18:43 | 显示全部楼层
应当理解程序,不当只会复制粘贴运行看效果。
回复

使用道具 举报

ID:332444 发表于 2020-8-12 05:03 | 显示全部楼层
假如 if(!++YS)不好理解不妨用 if(!--YS)再调节YS=k1?474:747;值或许好理解些,体会知识点的应用。
回复

使用道具 举报

ID:332444 发表于 2020-8-12 05:22 | 显示全部楼层
如果YS=k1?4:7;还是时间不够长,可设另一个变量予以延长延时时间用即可,如普通的嵌套循环一样道理,YS计数完毕令另设的变量计数,当另设变量计数达到数值才执行功能语句即可。
回复

使用道具 举报

ID:332444 发表于 2020-8-12 07:26 | 显示全部楼层
if(!++YS&&!++Xd)修改成这样看看时间够长?
回复

使用道具 举报

ID:599260 发表于 2020-8-12 15:22 | 显示全部楼层
你设的值不对,你的值是依次是原来亮过的反向值
回复

使用道具 举报

ID:595237 发表于 2020-8-12 22:21 | 显示全部楼层
xianfajushi 发表于 2020-8-12 07:26
if(!++YS&&!++Xd)修改成这样看看时间够长?

谢谢指点!

晚上调试一下 ,一直用快速计算 i, j  ,k 延时,
比如晶振12mhz ,   i-6,j=116,k=214   ,时间50000us
11.0592mhz,i=22,j=36,k=173,时间50000us,

新接触这样的延时,不懂调到需要的值。
回复

使用道具 举报

ID:595237 发表于 2020-8-12 23:55 | 显示全部楼层
xianfajushi 发表于 2020-8-12 07:26
if(!++YS&&!++Xd)修改成这样看看时间够长?

if(!++YS&&!++Xd)     不起用处,第一个LED也不亮,

if(!--YS)    能够用   47474 延时最长,也不够,

if(!++YS) 能够用   1   延时最长,也不够,

i=211,j-255,k=255  晶振11.0592Mhz   可以延时  5s
回复

使用道具 举报

ID:332444 发表于 2020-8-13 06:05 | 显示全部楼层
通常作为演示一个INT足够了,要达到秒的延时最好用定时器,因为计数延时是无法准确的;
YS=0,Xd=0;if(!++YS&&!++Xd) 这样写等于65536*255这个值应该知道,if(++YS==?&&++Xd==?)  都是可以随意的
if(!++YS){if(!++Xd) {。。。}}看来你的学习还任重道远,其实这些都是基本语句和逻辑,之上已经说得明白,还可以继续嵌套延时if(!++YS){if(!++Xd) {if()++d=={。。。}}}达到延时目标,不过一个CHAR一个INT变量达到5秒应该足够。
回复

使用道具 举报

ID:332444 发表于 2020-8-13 06:24 | 显示全部楼层
if(!++YS&&!++Xd)     不起用处,第一个LED也不亮,这个不是不能用而是延时超出了你预期等待的时间了,最大值为65536*255,可用一个开关替代按键测试到底这个值能延时多长时间。

if(!--YS)    能够用   47474 延时最长,也不够,这个值不是最长65536才最长

if(!++YS) 能够用   1   延时最长,也不够,这个值为0才最长

虽然看起来有点吹毛求疵,不过丽是这样的分析。
回复

使用道具 举报

ID:213173 发表于 2020-8-13 08:30 | 显示全部楼层
juncedz 发表于 2020-8-11 08:14
调试了,只是点亮led1,下面不会递加,没有反应。

这是经过验证的程序你还玩不转,说明你的硬件电路有问题。
回复

使用道具 举报

ID:136485 发表于 2020-8-13 09:01 | 显示全部楼层
你是按下要一直保持这个状态,还是松开按键就不亮,因为你那循环里只有四种灯点亮的状态,你要关掉的还是在循环里加一个关掉的功能比如if(s1>4){P0=0xFF;}就可以关掉了,你都没有关掉这步,除非你刚上电S1=0灯是不亮的
回复

使用道具 举报

ID:332444 发表于 2020-8-13 09:03 | 显示全部楼层
按纯粹的计数延时计算65536*255=16.7秒*1。08=18秒,12M与11.0592M差不离。而仿真运行到1秒其实实际时间不止1秒,因此,仿真会显得很长时间。
211*255*255还比65536*255小呢,变量占用大小2个是一样的,这些都是可分析的,也是基础知识,莫学无知之辈说用3个CHAR比用1个INT和1个CHAR占用少。
回复

使用道具 举报

ID:332444 发表于 2020-8-13 09:06 | 显示全部楼层
本帖最后由 xianfajushi 于 2020-8-13 09:47 编辑

如果认真计算3个char等同1个int和1个char,256*256*256==65536*256。
回复

使用道具 举报

ID:595237 发表于 2020-8-13 16:46 | 显示全部楼层
xianfajushi 发表于 2020-8-13 09:06
如果认真计算3个char等同1个int和1个char,256*256*256==65536*256。

谢谢你的指教,我真的是菜鸟,只是想学习,
调试delay(5)  的时间是正确的。
void delay(unsigned char time)
{    unsigned char i,j,k;
       while(time--)
        for(k=46;k>0;k--)
        for(j=152;j>0;j--)
        for(i=70;i>0;i--)   
}

delay(5)    差不多 5s


unsigned int YS=47474;
YS=k1?47474:47474;
if(!++YS&&!++Xd)    用这样的差不多延时2分钟,  所以我昨晚说没有亮灯 ,
是我说错了,不是程序错 ,是时间太久,没有亮灯,不会调节到5s。

unsigned int YS=0;
YS=k1?0:0;
if(!++YS&&!++Xd)    也是差不多延时2分钟.
回复

使用道具 举报

ID:595237 发表于 2020-8-13 16:53 | 显示全部楼层
kxcuser 发表于 2020-8-13 09:01
你是按下要一直保持这个状态,还是松开按键就不亮,因为你那循环里只有四种灯点亮的状态,你要关掉的还是在 ...

谢谢,关 也是需要 延 时关 的。
回复

使用道具 举报

ID:595237 发表于 2020-8-13 16:56 | 显示全部楼层
wulin 发表于 2020-8-13 08:30
这是经过验证的程序你还玩不转,说明你的硬件电路有问题。

谢谢,电路绝对没有错,程序也是正确,

就是 延时差不多2分钟,

不懂调节 到5s
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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