【问题标题】:Setting up multiple timers with AVR使用 AVR 设置多个计时器
【发布时间】:2013-10-13 11:32:38
【问题描述】:

我正在尝试使用 Teensy 2.0 微控制器(基于 ATMEGA32U4 8 位 AVR 16 MHz)设置两个定时器中断例程,以独立控制两个伺服电机

经过多次尝试 - 我能够在端口 C 的引脚 7 上设置一个,但是

  1. 如何设置第二个 ISR 以独立于第一个 ISR 进行初始化和调用?
  2. 我是否需要设置第二个计时器,如果需要,这样的代码应该是什么样的?

这里是设置代码:

int main(void)
{
    DDRE = 0xFF; 

    TCCR1A |= 1 << WGM12;       // Configure timer 1 for CTC mode 
    TCCR1B = (1<<WGM12) | (1<<CS11) ;

    OCR1A = 1000;   // initial            

    TIMSK1 |= 1 << OCIE1A;      // Output Compare A Match Interrupt Enable 
    sei();                      // enable interrupts 

    // ...code that sets pulseWidth based on app logic variable. 
    // Not showing as its not important
}


ISR(TIMER1_COMPA_vect)
{ 
    if (0 == pulseWidth)
    {
        return;
    }

    static uint8_t state = 0;
    int dutyTotal = 20*1000;    

    if (0 == state)
    {
        PORTC |= 0b10000000; 
        OCR1A = pulseWidth; 
        state = 1;
    }
    else if (1 == state)
    {
        PORTC &= 0b01111111; 
        OCR1A = dutyTotal - pulseWidth; 
        state = 0;
    }
}

【问题讨论】:

  • 你想达到什么目的?你不能在同一个 ISR 中实现第二个电机的逻辑吗?看来您只想为每个电机输出一个 PWM。
  • 由于电机需要独立控制,我不确定如何从同一个 IRS 进行操作,因为定时器会根据电机的需要在 ISR 中触发,所以它会当其他电机需要它时不要点火。也许我错过了一些东西。我想我可以将计时器设置为总是每隔 100 微秒触发一次,然后为独立端口实现逻辑,你的意思是?
  • 是的,这就是我的意思。将一个时间设置为多个任务的时间基准并不少见。选择适当的频率。您必须注意 ISR 的代码执行时间永远不会超过 ISR 间隔,否则您将跳过中断并获得不规则的时序。

标签: c timer avr pwm


【解决方案1】:

虽然在不了解您的应用的更多信息的情况下很难给出明确的答案(例如,什么样的伺服/电机 - 我猜是 1-2ms pule 的 RC 型号?)有两种方法可以解决这个问题:

首先,在您的代码中,您似乎是通过切换 PC7 手动生成 PWM 信号。您可以通过增加状态数量来添加另一个输出 - 您需要比伺服器数量多一个来提供设置脉冲重复频率的间隙。当您需要驱动大量舵机时,这是一种常用技术,因为大多数 RC 舵机不关心脉冲相位或频率(在限制范围内),只关心脉冲宽度,因此您可以在之后生成一堆不同的脉冲其他在不同的输出上,而只使用一个像这样的计时器(在一种伪代码状态图中):

State 0:
Turn on output 1
Set timer TOP to pulse duration 1.
Go to state 1:

State 1:
Turn off output 1
Turn on output 2
Set timer TOP to pulse duration 1.
Go to state 2:

State 2:
Turn off output 2
Set timer TOP to pulse duration 3.
Go to state 0:

“脉冲持续时间 3”设置 PRF(脉冲重复频率)。如果你想变得花哨, 您可以将其设置为 1/f-pd1-pd2,以提供恒定频率。

[ “TOP”是 AVR 的说法,用于设置计时器的换行(溢出)率。见数据表。 ]

其次,如果您只使用两个伺服系统,还有一种更简单的方法 - 使用定时器的硬件 PWM 功能。 AVR 定时器具有内置的 PWM 功能,可以为您进行引脚切换。 mega32 上的 Timer1 有两个 PWM 输出引脚,可以很好地用于您的两个伺服系统,然后您根本不需要(必然)需要中断处理程序。 如果您直接使用 PWM 驱动电机(例如通过 H 桥),这也是正确的解决方案。

为此,您需要将定时器置于 PWM 模式并启用 OC1A 和 OC1B 输出引脚,例如

/*
 * Set fast PWM mode on OC1A and OC1B with ICR1 as TOP
 * (Mode 14)
 */
TCCR1A = (1 << WGM11) | (1 << COM1B1) | (1 << COM1A1);
TCCR1B = (3 << WGM12);

/*
 * Clock source internal, pre-scale by 8
 * (i.e. count rate = 2MHz for 16MHz crystal)
 */
TCCR1B |= (1 << CS11);

/*
 * Set counter TOP value to set pulse repetition frequency.
 * E.g. 50Hz (good for RC servos):
 * 2e6/50 = 40000. N.B. This must be less than 65535.
 * We count from t down to 0 so subtract 1 for true freq.
 */
ICR1 = 40000-1;

/* Enable OC1A and OC1B PWM output */
DDRB |= (1 << PB5) | (1 << PB6);

/* Uncomment to enable TIMER1_OVF_vect interrupts at 50Hz */
/* TIMSK1 = (1 << TOV1); */

/*
 * Set both servos to centre (1.5ms pulse).
 * Value for OCR1x is 2000 per ms then subtract one.
 */
OCR1A = 3000-1;
OCR1B = 3000-1;

免责声明 - 此代码片段可以编译,但我尚未在实际设备上对其进行检查,因此您可能需要仔细检查寄存器值。查看完整的数据表http://www.atmel.com/Images/doc7766.pdf

另外,您的代码中可能有一些拼写错误,TCC1A 中不存在位 WGM12(您实际上设置了位 3,即 FOC1A -“强制比较”,请参阅数据表。)另外,您正在编写 DDRE启用端口 E 上的输出,但切换端口 C 上的引脚。

【讨论】:

  • 非常感谢您的解释。
【解决方案2】:

Halzephron,非常感谢您的回答。我没有足够高的声誉来标记您的答案,希望其他人会。

详情如下:

您能够使用单个 IRS 来控制多个伺服系统是绝对正确的 - 令人尴尬的是我没有想到这一点,但考虑到您更简单的解决方案的效果如何 - 我会使用它。

...另外,您正在编写 DDRE 以启用端口 E 上的输出,但切换端口 C 上的引脚。

谢谢,我把那行注释掉了,它的工作原理是一样的——(所以我根本不需要启用输出?)

位 WGM12 在 TCC1A 中不存在(您实际上设置了位 3,即 FOC1A -“强制比较”,请参阅数据表。)

我也删除了它,但保留了我的其余代码不变 - 它导致伺服系统移动更慢,扭矩和抖动更小,即使在到达所需位置后也是如此。伺服器发出一种奇怪的“颤抖”噪音(频率约为 10-20,我会说)和它的手臂颤抖,所以出于我不明白的原因 - 设置这个位似乎是必要的。

我怀疑每个电机的定时器非常不雅,所以我真的很喜欢你的第二种方法(内置定时器生成的 PWM),

...如果您直接使用 PWM 驱动电机(例如通过 H 桥),这也是正确的解决方案。

很好奇,为什么? IE。使用这种方法与定时器生成的 PWM 有什么区别。

在您的代码中,我必须更改下面的行以获得 50HZ,否则我之前得到 25HZ(使用范围验证) ICR1 = 20000-1; // 是 40000 - 1;

我注意到范围的另一件事是,我拥有的定时器生成的 PWM 代码 - 产生的“矩形”形状比您附加的 PWM 代码 sn-p 少。使用我的代码,信号下降到 0 大约需要 0.5 毫秒,而你的代码绝对是瞬时的(这很棒)。这解决了我一直在努力解决的另一个问题:我可以让模拟伺服系统与我的代码(IRS 生成的 PWM)一起正常工作,但是我尝试过的任何数字伺服系统 - 只是没有移动,就好像它坏了一样。我猜信号的形状对于数字伺服系统至关重要,我从来没有在任何地方读过这个。或者可能是我不知道的其他东西。

作为旁注,我花了很多时间在另一个奇怪的地方 - 我取消了 TIMSK1 = (1

再次感谢您的帮助。

【讨论】:

    猜你喜欢
    • 2016-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多