【问题标题】:Multiple controls to servo on standard i/o port (ATmega32 AVR)?标准 i/o 端口 (ATmega32 AVR) 上的多个伺服控制?
【发布时间】:2015-10-04 10:14:16
【问题描述】:

我基本上是在按下特定按钮时尝试在多个伺服电机上执行 动作。以下代码工作正常,但只能在多个伺服器上执行单个动作,即当按下按钮 伺服1 移动到 900,伺服2 移动到 1500,否则它们会回到标准位置。

我想要实现的是一组动作,例如当按下按钮时,我希望两个舵机都摆动(0 到 180 到 0(3 个不同的动作))。我尝试使用延迟功能并更改伺服的值,但它不起作用,我假设这是因为延迟变得大于我的快速 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;  
}

我该怎么做呢? 任何帮助表示赞赏。

【问题讨论】:

  • 如果可能的话,我会选择带硬件 PWM 的 MCU。也许您的计时器硬件甚至支持它。至少你应该有一个输出比较功能,它允许在定时器结束时切换一个引脚。在这种情况下,唯一涉及的软件将是重置计时器,而您的 CPU 在此期间可以做其他事情。

标签: embedded avr atmega


【解决方案1】:

您似乎正在使用 Timer1 手动实现 PWM,这意味着您不能像 那样添加延迟,因此,您唯一的选择是实现类似于状态机的东西。

为状态定义一个变量,其中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个周期的等待时间是足够还是太多,但你应该根据你的测试更改time[]表......

还建议使用 2 个开关,一个用于检查条件并相应地更改状态,另一个用于实际执行实际状态的任务……我只是懒了,在一个开关中完成了这两个操作。 ..

同样当您使用枚举时,最好将状态重命名为有意义的名称,例如 STATE_WAIT 或 STATE_POS_180 或 STATE_LOCATION_A...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多