我计划用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);
}
}
答案 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()
函数本身就存在问题。