【问题标题】:is it possible compare a 16-bit value with a 8-bit compare match ISR是否可以将 16 位值与 8 位比较匹配 ISR 进行比较
【发布时间】:2015-06-10 12:46:36
【问题描述】:

我正在尝试制作一个分辨率比 ATtiny85 8 位定时器/计数器更高的伺服控制器。到目前为止,我已经设法在 21'000 µs 的时间内在我的伺服系统上获得了大约 2000 个位置(1µs/步)。我还设法以不同的速度顺序移动 5 个伺服系统,但现在我想同步移动它们。

我最大的问题是我不知道应该如何实现它!我环顾了其他伺服代码,包括servo8bit库,并试图找到一种方法。似乎大多数示例都使用比较匹配 ISR 来“同时”移动伺服系统,我的问题是我有一个 16 位整数要比较。

有没有办法做一些魔术,以便我可以将 8 位比较匹配 ISR 与我的 16 位整数一起使用?或者你们中有人对我如何在不使用比较匹配 ISR 的情况下同步移动伺服系统有其他建议吗?

我希望我的问题有意义!

因为我还没有真正要显示的代码(只有没有比较匹配 ISR 的有缺陷的尝试没有意义)如果有帮助,我会将链接发布到我的 TinyServo 代码。

编辑 1:

这是我第一次提到但没有发布的代码部分:

void servoMove(void)
{   
uint16_t nextPulse = hPulse[0];

timerSetup ();      //16-bit setup for counter

for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
    if ( (oTime > nextPulse) && (channel < sizeof(servo)/sizeof(servo[0])) )        //check if HIGH pulse (pos) is done
    {
        PORTB &= ~(1 << servo[channel]);

        if (i+1 < sizeof(hPulse)/sizeof(hPulse[0]))
        {
            nextPulse += hPulse[i+1];
        }

        channel++;
    }

    else
    {
        channel = 0;

        oTime = 0;      //resets 16-bit variable
        tot_overflow = 0;       //resets tot_overflow variable  
        TIFR |= (1 << TOV1);        // clear counter1 overflow-flag
        TCNT1 = 0;      //resets Timer/Counter1 
    }

}

for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
    if ( (oTime > tPulse - nextPulse) && (channel < sizeof(servo)/sizeof(servo[0]))   )         //check if LOW pulse (period) is done 
    {   
        PORTB |= (1 << servo[channel]);
        nextPulse -= hPulse[i];
        channel++;  
    }

}

}


void servoPosSet(volatile uint16_t pos[], uint8_t size)
{
     for (i = 0; i < size; i++)
     {
        hPulse[i] = pos[i];
     }

}


int main(void)
{       
TCCR1 |= (1 << CS12);   //set Timer/Counter1 prescaler to increment every 1 µs (PCK/8)

for (channel = 0; channel < size); channel++)
{
    DDRB |= (1 << servo[channel]);  //sets PB0-PB4 as output pins
}

channel = 0;

uint16_t pos[] = {2000, 1500, 1900, 1300, 1700};
uint8_t size = 5;

while(1)        
{
        servoPosSet(pos);

        servoMove();
}

}

编辑 2:

这是我认为代码应该如何工作的说明:

...但事实并非如此!

【问题讨论】:

  • TinyServo 链接中显示的代码并没有直接说明您正在尝试什么不起作用。你应该考虑展示你尝试过的东西,即使正如你所说的那样,它没有任何意义。
  • 您可以使用整数的低 8 位来触发 ISR,在 ISR 中您可以计算它发生了多少次增加另一个 8 位值。如果该值与您的高 8 位匹配,那么您就成功了。
  • @ryyker 我现在发布了代码 ;-)
  • @Nidhoegger - 你能说明你刚才在回答中所说的话吗?
  • @Nidhoegger 附上一张图片来说明上面的代码。你是这个意思吗?

标签: c avr isr attiny


【解决方案1】:

如果您在脉搏期间无事可做,您可以使用忙碌的 循环而不是中断:

#include <avr/io.h>
#include <util/delay_basic.h>

/* Send a pulse of width = 4*count cycles. */
void pulse(uint16_t count, uint8_t channel)
{
    uint8_t mask     = 1 << channel,
            old_port = PORTB,
            high     = old_port | mask,
            low      = old_port & ~mask;

    PORTB = high;
    _delay_loop_2(count);
    PORTB = low;
}

这将为您提供 4 个时钟周期或 0.5 µs 的分辨率 8 MHz 时钟。

向 5 个伺服系统发送脉冲最多需要 10 毫秒。自从 你每 21 毫秒重复一次脉冲序列,这样你就剩下 11 毫秒 计算下一组位置,这应该很多。你可以 设置一个定时器,每 21 毫秒唤醒你一次,然后你的 main() 可能 看起来像:

int main(void)
{
    static uint16_t pos[] = {4000, 3000, 3800, 2600, 3400};
    uint8_t i;

    /* Wake up every 21 ms. */
    setup_timer();
    sleep_enable();

    for (;;) {
        /* Update the servos. */
        for (i = 0; i < 5; i++) pulse(pos[i], i);

        /* Compute the next set of positions. */
        ...

        /* Wait for timer interrupt. */
        sleep_cpu();
    }
}

【讨论】:

  • 这和我前段时间看到的很接近!感觉是对的,但当时没看懂,也没有这个例子那么现场!现在我所要做的就是设法腾出一些时间并打开那里的灯! ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多