2015-10-04 61 views
0

我基本上是試圖在一個特定的按鈕pressed.The執行的多個伺服電機動作下面的代碼工作正常,但在多個舵機即當按下按鈕Servo1移至只能執行單一的運動900和伺服2到1500,否則他們回到標準位置。標準I/O端口(ATmega32 AVR)上的多個伺服控制?

我想要實現的是一組動作,例如當按鈕被按下我想同時得到伺服擺動(0到180爲0(3個不同的運動))。我試圖用延時功能,改變伺服的值,但那就不是工作,這IM假設是因爲延遲變得比我快速PWM的時間週期。

void main() 
{ 
DDRB = 0xFF; 
DDRC = 0x00; 
PORTC = 0XFF; 

TCCR1A |= 1<<WGM11; 
TCCR1B |= 1<<WGM12 | 1<<WGM13 | 1<<CS10; 
TIMSK |= 1<<OCIE1A; 

ICR1=19999; 

sei(); 

uint16_t Servo1 = 2000, Servo2 = 900; 

while(1) 
{ 
    if(bit_is_clear(PINC,0)) 
    { 
     Servo1 = 900, Servo2 = 1500; 
    } 
else{ 
    Servo1 = 1500, Servo2=2200; 
} 
    if(TCNT1>=800 && TCNT1<=2400) 
    { 
     if (TCNT1 >= Servo1 && bit_is_set(PORTB,PINB0)) PORTB &= ~(1<<PINB0); 
     if (TCNT1 >= Servo2 && bit_is_set(PORTB,PINB1)) PORTB &= ~(1<<PINB1); 
    } 

} 
} 

ISR(TIMER1_COMPA_vect) 
{ 
PORTB = 0xFF; 
} 

我該怎麼做呢? 任何幫助表示讚賞。

+0

如果可能的話,我會選擇與硬件PWM一個MCU 。也許你的計時器硬件甚至支持它。至少你應該有一個輸出比較功能,它允許在定時器超時時切換一個引腳。在這種情況下,唯一涉及的軟件將會重置定時器,並且您的CPU可以在此期間執行其他操作。 – Lundin

回答

0

看來你正在使用Timer1手動實現你的PWM,這意味着你不能像<util/delay.h>那樣添加延遲,所以你唯一的選擇是實現類似於狀態機的東西。

定義的狀態下STATE0將是等待狀態的變量,STATE1將是第一個運動STATE2第二運動等等...

然後定義一個「時間表」來定義多少時間它會等待每個狀態,(理想情況下應該是一個狀態表,但無論如何...)

enum{ STATE0,STATE1,STATE2};// from 0 to 2 
int time[3]={0,500,500}; //for state 0 it'll wait the button 
volatile int time_counter=0; //needs to be volatile 'cos it's used inside the interrupt 
int state = STATE0; 

void main() 
{ 
DDRB = 0xFF; 
DDRC = 0x00; 
PORTC = 0XFF; 

TCCR1A |= 1<<WGM11; 
TCCR1B |= 1<<WGM12 | 1<<WGM13 | 1<<CS10; 
TIMSK |= 1<<OCIE1A; 

ICR1=19999; 

sei(); 

uint16_t Servo1 = 2000, Servo2 = 900; // are these initial values ok for STATE0? 

while(1) 
{ 
    //eval state 
    switch(state){ 
     case STATE0: 
      if(bit_is_clear(PINC,0)) // if button 
      { 
       //change state 
       state=STATE1; 
       time_counter=0; 
       //do task 
       Servo1 = 900, Servo2 = 1500; 
      } 
     break; 
     case STATE1: 
      if(time_counter>time[state]) 
      { 
       //change state 
       state=STATE2; 
       time_counter=0; 
       //do task 
       Servo1 = 1500, Servo2 = 2200; 
      } 
     break; 
     case STATE2: 
      if(time_counter>time[state]) 
      { 
       //change state 
       state=STATE0; // go to wait the buton again 
       time_counter=0; // not necesary but anyway... 
       //do task 
       Servo1 = 2000, Servo2 = 900; 
      } 

     break; 
    } 
    //do the pwm stuff 
    if(TCNT1>=800 && TCNT1<=2400) 
    { 
     if (TCNT1 >= Servo1 && bit_is_set(PORTB,PINB0)) PORTB &= ~(1<<PINB0); 
     if (TCNT1 >= Servo2 && bit_is_set(PORTB,PINB1)) PORTB &= ~(1<<PINB1); 
    } 

} 
} 

ISR(TIMER1_COMPA_vect) 
{ 
PORTB = 0xFF; 
time_counter++; //here we count the pwm cycles... 
} 

我沒有檢查你的計時器的配置,所以我其實不知道,如果等待時間500個週期應該是足夠或太多,但你應該根據你的測試更改時間[]表...

它也建議使用2個開關,一個來檢查條件並相應地更改狀態,而另一個真正的實際狀態做任務...我只是偷懶和一個開關都沒有.. 。

也可以作爲您使用的是枚舉{},最好您重命名狀態,以soemthing有意義的,就像STATE_WAIT或STATE_POS_180或STATE_LOCATION_A ...