biying 发表于 2014-6-20 09:41:48

如何把for循环改为实时系统(已经解决)

本帖最后由 biying 于 2014-6-21 00:04 编辑

有个报警音函数,是用for循环来实现,但这样影响了系统的实时性,我想把它改成实时系统,却遇到这个for循环是有两个初值的呢,大家都是怎么解决的?

void alarm(void)   //报警
{
//static unsigned char k;
TCCR1=0x56;// 开启A路PWM输出
if(alarm_ON==1)//警报音开关
    {
   for(LIGHT=124;LIGHT>82;LIGHT--)//138对应1.8KHZ,70对应3.5KHZ,频率从1.8K到3.5K匀速增加,
   {   
         //OCR1C=LIGHT; //改到溢出中断中修改就不会出爆破音了               
         if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
         {
            OCR1A=(LIGHT/2);
            Even_numbers=0;
         }
         Even_numbers++;   
         delay_ms(6); //         
   }      
      for(LIGHT=82;LIGHT<124;LIGHT++)//138对应1.8KHZ,70对应3.5KHZ,频率从3.5K到1.8K匀速减少,
      {         
         //OCR1C=LIGHT;//改到溢出中断中修改就不会出爆破音了
         if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
         {
            OCR1A=(LIGHT/2);
            Even_numbers=0;
         }
         Even_numbers++;
         delay_ms(6);         
      }         
    }
}

xiaowu191 发表于 2014-6-20 11:44:05

for(LIGHT=124;LIGHT>40;LIGHT--)
{
    if(LIGHT > 82)
    {
      OCR1A=(LIGHT/2);   
    }
    else
    {
      OCR1A=((82 + 82 - LIGHT)/2);
    }
}


这样就是一个初值了

yht0312 发表于 2014-6-20 11:49:08

改实时系统的话,计时就得用外部计时了,主程序每次运行这个报警函数的时候,根据计时变量的值的不同执行不同的动作。

biying 发表于 2014-6-20 15:23:44

xiaowu191 发表于 2014-6-20 11:44
for(LIGHT=124;LIGHT>40;LIGHT--)
{
    if(LIGHT > 82)


谢谢!这是用PWM模拟警报音,频率改变得修改LIGHT值。除以2那个是为了保持50%的占空比。改为实时系统我用T0产生2ms,现在要把for改为if,但for中对LIGHT=124的赋初值不好处理。

biying 发表于 2014-6-20 15:26:55

yht0312 发表于 2014-6-20 11:49
改实时系统的话,计时就得用外部计时了,主程序每次运行这个报警函数的时候,根据计时变量的值的不同执行不 ...

是的,Tiny85,我用T0产生计时,T1做互补PWM,做实时真是麻烦呢!

xiaowu191 发表于 2014-6-20 15:51:40

就是改成2ms调用一次这个函数,是吧

biying 发表于 2014-6-20 16:09:15

xiaowu191 发表于 2014-6-20 15:51
就是改成2ms调用一次这个函数,是吧

不是,原for程序是6ms改变一次LIGHT的值,改实时系统就不能用for死循环了

biying 发表于 2014-6-20 16:11:18

这个报警函数得放主循环里,有报警才跑里面的,在前头有个if开关呢!

kebaojun305 发表于 2014-6-20 16:17:51

改成状态机就可以。

机器人天空 发表于 2014-6-20 16:21:47

状态机可以

xiaowu191 发表于 2014-6-20 16:43:48

uint8_t LIGHT;
       
void alarm(void)                        //报警
{
        static uint8_t time_tick = 0x03;
        static uint8_t index = 0x00;
       
        static uint8_t Even_numbers = 0x00;
       
        //static unsigned char k;
        TCCR1 = 0x56;                        // 开启A路PWM输出
       
        if(alarm_ON != 1)                //警报音开关关
        {
                time_tick = 0x03;
                index = 0x00;
                Even_numbers = 0x00;
        }
        else if(alarm_ON == 1)//警报音开关开
        {
                if(time_tick --)
                {
                        return;                        //没到时间,不执行
                }
               
                time_tick = 0x03;        //2ms * 3 = 6ms
               
                index ++;
               
                if(index > 83)
                {
                        index = 0x00;
                }
               
                if(index <= 41)                               
                {
                        LIGHT = 124 - index;        //124 - 83
                }
                else if(index <= 83)               
                {
                        LIGHT = 40 + index;                //82 - 123
                }
               
                if((Even_numbers ++) & 0x01)
                {
                        OCR1A = LIGHT >> 1;
                }

        }
}

这样可以不?2ms调用一次

rom 发表于 2014-6-20 16:59:56

状态机就行了

hongjie0216 发表于 2014-6-20 18:22:14

虽然上面很多人说了,但是还是要告诉楼主一声,状态机就可以{:lol:}

biying 发表于 2014-6-20 19:40:26

大家说的状态机是不是指马潮老师按键处理的那种程序?

biying 发表于 2014-6-21 00:04:09

搞定了,看起来和原FOR比没有多几行嘛,谢谢大家!不知道还能否再优化
void alarm(void)   //报警 ,频率从1.8K到3.5K匀速增加,然后再从3.5K到1.8K匀速减少,匀速进行,模拟报警音,占空比保持最大保证音量最大
{
static unsigned char alarm_status,initial_a;   
if(alarm_ON==1)//警报音开关
{
   switch (alarm_status)
   {
      case 0:
          if(initial_a==0)    //初始值装载开关,自关闭型
          {
            PWM_Frequency=124; //初始PWM频率
            OCR1A=62;//初始占空比
            initial_a=1;//关闭初始值装载开关
            TCCR1=0x56;// 开启A路PWM输出
            alarm_Delay=0;
          }
          if(alarm_Delay>=3) //6毫秒延时到,步进为2毫秒。加大于是防止万一单片机忙过时。
         {
             alarm_Delay=0;
             if(PWM_Frequency-->82) //频率从1.8K到3.5K匀速增加
            {
                if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
               {
                   OCR1A=(PWM_Frequency/2);
                   Even_numbers=0;
               }
               Even_numbers++;
            }
            elsealarm_status=1;         
         }
         break;         
      case 1:         
          if(alarm_Delay>=3) //6毫秒延时到,步进为2毫秒。加大于是防止万一单片机忙过时。
         {
             alarm_Delay=0;
             if(PWM_Frequency++<124)//频率从3.5K到1.8K匀速减少
            {
                if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
               {
                   OCR1A=(PWM_Frequency/2);
                   Even_numbers=0;
               }
               Even_numbers++;
            }
            elsealarm_status=0;
            if(++alarm_total_time>=250)//报警声总时间=数值X0.012秒,250时为3秒,即:响3秒后自动关闭报警
               {
                alarm_ON=0;//关闭报警开关
                TCCR1=0x00;// 关闭A路PWM输出
                alarm_status=0;
               }         
         }
         break;
      /*   
   for(PWM_Frequency=124;PWM_Frequency>82;PWM_Frequency--)//138对应1.8KHZ,70对应3.5KHZ,频率从1.8K到3.5K匀速增加,
   {   
         //OCR1C=LIGHT; //改到溢出中断中修改就不会出爆破音了               
         if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
         {
            OCR1A=(LIGHT/2);
            Even_numbers=0;
         }
         Even_numbers++;   
         delay_ms(6); //         
   }      
      for(PWM_Frequency=82;PWM_Frequency<124;PWM_Frequency++)//138对应1.8KHZ,70对应3.5KHZ,频率从3.5K到1.8K匀速减少,
      {         
         //OCR1C=LIGHT;//改到溢出中断中修改就不会出爆破音了
         if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
         {
            OCR1A=(PWM_Frequency/2);
            Even_numbers=0;
         }
         Even_numbers++;
         delay_ms(6);         
      }*/      
   }
}
}

biying 发表于 2014-6-21 00:12:08

xiaowu191 发表于 2014-6-20 16:43
这样可以不?2ms调用一次

谢谢,你那23行                        return;                        //没到时间,不执行
是怎么执行的,我没看懂

biying 发表于 2014-6-21 04:33:40

加入节拍速度、报警次数 void alarm(void)   //报警 ,频率从1.8K到3.5K匀速增加,然后再从3.5K到1.8K匀速减少,匀速进行,模拟报警音,占空比保持最大保证音量最大
{
static unsigned char alarm_status,initial_a,i,j;   
if(alarm_ON==1)//警报音开关
{
   switch (alarm_status)
   {
      if(alarm_ON_flag==1)    //新开报警标识,有新的报警指令时为1
          {
            alarm_status=0;
            initial_a=0;
            alarm_ON_flag=0;            
          }
      case 0:
          if(initial_a==0)    //初始值装载开关,自关闭型
          {
            PWM_Frequency=124; //初始PWM频率
            OCR1A=62;//初始占空比
            initial_a=1;//关闭初始值装载开关
            TCCR1=0x56;// 开启A路PWM输出
            alarm_Delay=0;
          }
          if(alarm_Delay>=alarm_Rhythm) //6毫秒延时到,步进为2毫秒。加大于是防止万一单片机忙过时。
         {
             alarm_Delay=0;
             if(PWM_Frequency-->82) //频率从1.8K到3.5K匀速增加
            {
               
                if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
               {
                   Duty_Ratio=(PWM_Frequency/2);
                   Even_numbers=0;
               }
               Even_numbers++;
            }
            elsealarm_status=1;         
         }
         break;         
      case 1:         
          if(alarm_Delay>=alarm_Rhythm) //6毫秒延时到,步进为2毫秒。加大于是防止万一单片机忙过时。
         {
             alarm_Delay=0;
             if(PWM_Frequency++<124)//频率从3.5K到1.8K匀速减少
            {
                if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
               {
                   Duty_Ratio=(PWM_Frequency/2);
                   Even_numbers=0;
               }
               Even_numbers++;
            }
            elsealarm_status=2;
         }
         break;
         case 2:
         if(++j>=alarm_total_time)//报警声总时间=数值X0.012秒,250时为3秒,即:响3秒后自动关闭报警
         {
         alarm_total_time=0;//清零报警总时间               
         initial_a=0;//下次再开报警时再装载初始值
         TCCR1=0x00;// 关闭A路PWM输出
         alarm_status=3;
         }
         elsealarm_status=0;
         break;
         case 3:
         if(alarm_Delay>=alarm_Interval)//报警声间隔,不响的时间
         {
            alarm_Delay=0;
            alarm_status=4;
            
         }
            break;
          case 4:
         if(++i>=alarm_counter)//报警声总时间=数值X0.012秒,250时为3秒,即:响3秒后自动关闭报警
            {
             i=0;
             alarm_ON=0;//关闭报警开关
            }
            elsealarm_status=0;
            break;   
   }
}
}
void alarm_EverySlow(void)//隔1秒慢响一次响3次,无需理会-----预警(单次震动、数错密码)
{
alarm_ON = 1;//开报警
alarm_ON_flag=1;//开报警标示,标示这是一次新的报警
alarm_total_time=1;//响一次为1秒
alarm_Rhythm=6;//节奏快慢
alarm_Interval=500;//间隔1秒响一回
alarm_counter=3;//报警3次
}
void alarm_EveryFast(void)//隔1秒快响一次直到用完电,必须处理-----特急(电瓶断电)
{
alarm_ON = 1;//开报警
alarm_ON_flag=1;//开报警标示,标示这是一次新的报警
alarm_total_time=2;//响一次为1秒
alarm_Rhythm=3;//节奏快慢
alarm_Interval=250;//间隔0.5秒响一回
alarm_counter=3;//报警250次
}

biying 发表于 2014-6-21 16:56:34

修改了以上错误 void alarm(void)   //报警 ,频率从1.8K到3.5K匀速增加,然后再从3.5K到1.8K匀速减少,匀速进行,模拟报警音,占空比保持最大保证音量最大
{
static unsigned char alarm_status,initial_a,i,j;   
if(alarm_ON==1)//警报音开关
{
      if(alarm_ON_flag==1)    //新开报警标识,有新的报警指令时为1
          {
            alarm_status=0;
            initial_a=0;
            alarm_ON_flag=0;            
          }
   switch (alarm_status)
   {
      
      case 0:
          if(initial_a==0)    //初始值装载开关,自关闭型
          {
            PWM_Frequency=124; //初始PWM频率
            OCR1A=62;//初始占空比
            initial_a=1;//关闭初始值装载开关
            TCCR1=0x56;// 开启A路PWM输出
            alarm_Delay=0;
          }
          if(alarm_Delay>=alarm_Rhythm) //6毫秒延时到,步进为2毫秒。加大于是防止万一单片机忙过时。
         {
             alarm_Delay=0;
             if(PWM_Frequency-->82) //频率从1.8K到3.5K匀速增加
            {
               
                if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
               {
                   Duty_Ratio=(PWM_Frequency/2);
                   Even_numbers=0;
               }
               Even_numbers++;
            }
            elsealarm_status=1;         
         }
         break;         
      case 1:         
          if(alarm_Delay>=alarm_Rhythm) //6毫秒延时到,步进为2毫秒。加大于是防止万一单片机忙过时。
         {
             alarm_Delay=0;
             if(PWM_Frequency++<124)//频率从3.5K到1.8K匀速减少
            {
                if(Even_numbers==2)   //偶数判断后计算占空比为一半,保证音量为最大
               {
                   Duty_Ratio=(PWM_Frequency/2);
                   Even_numbers=0;
               }
               Even_numbers++;
            }
            elsealarm_status=2;
         }
         break;
         case 2:
         if(++j>=alarm_total_time)//报警声总时间=数值X0.012秒,250时为3秒,即:响3秒后自动关闭报警
         {
         j=0;//清零报警总时间               
         //initial_a=0;//下次再开报警时再装载初始值
         TCCR1=0x00;// 关闭A路PWM输出
         alarm_status=3;
         }
         elsealarm_status=0;
         break;
         case 3:
         if(alarm_Delay>=alarm_Interval)//报警声间隔,不响的时间
         {
            alarm_Delay=0;
            alarm_status=4;
            
         }
            break;
          case 4:
         if(++i>=alarm_counter)//报警声总时间=数值X0.012秒,250时为3秒,即:响3秒后自动关闭报警
            {
             i=0;
             alarm_ON=0;//关闭报警开关
            }
            else
             {
            alarm_status=0;
            TCCR1=0x56;// 开启A路PWM输出
             }
            break;   
   }
}
}

biying 发表于 2014-6-21 17:15:47

糟了,一不小心i=0;j=0; 没有写入if(alarm_ON_flag==1)    //新开报警标识,有新的报警指令时为1,导致新切换报警音时会碰到少响次数。void alarm(void)   //报警 ,频率从1.8K到3.5K匀速增加,然后再从3.5K到1.8K匀速减少,匀速进行,模拟报警音,占空比保持最大保证音量最大
{
static unsigned char alarm_status,initial_a,i,j;   
if(alarm_ON==1)//警报音开关
{
      if(alarm_ON_flag==1)    //新开报警标识,有新的报警指令时为1
          {
            alarm_status=0;
            initial_a=0;
            alarm_ON_flag=0;
            i=0;
            j=0;            
          }
   switch (alarm_status)
   {
      
      case 0:
页: [1]
查看完整版本: 如何把for循环改为实时系统(已经解决)