如何停止循环并等待从串行接收到不同的值

时间:2014-11-13 21:21:09

标签: c loops serial-port avr

我计划用C和codevision在AVR上用串行控制触发信号进行多伺服控制

但是当触发器为真时,伺服在疯狂循环中运行,它回到原始位置(0度)而不是停留在所需位置,我的导师给我提示使用"等待......直到&# 34;与旧数据比较的声明,但我还没有找到在谷歌上使用它的方法

因为利用休息;在if结束时,芯片冻结直到它重置

和旧代码(它连续不断地运行伺服)

 while (1)
      {           
      while(UCSRA & (1<<RXC))  
          {
      // Place your code here
           //data=UDR;

           PORTC=UDR;
           data=UDR;
           //PORTB=data;
           } ;

          if (data== 0x0A || data== 0x0B)
          {     
                if (data== 0x0A)
                  {     
                        old_data=data;

                        PORTA=0x00;
                        PORTA.1=1;
                        movservo0(90,7);
                        movservo1(15,3);



                   }    

                if (data== 0x0B)
                  {     
                        old_data=data;

                        PORTA=0x00;
                        PORTA.1=1;
                        movservo0(15,3);
                        movservo1(90,7);


                   } 


           }
}

至于movservo0(另一个movservo()几乎有相同的代码)

void set_servo1(unchar derajat)
{   unchar n;

    servo2=1;
    delay_us(750);
    for(n=0; n<derajat; n++)
    {
        delay_us(12);

    };
    servo2=0;
    delay_ms(10);
}

void movservo0(unsigned char sudut, unsigned char speed)
{
     unchar i;
    set_servo1(sudut);
    for (i=1;i<=sudut;i+=speed){
    set_servo1(i);
    delay_ms(100/speed);
    }
}

1 个答案:

答案 0 :(得分:0)

这个新代码好一点。

while(UCSRA & (1<<RXC))循环的顶部就是这样。只有在要读取的字符时才会输入循环体。 (虽然,我不确定您为什么希望阅读&#39; \ n&#39;或垂直标签。)

一个小问题是UDR的读取方式。阅读UDR的行为会删除内容。所以你应该使用

data=UDR;    
PORTC=data;

舵机的跳跃似乎在moveservo()功能中。此功能始终将角度设置为1,然后逐渐增加伺服角度,直至达到所需角度。

setservo()似乎是尝试执行PWM来驱动伺服,但它无法正常工作。为了使伺服保持在所需的角度,你必须在正确的时间将引脚从0切换到1,而不是像这个功能一样。你看过定时器的PWM功能了吗?你只需设置它们,它们就会在后台运行。另一种方法是使用定时器将中断设置为唤醒并根据需要切换引脚。

如果您想在没有中断的情况下切换引脚,那么您应该在while(1)循环中使用延迟。只需使用setservo()函数来更改某些变量。

while(1)
{
    // read the UART if ready and set the target values
    // this part only runs occasionally
    while(UCSRA & (1<<RXC))  
    {
        // etc
    }

    // The rest of the loop body runs every time

    // adjust the servo values toward the target values
    // use a counter to determine if to adjust during this loop iteration
    // e.g., a slow speed counts to a higher number before adjusting

    delay(750);

    for(int i = 0; i < NUM_INTERVALS; ++i)
    {
        // decide whether to set pins to 1 or 0 based on the servo values
        delay(INTERVAL);
    }
} 

我不知道您的特定伺服系统,但它们通常有一段时间,其中大部分时间引脚为0,然后是引脚为1的时间段内的短时间。您需要调整NUM_INTERVALS和INTERVAL以及750加起来正确的时间长度。


这个片段存在很多错误,很难启动。很难说为什么伺服机构正在移动,因为它只是'#34;移动&#34;每次都达到相同的价值。 (除非,您省略了一些将其设置为其他值的代码。)

通常,当接收UART时,处理器应该等到收到字符。这是由

完成的
while(UCSRA & (1<<RXC) == 0);

注意;创建while循环的空体。这可能是你的导师的意思。设置标志后,循环退出,数据就可以读取了。

while(UCSRA & (1<<RXC) == 0);
data = UDR;

接下来,你有一个看起来像是要成为while循环一部分的块,但它不是。循环体是它上面的单个语句。每次都会执行该块。

  {
     if(data=0x0a)
     {
        olddata=data;
        movservo0(90,7); //move servo to certain degree
      }
  }

另一个错误是if语句中的条件。看起来你试图测试data是否为0x0A,但这不是正在发生的事情。相反,您将data设置为0x0A,然后每次都执行内部部分。您可能想要的条件是if(data == 0x0A)。请注意==而不是=

所以你的代码相当于

while(1)
{
  while(ucsra & (1<<RXC)) data=udr; // maybe read UDR into data

  data=0x0a; // set data anyway

  olddata=data;
  movservo0(90,7); //move servo to certain degree
}

同样,对于跳跃伺服,我怀疑这里省略了一些也每次运行的代码。否则,moveservo()函数本身就存在问题。