如何使用atmega 32 pwm控制电机

时间:2013-10-29 12:09:33

标签: c atmel atmega pwm motordriver

我已经有一段时间了解如何使用我的atmega32以快速pwm模式控制电机(控制其速度)。我需要使用8位Timer0,因为我对其他计数器有其他用途。我想我知道如何将计时器用于此任务:

void initial_io (void){
    DDRC = 0xFF;
    DDRB = 0xFF;
    PORTA = (1<<PA4)|(1<<PA5);
    TCCR0 = (1<<WGM01)|(1<<WGM00); // PWM mode : Fast PWM.
    TCCR0 = (1<<CS02)|(1<<CS00); // PWM clock = CPU_Clock/1024
}

然后问题就出现了。我根本不知道接下来该做什么,在我的主要做什么。

我的确切项目是驾驶加速遥控车。因此,当我从汽车要求前进时,它必须从固定加速度的停止加速到最大速度。我不知道任何大会,所以如果你能帮助我,请在C中做。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:6)

嗯,我想你可以将所有B和C端口作为输出。此外,您不需要在AVR上进行装配。只有汇编的东西在avr-libc中以宏的形式提供。

设置

首先,您将TCCR0设置错误。您必须一次设置所有位,或者必须使用读 - 修改 - 写操作(通常TCCR0 |= _BV(bit_num);设置一个位或TCCR0 &= ~_BV(bit_num);清除它)。 (_BV(N)是一个avr-libc宏,比你正在使用的(1<<N)内容更易读,但做同样的事情。)另外,你错过了PWM输出的极性,由COM00和COM01位设置。现在你有(隐式)禁用PWM输出(OC0断开连接)。

因此,我假设您需要正向PWM,即较大的PWM输入值会导致较大的高输出占空比。这意味着需要设置COM01并且需要清除COM00。 (参见ATmega32(L)数据手册的第80-81页。)这导致设置线:

TCCR0 = _BV(WGM01) | _BV(WGM00) // PWM mode: Fast PWM.
      | _BV(COM01)              // PWM polarity: active high
      | _BV(CS02) | _BV(CS00);  // PWM clock: CPU_Clock / 1024

占空比

现在我们开始实际的工作周期。定时器0非常愚蠢,并将其BOTTOM硬连接到0和TOP到0xFF。这意味着每个PWM周期为PWM_Clock / 256,并且由于您将PWM_Clock设置为CPU_Clock / 1024,因此周期为CPU_Clock / 262144,对于8 MHz CPU时钟约为33 ms。所以每个PWM时钟,该计数器从0到255递增计数,然后循环回0并重复。

实际的PWM由表40中的OC电路产生。对于我们的COM0*设置,它说:

  

比较匹配时清除OC0,将OC0设置为BOTTOM

这意味着每次计数器计数时,它会将计数值与OCR0寄存器进行比较,如果它们匹配则将OC0输出引脚驱动为GND。当计数器回绕到0时,它会将引脚驱动为VCC。

因此,要设置占空比,只需将与该占空比对应的值写入OCR0

OCR0 = 0;   // 0% duty cycle: always GND.
OCR0 = 64;  // 25% duty cycle
OCR0 = 128; // 50% duty cycle
OCR0 = 172; // 67% duty cycle
OCR0 = 255; // 100% duty cycle; always VCC. See below.

最后一种情况是解决PWM的常见问题:可能的占空比设置数总是比计数步数多一个。在这种情况下,有256个步骤,如果输出可以是这些步骤的0,1,2,... 256的VCC,则提供257个选项。因此,不是阻止0%或100%的情况,他们使100%的一个害羞案件消失。表40中的注1表示:

  

当OCR0等于TOP且COM01置位时,会发生特殊情况。在这种情况下,比较匹配被忽略,但是设置或清除在BOTTOM完成。

还有一件事:如果你在PWM周期的中间写入OCR0,它只会等到下一个周期。

模拟加速

现在获得&#34;持续加速&#34;你想要的,你需要有一些标准的时间基础。 TOV0(定时器0溢出)中断可能有效,或者您可以使用另一个定时器或某种外部引用。您将使用此标准时基来了解何时更新OCR0

恒定加速仅意味着速度随时间线性变化。更进一步,这意味着对于每个更新事件,您需要将速度更改为恒定量。这可能只是saturation arithmetic

#define kAccelStep 4
void accelerate_step() {
    uint8_t x = OCR0;
    if(x < (255 - kAccelStep))
        OCR0 = x + kAccelStep;
    else
        OCR0 = 255;
}

每个时间步都要做这样的事情,你会得到不断的加速。类似的算法可用于减速,您甚至可以使用更高级的算法来模拟非线性函数或补偿电机不会立即达到PWM指定速度的事实。

答案 1 :(得分:0)

由于您似乎是AVR编程的初学者,我建议您采用简单的方法:从Arduino开始

Arduino环境提供简单的功能,因此您无需直接操作处理器寄存器。例如,要控制PWM输出,只需调用analogWrite()documentation here

Here is a tutorial to hook up a motor to an Arduino

Here is a tutorial to program a ATMega32 from Arduino IDE