找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1182|回复: 20
收起左侧

求教单片机流水灯开慢到快关时快到慢关闭,不太懂占空比取固定值怎么写?

[复制链接]
ID:1002664 发表于 2022-1-23 16:48 来自手机 | 显示全部楼层 |阅读模式
求教流水灯开慢到快,关快到慢程序思路,试着delay来判断,不懂占空比5%~100%怎么取值固定,小白。流水程序看视频学写的,delay按着一些理解来写的,软件void delay报错不对。。。。

单片机源程序如下:
#include  <reg51.h> // <reg51.h>程序电脑实验  


sbit key1=P3^0;

unsigned char dat1[4]={0xf1,0xf2,0xf4,0xf8};
unsigned char dat2[4]={0xfc,0xf9,0xf3,0xf6};
unsigned char dat3[4]={0xfe,0xfd,0xfb,0xf7};

        
unsigned char MODE;
unsigned int  count;

void delay (unsigned int x);
void mode1(void);
void mode2(void);
void mode3(void);
void keyscan(void);

void main(void)
{
        while(1)
        {
                keyscan();
                switch(MODE)
                {
                        case 0: P0=0xff;break;
                        case 1: mode1();break;
                        case 2: mode2();break;
                        case 3: mode3();break;
                }
                delay(1);
  }
}

void delay(unsigned int x)
{
        unsigned int i,j;
        for(i=0;i<x;i++)
        {
              for(j=0;j<120;j++);//12T
         
        }
}


void mode1(void)
{
        static unsigned char i;
        static unsigned int j;
        P0=dat1;
     for(j=500;j>50;j--)  //慢到快,怎么固定到快?不知道对不对
       if(++j>=50)
        {
                j=50
                i=++i%4;
        }
   {
    MODE=0
   for(j=50;j<50;j++)  //快到慢?关闭?
     if(++j>=50)
    }
}
void mode2(void)
{
        static unsigned char i;
        static unsigned int j;
        P0=dat2;
         for(j=500;j>50;j--)  //慢到快,怎么固定到快?不知道对不对
       if(++j>=50)
        {
                j=50
                i=++i%4;
        }
   {
    MODE=0
   for(j=50;j<50;j++)  //快到慢?关闭?
     if(++j>=50)
    }
}

void mode3(void)
{
        static unsigned char i;
        static unsigned int j;
        P0=dat3;
         for(j=500;j>50;j--)  //慢到快,怎么固定到快?不知道对不对
       if(++j>=50)
        {
                j=50
                i=++i%4;
        }
   {
    MODE=0
   for(j=50;j<50;j++)  //快到慢?关闭?
     if(++j>=50)
    }
}

void keyscan(void)
{
        if(key1==0)
        {
                if(count<501)count++;

                if(count==500)
                {
                        sign=~sign;
                        if(sign)
                        {
                                slow=MODE;
                                MODE=0;
                        }
                        else MODE=slow;
                }
        }   
        else
        {
                if(count>20 && count<500
                {
                        ++MODE;
                        if(MODE>3)
                                MODE=1;
                }
                count=0;
        }   
}
回复

使用道具 举报

ID:624769 发表于 2022-1-23 22:55 | 显示全部楼层
初学单片机,学了流水灯,delay 稍微了解一下即可。
接下来,你应该折腾定时器,研究中断。用这些组合来控制流水灯。
然后,再回过头来,搞花样delay.

不然,你单片机学习的道路,会越走越偏,还会固化思想,在单线程道路上越走越远。
回复

使用道具 举报

ID:474583 发表于 2022-1-23 23:26 | 显示全部楼层
有的MCU有PWM硬件, 可以配置周期和占空比的。如果没有PWM, 只能用GPIO+TIM 配合实现了
回复

使用道具 举报

ID:990881 发表于 2022-1-24 08:41 | 显示全部楼层
代码是不是贴错了,咋感觉看不懂,
for(j=500;j>50;j--)  //慢到快,怎么固定到快?不知道对不对
       if(++j>=50)
        {
                j=50
                i=++i%4;
        }
这个不是就循环一次吗?
  for(j=50;j<50;j++)  //快到慢?关闭?
     if(++j>=50)
这个也是循环一次,两个没区别呀
回复

使用道具 举报

ID:1002664 发表于 2022-1-24 08:58 来自手机 | 显示全部楼层
188610329 发表于 2022-1-23 22:55
初学单片机,学了流水灯,delay 稍微了解一下即可。
接下来,你应该折腾定时器,研究中断。用这些组合来控 ...

哦哦好的,谢谢
回复

使用道具 举报

ID:1002664 发表于 2022-1-24 10:05 | 显示全部楼层
188610329 发表于 2022-1-23 22:55
初学单片机,学了流水灯,delay 稍微了解一下即可。
接下来,你应该折腾定时器,研究中断。用这些组合来控 ...

就是看了学习视频不知道怎么融入进去能给一段融合后的参考下嘛
回复

使用道具 举报

ID:161164 发表于 2022-1-24 14:25 | 显示全部楼层
本帖最后由 lkc8210 于 2022-1-24 21:28 编辑

一步一步来
先弄一个定速流水灯

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295
  5. u16 TMR_XX_ACC;
  6. u8 index = 0;
  7. void main()
  8. {
  9.     while (1)
  10.     {        
  11.                         if(++TMR_XX_ACC >= 10000)
  12.                         {TMR_XX_ACC=0;
  13.                                 P1 = ~(0x01 << index);
  14.                                 index = ++index %8;
  15.                         }
  16.     }
  17. }
复制代码


加一个变数变成加速流水灯

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295
  5. u16 TMR_XX_ACC;
  6. u16 TMR_XX_PRE = 10000;
  7. u8 index = 0;
  8. void main()
  9. {
  10.     while (1)
  11.     {        
  12.                         if(++TMR_XX_ACC >= TMR_XX_PRE)
  13.                         {TMR_XX_ACC=0;
  14.                                 P1 = ~(0x01 << index);
  15.                                 index = ++index %8;
  16.                                 if(index==0)
  17.                                         if(TMR_XX_PRE>1000)//固定到快
  18.                                                 TMR_XX_PRE -=500;
  19.                         }
  20.     }
  21. }
复制代码


再来一组LED 1%固定亮度PWM

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295

  5. void delayus(u8 x)
  6. {
  7.         while(x--);
  8. }
  9. void main()
  10. {
  11.     while (1)
  12.     {        
  13.                         P1 = 0;
  14.                         delayus(1);               
  15.                         P1 = 0xFF;
  16.                         delayus(99);                        
  17.     }
  18. }
复制代码


加一个变数变渐亮PWM

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295

  5. u16 TMR_XX_ACC;
  6. u8 PWM = 1;
  7. void delayus(u8 x)
  8. {
  9.         while(x--);
  10. }
  11. void main()
  12. {
  13.     while (1)
  14.     {        
  15.                         P1 = 0;
  16.                         delayus(PWM);               
  17.                         P1 = 0xFF;
  18.                         delayus(100-PWM);
  19.                         if(++TMR_XX_ACC >= 500)
  20.                         {TMR_XX_ACC=0;
  21.                                 if(PWM <99) PWM++;
  22.                         }
  23.     }
  24. }
复制代码


最后把他们合起来

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295

  5. u16 TMR_XX_ACC;
  6. u16 TMR_XX_PRE = 500;
  7. u8 PWM = 1;
  8. u8 index = 0;
  9. void delayus(u8 x)
  10. {
  11.         while(x--);
  12. }
  13. void main()
  14. {
  15.     while (1)
  16.     {        
  17.                         P1 = ~(0x01 << index);
  18.                         delayus(PWM);               
  19.                         P1 = 0xFF;
  20.                         delayus(100-PWM);
  21.                         if(++TMR_XX_ACC >= TMR_XX_PRE)
  22.                         {TMR_XX_ACC=0;
  23.                                 if(PWM <99) PWM++;
  24.                                 index = ++index %8;
  25.                                 if(index==0)
  26.                                         if(TMR_XX_PRE>50)//固定到快
  27.                                                 TMR_XX_PRE -=50;
  28.                         }
  29.     }
  30. }
复制代码
回复

使用道具 举报

ID:1002664 发表于 2022-1-25 23:00 | 显示全部楼层
lkc8210 发表于 2022-1-24 14:25
一步一步来
先弄一个定速流水灯

谢谢 大佬,TMR_XX_ACC是定时器嘛?PWM为什么不用写TH0 ;TL0这些中断,启动也能行?
回复

使用道具 举报

ID:161164 发表于 2022-1-26 09:43 | 显示全部楼层
菜鸟一个622 发表于 2022-1-25 23:00
谢谢 大佬,TMR_XX_ACC是定时器嘛?PWM为什么不用写TH0 ;TL0这些中断,启动也能行?

TMR_XX_ACC是变数,记录系统走了多少个循环
PWM是用定时器中断来写更好,但初入门用delay比较好理解
当你了解了定时器的原理,就可以试试用定时器来写
回复

使用道具 举报

ID:1002664 发表于 2022-1-26 14:52 | 显示全部楼层
lkc8210 发表于 2022-1-26 09:43
TMR_XX_ACC是变数,记录系统走了多少个循环
PWM是用定时器中断来写更好,但初入门用delay比较好理解
当 ...

您的代码好短,能简单实现功能,我看b站学好几天代码一大堆需要的实现不了还出错,如果可以这个开关快慢暗亮是不是可以在 void key里面实现,main里面我直接切换模式?key里面就是消抖按键时长貌似不能,在main里面切换模式,mode里面开关又出问题了,要么开不了,要么关不了。。啊脑子不够了,您有空可以直接写我想的这个程序我看看嘛,开时慢到快暗到亮,可以切换模式,关亮到暗快到慢结束嘛。码代码都懵了,码完keil也没报错就是功能不对大佬私聊消息看看吧
回复

使用道具 举报

ID:161164 发表于 2022-1-26 16:34 | 显示全部楼层
继续加功能

之前弄了由暗到亮由慢到快
现在再加个变数和逻辑来实现由亮到暗由快到慢再关机


  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295
  5. sbit key1=P3^0;
  6. u16 TMR_XX_ACC;
  7. u16 TMR_XX_PRE = 500;
  8. u8 PWM = 1;
  9. u8 index = 0;
  10. bit Power_On = 1;
  11. void delayus(u8 x)
  12. {
  13.         while(x--);
  14. }
  15. void main()
  16. {
  17.         while (1)
  18.         {
  19.                 if(PWM > 0)
  20.                 {
  21.                         P1 = ~(0x01 << index);
  22.                         delayus(PWM);
  23.                 }
  24.                 P1 = 0xFF;
  25.                 delayus(100 - PWM);
  26.                 if(++TMR_XX_ACC >= TMR_XX_PRE)
  27.                 {
  28.                         TMR_XX_ACC = 0;
  29.                         if(Power_On)
  30.                         {
  31.                                 if(PWM < 99)
  32.                                 {
  33.                                         PWM++;
  34.                                 }
  35.                                 else
  36.                                         Power_On = 0;
  37.                         }
  38.                         else
  39.                         {
  40.                                 if(PWM > 0)
  41.                                 {
  42.                                         PWM--;
  43.                                 }
  44.                         }
  45.                         index = ++index % 8;
  46.                         if(index == 0)
  47.                                 if(Power_On)
  48.                                 {
  49.                                         if(TMR_XX_PRE > 50) //固定到快
  50.                                         {
  51.                                                 TMR_XX_PRE -= 50;
  52.                                         }
  53.                                 }
  54.                                 else
  55.                                 {
  56.                                         if(TMR_XX_PRE < 500) //固定到快
  57.                                         {
  58.                                                 TMR_XX_PRE += 50;
  59.                                         }
  60.                                 }
  61.                 }
  62.         }
  63. }
复制代码


加一段按键代码去控制开机还是关机

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295
  5. sbit key1=P3^0;
  6. u16 TMR_XX_ACC;
  7. u16 TMR_XX_PRE = 500;
  8. u8 PWM = 1;
  9. u8 index = 0;
  10. bit Power_On = 1;
  11. void key_Proc()
  12. {
  13.         static u16 Delay_XD=0;                        //消抖计数
  14.         if(!key1)
  15.         {
  16.                 if(Delay_XD<0xFFFF)Delay_XD++;
  17.                 if(Delay_XD==25)                        //消抖
  18.                 {
  19.                         if(!key1)Power_On ^= 1;
  20.                 }
  21.         }
  22.         else                                                        //按键抬起
  23.                 Delay_XD=0;                                        //Delay_XD清0
  24. }
  25. void delayus(u8 x)
  26. {
  27.         while(x--);
  28. }
  29. void main()
  30. {
  31.         while (1)
  32.         {
  33.                 if(PWM > 0)
  34.                 {
  35.                         P1 = ~(0x01 << index);
  36.                         delayus(PWM);
  37.                 }
  38.                 P1 = 0xFF;
  39.                 delayus(100 - PWM);
  40.                 key_Proc();
  41.                 if(++TMR_XX_ACC >= TMR_XX_PRE)
  42.                 {
  43.                         TMR_XX_ACC = 0;
  44.                         if(Power_On)
  45.                         {
  46.                                 if(PWM < 99) PWM++;
  47.                         }
  48.                         else
  49.                         {
  50.                                 if(PWM > 0) PWM--;
  51.                         }
  52.                         index = ++index % 8;
  53.                         if(index == 0)
  54.                                 if(Power_On)
  55.                                 {
  56.                                         if(TMR_XX_PRE > 50) //固定到快
  57.                                         {
  58.                                                 TMR_XX_PRE -= 50;
  59.                                         }
  60.                                 }
  61.                                 else
  62.                                 {
  63.                                         if(TMR_XX_PRE < 500) //固定到快
  64.                                         {
  65.                                                 TMR_XX_PRE += 50;
  66.                                         }
  67.                                 }
  68.                 }
  69.         }
  70. }
复制代码
回复

使用道具 举报

ID:1002664 发表于 2022-1-27 08:46 | 显示全部楼层
lkc8210 发表于 2022-1-26 16:34
继续加功能

之前弄了由暗到亮由慢到快

谢谢大佬 今天又有得琢磨,但是肯定要简单些了
回复

使用道具 举报

ID:908826 发表于 2022-1-27 09:05 | 显示全部楼层
要不先去看看呼吸灯的写法?进阶的玩一下,再回头玩这个,会很简单的,就是编程逻辑和思路的问题
回复

使用道具 举报

ID:1002664 发表于 2022-1-27 13:10 来自手机 | 显示全部楼层
13205495918 发表于 2022-1-27 09:05
要不先去看看呼吸灯的写法?进阶的玩一下,再回头玩这个,会很简单的,就是编程逻辑和思路的问题

呼吸灯会写,但是代码没这个短,怎么固定值,头有点乱
回复

使用道具 举报

ID:1002664 发表于 2022-1-27 14:29 | 显示全部楼层
lkc8210 发表于 2022-1-26 16:34
继续加功能

之前弄了由暗到亮由慢到快

研究懂了,那么切换led亮的颗数能,现在是0x01<<index我保留,增加0x03<<index的亮法,启动不了。。。

void key_Proc()
{
                        count=0;
        if(!key1)
        
        if(key1==0)
        {
                if(count<501)count++;

                if(count==500)//长按
                {
                        ++MODE;
                        if(MODE>3)
                                MODE=1;
                }
                                                               
        }   
        else
        {
                if(count>20 && count<500)//短按
                { Power_On=~Power_On;
                        if(Power_On)
                        {
                                slow=MODE;//保存键值
                                MODE=0;//关闭流水
                        }
                        else MODE=slow;//还原键值
                     
                }
                count=0;
        }                                 
}
void main()
{
    while (1)
     {

           key_Proc();
                                        switch(MODE)
                                        {
                                                case 0: P0=0xFF;break;
                                                case 1: mode1();break;
                                                case 2: mode1();break;
                                        }
         
        }
}

void mode1(void)
{
                   if(PWM > 0)
          {
           P0 = ~(0x01 << index);
          delayus(PWM);
          }
           P0 = 0xFF;
           delayus(100 - PWM);
        if(++TMR_XX_ACC >= TMR_XX_PRE)
             {
              TMR_XX_ACC = 0;
              if(Power_On)
             {
               if(PWM < 99)PWM++;
                                                         
             }
                   else
             {
                  if(PWM > 0) PWM--;
             }
             index = ++index % 8;
          if(index == 0)
          if(Power_On)
      {
         if(TMR_XX_PRE > 50) //固定到快
            {
             TMR_XX_PRE -= 50;
                                                }
       }
                  else
             {
            if(TMR_XX_PRE < 500) //固定到快
             {
              TMR_XX_PRE += 50;
                       }
                    }
                }
                                                        }
回复

使用道具 举报

ID:1002664 发表于 2022-1-27 14:37 | 显示全部楼层
lkc8210 发表于 2022-1-26 16:34
继续加功能

之前弄了由暗到亮由慢到快

我也试着在主程序main里面switch(),case0:直接启动流水,case1:流水模式2 。不行
回复

使用道具 举报

ID:161164 发表于 2022-1-27 22:06 | 显示全部楼层
最后再加上长短按功能和多个流水模式就达成了楼主的要求

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295
  5. sbit key1 = P3 ^ 0;
  6. u16 TMR_XX_ACC;
  7. u16 TMR_XX_PRE = 500;
  8. u8 PWM = 1;
  9. u8 index = 0;
  10. u8 MODE = 1;
  11. bit Power_On = 1;
  12. unsigned char dat1[4] = {0xf1, 0xf2, 0xf4, 0xf8};
  13. unsigned char dat2[4] = {0xfc, 0xf9, 0xf3, 0xf6};
  14. unsigned char dat3[4] = {0xfe, 0xfd, 0xfb, 0xf7};

  15. void key_Proc()
  16. {
  17.     static u16 Delay_XD = 0;                      //消抖计数
  18.     static u16 Min_T = 25;
  19.     static u16 Max_T = 2500;

  20.     if(!key1)
  21.     {
  22.         if(Delay_XD < 0xFFFF)Delay_XD++;
  23.         //else Delay_XD = 0;                //連按功能
  24.         if(Delay_XD == Max_T)                        //长按
  25.         {
  26.             MODE = ++MODE % 3;
  27.         }
  28.     }
  29.     else                                                         //按键抬起
  30.     {
  31.         if(Delay_XD > Min_T && Delay_XD < Max_T)                        //短按
  32.         {
  33.             Power_On ^= 1;
  34.         }
  35.         Delay_XD = 0;                                      //Delay_XD清0
  36.     }
  37. }
  38. void delayus(u8 x)
  39. {
  40.     while(x--);
  41. }
  42. void main()
  43. {
  44.     while (1)
  45.     {   
  46.         if(PWM > 0) {
  47.             switch (MODE)
  48.             {
  49.             case 0:
  50.                 P1 = dat1[index];
  51.                 break;
  52.             case 1:
  53.                 P1 = dat2[index];
  54.                 break;
  55.             case 2:
  56.                 P1 = dat3[index];
  57.                 break;
  58.             }
  59.             delayus(PWM);
  60.         }
  61.         P1 = 0xFF;
  62.         delayus(100 - PWM);
  63.         key_Proc();
  64.         if(++TMR_XX_ACC >= TMR_XX_PRE)
  65.         {   TMR_XX_ACC = 0;
  66.             if(Power_On)
  67.             {
  68.                 if(PWM < 99) PWM++;
  69.             } else {
  70.                 if(PWM > 0) PWM--;
  71.             }
  72.             index = ++index % 4;
  73.             if(index == 0)
  74.                 if(Power_On)
  75.                 {
  76.                     if(TMR_XX_PRE > 50) //固定到快
  77.                     {
  78.                         TMR_XX_PRE -= 50;
  79.                     }
  80.                 } else {
  81.                     if(TMR_XX_PRE < 500) //固定到快
  82.                     {
  83.                         TMR_XX_PRE += 50;
  84.                     }
  85.                 }
  86.         }
  87.     }
  88. }
复制代码
回复

使用道具 举报

ID:161164 发表于 2022-1-27 22:07 | 显示全部楼层
菜鸟一个622 发表于 2022-1-27 14:37
我也试着在主程序main里面switch(),case0:直接启动流水,case1:流水模式2 。不行

放错地方了
回复

使用道具 举报

ID:1002664 发表于 2022-1-28 09:30 | 显示全部楼层

该放那里,大佬
回复

使用道具 举报

ID:1002664 发表于 2022-1-28 10:46 | 显示全部楼层
lkc8210 发表于 2022-1-27 22:06
最后再加上长短按功能和多个流水模式就达成了楼主的要求

谢谢大佬,有的学,来琢磨了
回复

使用道具 举报

ID:161164 发表于 2022-1-28 13:50 | 显示全部楼层

参考我的回覆
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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