找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12457|回复: 25
收起左侧

一道单片机题,控制两个LED灯轮流亮灭,求大佬给个大致算法

  [复制链接]
ID:417624 发表于 2018-10-29 23:08 | 显示全部楼层 |阅读模式
要求实现以下要求:(STC89C51单片机板子)
1.控制两个LED灯轮流亮灭;
2.初始设定A灯与B灯等时间亮灭,A灯点亮时间+B灯点亮时间=1s;
3.随后A灯点亮时间逐渐增加,B灯点亮时间逐渐减少,当B灯点亮时间小于某一阙值时,B灯点亮时间增加,同时A灯减少。(每次修改的步进为100ms,门阙值指定为100ms)如此循环;
4.定时器随意,模式随意,尽量不用中断

本人小白,没学几天,资质平庸,刚了一个下午实在想不出,缺一个基本思路,求大佬指教


回复

使用道具 举报

ID:94031 发表于 2018-10-30 08:32 | 显示全部楼层
will(1)
{
if(dir==0) {
    A灯点亮
    延时m秒
    B灯点亮
    延时1-m秒
   m=m+0.1;
   if(m>1){m=1;dir=1}
  }
else
{
    A灯点亮
    延时m秒
    B灯点亮
    延时1-m秒
    m=m-0.1;
   if(m==0){m=0;dir=0}
  }


}


回复

使用道具 举报

ID:320306 发表于 2018-10-30 08:43 | 显示全部楼层
就是A加B等于1S,A的时间到900MS之后,就减小,每次100MS,到100MS之后就增加,不用管B,B就等于1S-A的时间。
回复

使用道具 举报

ID:41713 发表于 2018-10-30 08:48 | 显示全部楼层
用定时器吧,根据晶振,用STC自带的软件算一下初值,还有一个系统的累加计算你要的阙值,判断一下就OK的。具体程序自己想吧,初学者要学会一个功能一个功能的去试,人中找到成就感,并逐步提高。
回复

使用道具 举报

ID:415338 发表于 2018-10-30 08:52 | 显示全部楼层
我觉得简单一点,直接使用if   else再加几个延时就OK了,用定时器的话,外加中断,在中断还是用if else,中断蛮简单的,一一对应就行
回复

使用道具 举报

ID:308437 发表于 2018-10-30 09:05 | 显示全部楼层
你这个定时器都可以不用,A和B都用一个延时函数就可以了。时间改变就是改延时函数的变量
回复

使用道具 举报

ID:417736 发表于 2018-10-30 09:30 | 显示全部楼层
B灯 1S减一次 ,减到 100后 ,下一秒开始增加,A灯减少
回复

使用道具 举报

ID:417727 发表于 2018-10-30 09:30 | 显示全部楼层
延时函数就可以了
回复

使用道具 举报

ID:276663 发表于 2018-10-30 09:36 | 显示全部楼层
  1. //首先你做一个延时函数
  2. void delay_1ms(void);
  3. //然后做一个延时函数
  4. void delay_Nms(unsigned int Value)
  5. {
  6.     while(Value--)delay_1ms();
  7. }

  8. //定义时间变量
  9. unsigned int TimeA=20;
  10. unsigned int TimeB=1000-TimeA;
  11. //定义方向变量
  12. unsigned char Direction = 1;
  13. //然后在主循环里就可以。
  14. while(1)
  15. {
  16.     if(Direction)        // LEDA时间增加
  17.     {           
  18.                 TimeA++;
  19.                 TimeB = 1000-TimeA;
  20.                 if (TimeA>=980)
  21.                 {
  22.                         Direction = 0;
  23.                 }
  24.     }
  25.     else                        // LEDA时间减少   
  26.     {
  27.             TimeA--;
  28.             TimeB = 1000-TimeA;
  29.             if (TimeA <=20)
  30.             {
  31.                     Direction = 1;                   
  32.             }
  33.     }
  34.     LEDA = 0; LEDB = 1;        // A灯亮B灯灭
  35.     delay_Nms(TimeA);
  36.     LEDA = 1; LEDB = 0;        // A灯灭B灯亮
  37.     delay_Nms(TimeB);
  38. }
复制代码
回复

使用道具 举报

ID:276663 发表于 2018-10-30 09:36 | 显示全部楼层
我程序里面写的是步进1ms应该能看懂吧
回复

使用道具 举报

ID:417624 发表于 2018-10-30 10:55 来自手机 | 显示全部楼层
IdeaMing 发表于 2018-10-30 09:36

老哥,延时函数看懂了,但我主要想练一下定时器,如果用定时器的话,应该怎么写呢?(    )
回复

使用道具 举报

ID:417624 发表于 2018-10-30 10:57 来自手机 | 显示全部楼层
zsyzdx 发表于 2018-10-30 08:43
就是A加B等于1S,A的时间到900MS之后,就减小,每次100MS,到100MS之后就增加,不用管B,B就等于1S-A的时间 ...

判断条件怎么设置啊?(((//Д//)))
回复

使用道具 举报

ID:225048 发表于 2018-10-30 11:23 | 显示全部楼层
最简单的就是加个延时
回复

使用道具 举报

ID:225048 发表于 2018-10-30 11:23 | 显示全部楼层
加个延时就好了
回复

使用道具 举报

ID:417841 发表于 2018-10-30 11:39 | 显示全部楼层
will(1)
{
if(dir==0) {
    A灯点亮
    延时m秒
    B灯点亮
    延时1-m秒
   m=m+0.1;
   if(m>1){m=1;dir=1}
  }
else
{
    A灯点亮
    延时m秒
    B灯点亮
    延时1-m秒
    m=m-0.1;
   if(m==0){m=0;dir=0}
  }


}
回复

使用道具 举报

ID:417914 发表于 2018-10-30 15:01 | 显示全部楼层
如果只是单纯的实现题目要求的话,用延时函数就可以,用方法的话还是用学一下定时器中断计时
回复

使用道具 举报

ID:410942 发表于 2018-10-30 17:06 | 显示全部楼层
你或者参照pwm这个程序,然后改改参数CYCLE=600的数值。应该可以的。
/*-----------------------------------------------

------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义

sbit LED0=P1^0;// 用sbit 关键字 定义 LED到P1.0端口,LED是自己任意定义且容易记忆的符号
sbit LED1=P1^1;

void Delay(unsigned int t); //函数声明
/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main (void)
{
                  
unsigned int CYCLE=600,PWM_LOW=0;//定义周期并赋值
while (1)         //主循环
  {
LED0=1;
Delay(60000);        //特意加延时,可以看到熄灭的过程
for(PWM_LOW=1;PWM_LOW<CYCLE;PWM_LOW++){ //PWM_LOW表示低
//电平时间,这个循环中低电平时长从1累加到CYCLE(周期)的值,即600次

                   LED0=0;        //点亮LED  
                   Delay(PWM_LOW);//延时长度,600次循环中从1加至599
                   LED1=1;        //熄灭LED
              Delay(CYCLE-PWM_LOW);//延时长度,600次循环中从599减至1
     
   }
LED0=0;
for(PWM_LOW=CYCLE-1;PWM_LOW>0;PWM_LOW--){ //与逐渐变亮相反的过程

                   LED1=0;
                   Delay(PWM_LOW);
                   LED0=1;
              Delay(CYCLE-PWM_LOW);
     
   }
                     //主循环中添加其他需要一直工作的程序
  }
}
/*------------------------------------------------
延时函数,含有输入参数 unsigned int t,无返回值
unsigned int 是定义无符号整形变量,其值的范围是
0~65535
------------------------------------------------*/
void Delay(unsigned int t)
{
while(--t);
}
回复

使用道具 举报

ID:417624 发表于 2018-10-30 18:02 | 显示全部楼层
这是我编的程序,感觉挺对的,但实际却是两个灯闪烁时间一样,为什么啊?
#include<reg51.h>
#include<stdio.h>

sbit ledA=P2^0;
sbit ledB=P2^1;
typedef unsigned int u16;
typedef unsigned char u8;


void main()
{
u16 i=0;
u16 b=2000;
u16 c=0;
   ledA=0;
   ledB=1;
   TMOD|=0X02;  //工作方式2
   TH0=0X06;        //0.25ms一次
   TL0=0X06;
   TR0=1;
   
           while(1){       
        if(TF0==1)
         {
          TF0=0;
          i++;}

                  while(b<4000){       
                if(i==b){
                i=0;
                ledA=~ledA;
                ledB=~ledB;               
                }
                if(i==4000-b){
                 ledA=~ledA;
                ledB=~ledB;
                i=0;               
                }
                b=b+400;          
        }
         b=b-800;
                   while(b>0){
                 if(i==b) {
                                         i=0;
                ledA=~ledA;
                ledB=~ledB;
               
                }
                if(i==4000-b){
                 ledA=~ledA;
                ledB=~ledB;
                i=0;
                 }
                 b=b-400;
                 } b=b+800;}           }
                        
回复

使用道具 举报

ID:418122 发表于 2018-10-30 19:46 | 显示全部楼层
用个延时函数,在while循环里先点亮再延时再灭掉延时
回复

使用道具 举报

ID:418171 发表于 2018-10-30 21:10 | 显示全部楼层
可以参考SPWM波的程序吧
回复

使用道具 举报

ID:276663 发表于 2018-10-31 09:43 | 显示全部楼层
y352715553 发表于 2018-10-30 10:55
老哥,延时函数看懂了,但我主要想练一下定时器,如果用定时器的话,应该怎么写呢?(    )

你能不能别眼高手低,就用延时的你实现了吗?
然后,你条件里写了,定时器随意。大家都觉得用延时函数就行了。
定时器的话就是把延时用定时器处理。
回复

使用道具 举报

ID:417624 发表于 2018-10-31 12:41 | 显示全部楼层
IdeaMing 发表于 2018-10-31 09:43
你能不能别眼高手低,就用延时的你实现了吗?
然后,你条件里写了,定时器随意。大家都觉得用延时函数就 ...

很抱歉,老哥,是我表意不明,我说的定时器随意是定时器1或定时器0都行,我也不是眼高手低,延时函数的程序我之前就已经编过了。。。
回复

使用道具 举报

ID:375201 发表于 2018-10-31 13:25 | 显示全部楼层
加个延时
回复

使用道具 举报

ID:89515 发表于 2018-10-31 15:32 | 显示全部楼层
y352715553 发表于 2018-10-30 18:02
这是我编的程序,感觉挺对的,但实际却是两个灯闪烁时间一样,为什么啊?
#include
#include

你用查询的方式,那用定时器还有什么意义。……用中断,在中断函数里设定你需要的单位时间,然后在主函数里更改你需要的时间值。但是你的led两个状态时间值不一样,所以必须分开,if-else语句就可以了,在里面设定不同的时间值,并设定一个交替执行的标志就可以。大家都叫你用软件延时函数,因为那样更好理解,而且你这个确实没必要,也没有意义。表面上看起来像模拟PWM,实际上又不是,所以………………
回复

使用道具 举报

ID:418559 发表于 2018-10-31 15:41 | 显示全部楼层
加个延时函数
回复

使用道具 举报

ID:417624 发表于 2018-11-2 12:27 | 显示全部楼层
#include <reg51.h>
#include<math.h>
typedef unsigned int u16;          
typedef unsigned char u8;

sbit led1=P2^0;
sbit led2=P2^1;
u16 b=2000;
u16 shuZu;
u16 ciShu=0;
u16 k;
u16 text[]={0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1,0,(-1),(-2),(-3),(-4),(-5),(-6),(-7),(-8),(-7),(-6),(-5),(-4),(-3),(-2),(-1)};
void InitTimer0(void)
{
TMOD = 0x02;
TH0 = 0x06;
TL0 = 0x06;//0.25ms中断
EA = 1;
ET0 = 1;
TR0 = 1;
}

void main(void)
{
led1=0;
led2=1;
InitTimer0();
while(1);
}
void Timer0Interrupt(void) interrupt 1
{static int i=0;

i++;
if(i==b)
{led1=~led1;
led2=~led2;
i=0;

shuZu=ciShu%32;
k=text[shuZu];
b=b+pow((-1),(ciShu+1))*400*k;
ciShu++;

}
}

终于跑出来了,虽然用了中断。。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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