找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2926|回复: 19
收起左侧

单片机呼吸灯程序总是跑飞,C语言全局变量和静态变量的设置,大神们帮忙看看呢

  [复制链接]
回帖奖励 15 黑币 回复本帖可获得 5 黑币奖励! 每人限 1 次
ID:336670 发表于 2022-1-20 23:15 | 显示全部楼层 |阅读模式
这是我自己写的可切换的呼吸灯程序,请大神们帮忙看看中断函数里面的静态变量设置有没有必要呢,还有就是现在可以正常切换,但是开发版上运行的时候偶尔会卡住或者是连着切换,这是怎么回事呢

单片机源程序如下:
/*自由切换呼吸灯小程序*/      
#include"reg51.h"
sbit led_green=P2^0;        //定义绿灯为P2.0端口
sbit led_red  =P2^1;        //定义红灯为P2.1端口
sbit led_switch=P2^7; //按键检测状态灯,当按键按下,此灯点亮
sbit key                        =P3^2;        //定义模式切换开关
unsigned char r=0;                //定义切换变量
unsigned int cycle=800;//定义闪烁频率为800HZ


void delay(unsigned int x)        //延时函数
{
        unsigned int a;
        for(a=x;a>0;a--)
        {
                ;
        }
}


void led_green_flicker()//绿灯闪烁程序
{
        unsigned int a;
        for(a=cycle;a>0;a--)//闪烁频率
        {
                led_green=0;
                delay(a);//灯亮时间,每进入一次FOR循环,绿灯灭的时间减1;
                led_green=1;
                delay(cycle-a);//灯灭时间,每进入一次FOR循环,绿灯亮的时间加1;
        }
        led_green=1;
        delay(50000);
        for(a=cycle;a>0;a--)//闪烁频率
        {
                led_green=1;
                delay(a);//灯亮时间,每进入一次FOR循环,绿灯灭的时间减1;
                led_green=0;
                delay(cycle-a);//灯灭时间,每进入一次FOR循环,绿灯亮的时间加1;
        }
        led_green=0;
        delay(50000);
}
void led_red_flicker()//红灯闪烁程序
{
        unsigned int a;
        for(a=cycle;a>0;a--)//闪烁频率
        {
                led_red=0;
                delay(a);//灯亮时间,每进入一次FOR循环,红灯灭的时间减1;
                led_red=1;
                delay(cycle-a);//灯灭时间,每进入一次FOR循环,红灯亮的时间加1;
        }
        led_red=1;
        delay(50000);
        for(a=cycle;a>0;a--)//闪烁频率
        {
                led_red=1;
                delay(a);//灯亮时间,每进入一次FOR循环,红灯灭的时间减1;
                led_red=0;
                delay(cycle-a);//灯灭时间,每进入一次FOR循环,红灯亮的时间加1;
        }
        led_red=0;
        delay(50000);
}
/**********************
按键延时函数,暂时未用到
***********************
void delay1(        unsigned int a)
{
        while(a--);
}
*/
void main()
{      
        led_green=1;
        led_red=1;
        IT0=1;//跳变沿出发方式(下降沿)
        EX0=1;//打开INT0的中断允许。      
        EA=1;//打开总中断      
        while(1)
        {
                switch(r)                //根据变量选择运行的呼吸灯颜色,闪烁呼吸灯前先熄灭所有LED灯
                {
                        case 0:{P2=0XFF;led_green_flicker();break;}
                        case 1:{P2=0XFF;led_red_flicker();break;}
                        case 2:{P2=0XFF;led_green_flicker();P2=0XFF;;led_red_flicker();P2=0XFF;;break;}
                }
        }
}
void Int0()        interrupt 0//                外部中断0函数,实现按键检测和变量切换
{
        static s;                                        //设置一个静态变量J宫每次进入中断函数都是上一次退出时的值,如果不设置,直接使用全局变量,主函数里switch就不能切换


        if(key==0)
        {
                led_switch=0;                //当检测按键按下,按键状态灯点亮,
                while(!key);                // 当按键松开,按键状态灯熄灭,并且开关切换变量加1;
                led_switch=1;
                        s=s+1;
                        r=s;                                       
                        if(s>=3)
                        {
                                s=0;
                        }
        }
}
回复

使用道具 举报

ID:301191 发表于 2022-1-21 15:25 | 显示全部楼层
顶一下
回复

使用道具 举报

ID:161164 发表于 2022-1-21 15:31 | 显示全部楼层
1. 部分代码被吃了,请重贴
2. 不要用delay!不要用delay!不要用delay!看到delay(50000)就脑壳痛
回复

使用道具 举报

ID:336670 发表于 2022-1-21 18:56 | 显示全部楼层

不要水贴,看到水贴就脑壳痛
回复

使用道具 举报

ID:336670 发表于 2022-1-21 18:57 | 显示全部楼层
lkc8210 发表于 2022-1-21 15:31
1. 部分代码被吃了,请重贴
2. 不要用delay!不要用delay!不要用delay!看到delay(50000)就脑壳痛

我看没有代码被吃呢,还有不用delay()用什么呢
回复

使用道具 举报

ID:161164 发表于 2022-1-21 22:48 | 显示全部楼层
老二不怕黑 发表于 2022-1-21 18:57
我看没有代码被吃呢,还有不用delay()用什么呢

中断函数缺了个"}"

以下是不用Delay和中断的流水灯代码
你可以参考一下
  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 KEY_35 = P3^5;
  6. sbit KEY_36 = P3^6;
  7. sbit KEY_37 = P3^7;
  8. u8 mode = 0;
  9. u16 TMR_XX_PRE = 6000;
  10. void key_Proc()
  11. {
  12.         static u16 Delay_XD=0;
  13.         if(!KEY_35 || !KEY_36 || !KEY_37)
  14.         {
  15.                 if(Delay_XD<0xFFFF)Delay_XD++;
  16.                 if(Delay_XD==250)
  17.                 {
  18.                         if(!KEY_35)
  19.                         {
  20.                                 mode = ++mode %4;                               
  21.                         }
  22.                         if(!KEY_36)
  23.                         {
  24.                                 TMR_XX_PRE -= 500;       
  25.                                 if(TMR_XX_PRE < 1000)TMR_XX_PRE = 1000;                               
  26.                         }
  27.                         if(!KEY_37)
  28.                         {
  29.                                 TMR_XX_PRE += 500;       
  30.                                 if(TMR_XX_PRE > 9000)TMR_XX_PRE = 9000;                               
  31.                         }
  32.                 }
  33.         }
  34.         else
  35.                 Delay_XD = 0;
  36. }
  37. void Led_Flow()
  38. {
  39.         static u16 TMR_XX_ACC;
  40.         static u8 index = 0;
  41.         if(++TMR_XX_ACC >= TMR_XX_PRE)
  42.         {TMR_XX_ACC=0;
  43.                 switch (mode)
  44.                 {
  45.                         case 0:
  46.                                 P1 = ~(0x01 << index);
  47.                                 index = ++index %8;
  48.                                 break;
  49.                         case 1:
  50.                                 P1 = ~(0x80 >> index);
  51.                                 index = ++index %8;
  52.                                 break;
  53.                         case 2:
  54.                                 if(index < 8)
  55.                                         P1 &= ~(0x01 <<index);
  56.                                 else
  57.                                         P1 |= (0x01 <<(index-8));
  58.                                 if(++index >15)
  59.                                 {
  60.                                         index = 0;
  61.                                 }
  62.                                 break;
  63.                 }
  64.         }
  65. }
  66. void main()
  67. {
  68.     while (1)
  69.     {
  70.                         key_Proc();
  71.                         Led_Flow();
  72.     }
  73. }
复制代码
回复

使用道具 举报

ID:453974 发表于 2022-1-25 16:02 | 显示全部楼层
第一点,你需要加一个消除机械抖动的延时,仿真里面没有机械抖动,实物上是有机械抖动的
第二点,感觉你那个静态变量是不必要的,让led_switch自加,然后直接对它进行判断
第三点,感觉你的程序写的很乱,里面延时或者其他的变量有冲突,建议转换一下编程思路或者做好按键按下后变量清除的代码
回复

使用道具 举报

ID:844772 发表于 2022-1-25 16:18 | 显示全部楼层
我也觉得主要问题是按键没有消抖,还有是进入中断没有关中断,抖动导致重复进入,那个静态变量没用,而且又没赋初值。
回复

使用道具 举报

ID:883031 发表于 2022-1-25 17:22 | 显示全部楼层
开关都是有抖动的,需要去抖,不然的话会出现多次出现下降沿,重复中断的现象。或者进入中断后,先将中断关掉,处理完再打开。
回复

使用道具 举报

ID:883242 发表于 2022-1-25 21:17 | 显示全部楼层
static s;  
你确定这句话能通过编译?
回复

使用道具 举报

ID:718536 发表于 2022-1-26 00:14 | 显示全部楼层
PWM调光就不要用硬延时了好不?直接一个震荡周期变量,一个占空比变量。一个增量标志,一个减量标志,例如
  pwm++;
if(pwm>100)
{
pwm=0;
if(max==0){zkb++;}
if(max==1){zkb--;}
if(zkb==100){max=1;}
if{zkb==0}{max=0;}
}
if(pwm>zkb) LED1=0;else LED1=1;
回复

使用道具 举报

ID:336670 发表于 2022-2-8 11:14 来自手机 | 显示全部楼层
suqianfu 发表于 2022-1-26 00:14
PWM调光就不要用硬延时了好不?直接一个震荡周期变量,一个占空比变量。一个增量标志,一个减量标志,例如
...

能帮忙加个注释吗,看起来有点恼火,谢谢咯
回复

使用道具 举报

ID:718536 发表于 2022-3-6 00:37 | 显示全部楼层
void main()     //主循环
{  
  pwm++;           //震荡周期变量
  if(pwm>100)     //如果数值大于100
{
pwm=0;             //周期归零
if(max==0){zkb++;}      //MAX占空比渐加渐减标志位 默认max为0.每一周期占空比渐加
if(max==1){zkb--;}        //MAX占空比渐加渐减标志位 如果max为1.每一周期占空比渐减
if(zkb==100){max=1;}  //如果占空比的值为100      标志位MAX置为1.渐减
if{zkb==0}{max=0;}     //如果占空比的值为0         标志位MAX置为0.渐加
}
if(pwm>zkb){LED1=0;} //判断周期值是否大于占空比,如果大于占空比,LED点亮
else LED1=1;               //否则LED灭灯。
}

这样就可以实现呼吸灯的效果了

这几个关键参数可以在头文件建立,也可以在主循环建立。
回复

使用道具 举报

ID:1008524 发表于 2022-3-6 13:45 | 显示全部楼层
按键消抖这段程序特别重要
回复

使用道具 举报

ID:61261 发表于 2022-3-7 08:31 | 显示全部楼层
有没有进入到死循环的可能呢
回复

使用道具 举报

ID:1009605 发表于 2022-3-11 00:05 | 显示全部楼层
suqianfu 发表于 2022-3-6 00:37
void main()     //主循环
{  
  pwm++;           //震荡周期变量

怎么样才能实现流水的效果呢
回复

使用道具 举报

ID:743654 发表于 2022-3-11 09:10 | 显示全部楼层
/***********************
PWM-呼吸灯
*************************/
#include<reg52.h>

#define led P2

unsigned char t_count ; //累计每个周期中断次数的个数,满20清零,20*100us=2ms(pwm的周期)
unsigned int count ;  //累计占空比需要修改(增加还是减少)的中断次数的个数        1200*100us=120ms
unsigned char t ;  //累计高电平的个数
bit flag ; //标志位 0增加,1减少

void timer0init(void)
{
        EA = 1;
        TMOD = 0X02;
        TH0 = 0Xa3;
        TL0 = 0Xa3;
        ET0 = 1;
        TR0 = 1;
}

void main(void)
{
        t_count = 0;
        count = 0;
        t =10;           //占空比总50%开始
//        led = 1;

        timer0init();
       while(1);
}
/*每100us进入一次中断*/
void timer0() interrupt 1
{
   t_count++;
   count++;

   if(t_count == t)        
    {
             P2 = 0x00;
    }
        if(t_count == 19)
        {
           t_count = 0;
           P2 = 0xff;
        }


        if((count == 1200)&&(flag == 0))
         {
               count = 0;
               t++;
               if(t == 19)        //增加最大占空比 95%
                 {
                   flag = 1;
                 }
         }

        if((count ==1200)&&(flag == 1))
         {
                count = 0;
                     t--;
                    if(t ==10)        //减小到最低占空比 50%
                   {
                         flag = 0;
                   }
     }

}

回复

使用道具 举报

ID:382454 发表于 2022-3-11 16:17 | 显示全部楼层
回复

使用道具 举报

ID:488334 发表于 2022-3-12 03:06 | 显示全部楼层
老二不怕黑 发表于 2022-1-21 18:57
我看没有代码被吃呢,还有不用delay()用什么呢

delay能不用就不用,这个东西对程序来说弊大于利,可以用定时器设置一个时间标志位,当标志位置1了,就可以进去程序里面,否则退出
回复

使用道具 举报

ID:879348 发表于 2022-3-12 11:48 | 显示全部楼层
如果主循环没有阻塞,可以把函数放主循环,不然只能放定时器中断,把lpwm的值控制LED

void showled(void)
{
static byte lpwmcnt=0,lpwm=0;
static byte scnt=0,dir=0;
scnt++;
if(scnt>100)
{
scnt=0;
if(dir)
{if(lpwm<0xff)lpwm++;else dir=0;}
else
{if(lpwm>10)lpwm-=2;else dir=1; }


}

}
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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