简体   繁体   English

如何以atmega 32 pwm控制电机

[英]How to control a motor with atmega 32 pwm

I have been for some time on how to control a motor (control its speed) with fast pwm mode with my atmega32. 我已经有一段时间研究如何使用atmega32以快速pwm模式控制电动机(控制电动机的速度)了。 I need to use the 8-bit Timer0, because i have other uses for the other counters. 我需要使用8位Timer0,因为我还有其他计数器的用途。 I think I know how to inialise the timer for this task: 我想我知道如何为该任务初始化计时器:

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
}

But then comes the problem. 但是随之而来的问题。 I simply don't know what to do next, what to do on my main. 我根本不知道下一步该做什么,我该做什么。

My exact project is to drive a remote controlled car with acceleration. 我确切的项目是驾驶具有加速功能的遥控汽车。 So when I ask from the car to go forward it must accelerate from stop to maximum speed whith fixed acceleration. 因此,当我要求汽车前进时,它必须从停车加速到最大速度,然后再进行固定加速。 I don't know any Assembly, so if you can help me please do it in C. Any help will be much appreciated. 我不知道任何大会,因此如果可以帮助我,请用C语言进行。任何帮助将不胜感激。

Well, I guess you're okay with all port B and C pins being outputs. 好吧,我想您可以将所有端口B和C引脚都输出。 Also, you shouldn't need to do anything in assembly on AVR. 另外,您无需在AVR上进行任何组装。 The assembly-only stuff is available as macros in avr-libc. 仅汇编的内容可在avr-libc中作为宏使用。

Setup 设定

First off, you're setting up TCCR0 wrong. 首先,您设置的TCCR0错误。 You have to set all the bits at once, or you have to use a read-modify-write operation (usually TCCR0 |= _BV(bit_num); to set a bit or TCCR0 &= ~_BV(bit_num); to clear it). 您必须一次设置所有位,或者必须使用读-修改-写操作(通常是TCCR0 |= _BV(bit_num);设置一个位,或设置TCCR0 &= ~_BV(bit_num);清除它) 。 ( _BV(N) is an avr-libc macro that's more legible than the (1<<N) stuff you're using, but does the same thing.) Also, you're missing the polarity of your PWM output, set by the COM00 and COM01 bits. _BV(N)是一个avr-libc宏,它比您使用的(1<<N)东西更清晰,但具有相同的作用。)而且,您缺少PWM输出的极性,由COM00和COM01位。 Right now you have them (implicitly) disabled PWM output (OC0 disconnected). 现在,您(隐式地)使它们禁用了PWM输出(断开了OC0)。

So I'm going to assume you want a positive-going PWM, ie larger PWM input values result in larger high-output duty cycles. 因此,我假设您想要一个正向PWM,即较大的PWM输入值会导致较大的高输出占空比。 This means COM01 needs to be set and COM00 needs to be cleared. 这意味着需要设置COM01 ,并且需要清除COM00 (See pp. 80-81 of the ATmega32(L) data sheet.) This results in the setup line: (请参阅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

Duty Cycle 占空比

Now we get to the actual duty cycle generation. 现在我们开始实际的占空比生成。 Timer 0 is pretty stupid, and hard wires its BOTTOM to 0 and TOP to 0xFF . 计时器0非常愚蠢,并且将其BOTTOM设置为0并将TOP设置为0xFF This means that each PWM period is PWM_Clock / 256 , and since you set PWM_Clock to CPU_Clock / 1024 , the period is CPU_Clock / 262144 , which is about 33 ms for an 8 MHz CPU clock. 这意味着每个PWM周期为PWM_Clock / 256 ,并且由于将PWM_Clock设置为CPU_Clock / 1024 ,因此该周期为CPU_Clock / 262144 ,对于8 MHz CPU时钟约为33 ms。 So each PWM clock, this counter counts up from 0 to 255, then loops back to 0 and repeats. 因此,每个PWM时钟,该计数器从0计数到255,然后循环回到0并重复。

The actual PWM is generated by the OC circuit per Table 40. For the COM0* setting we have, it says: 实际的PWM由表40的OC电路生成。对于COM0*设置,它表示:

Clear OC0 on compare match, set OC0 at BOTTOM 比较匹配时清除OC0,将BOTTOM设置为OC0

What this means is that each time the counter counts up, it compares the count value to the OCR0 register, and if they match it drives the OC0 output pin to GND. 这意味着每次计数器向上计数时,它都会将计数值与OCR0寄存器进行比较,如果匹配,它将OC0输出引脚驱动至GND。 When the counter wraps around to 0, it drives the pin to VCC. 当计数器回绕为0时,它将引脚驱动至VCC。

So to set the duty cycle, you just write a value corresponding to that duty cycle into OCR0 : 因此,要设置占空比,只需将与该占空比对应的值写入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.

That last case is there to resolve a common problem with PWM: the number of possible duty cycle settings is always one more than the number of count steps. 最后一种情况可以解决PWM的一个常见问题:可能的占空比设置数总是比计数步数多一。 In this case, there are 256 steps, and if the output could be VCC for 0, 1, 2, … 256 of those steps, that gives 257 options. 在这种情况下,有256个步骤,并且如果对于这些步骤中的0、1、2…256的输出可能是VCC,则提供257个选项。 So rather than prevent either the 0% or 100% case, they make the one-shy-of-100% case disappear. 因此,它们使100%害羞的情况消失了,而不是防止0%或100%的情况发生。 Note 1 on Table 40 says: 表40的注1表示:

A special case occurs when OCR0 equals TOP and COM01 is set. 当OCR0等于TOP并且设置了COM01时,会发生一种特殊情况。 In this case, the compare match is ignored, but the set or clear is done at BOTTOM. 在这种情况下,比较匹配将被忽略,但设置或清除在BOTTOM处完成。

One more thing: if you write to OCR0 in the middle of a PWM cycle, it just waits until the next cycle. 还有一件事:如果在PWM周期的中间写入OCR0 ,它只会等到下一个周期。

Simulating Acceleration 模拟加速度

Now to get the "constant acceleration" you want, you need to have some kind of standard time base. 现在,要获得所需的“恒定加速度”,您需要具有某种标准时基。 The TOV0 (timer 0 overflow) interrupt might work, or you could use another of the timers or some kind of external reference. TOV0 (定时器0溢出)中断可能起作用,或者您可以使用其他定时器或某种外部参考。 You'll use this standard time base to know when to update OCR0 . 您将使用此标准时基来知道何时更新OCR0

Constant acceleration just means that the speed changes linearly with time. 恒定的加速度仅表示速度随时间线性变化。 Taking this a step further, it means that for each update event, you need to change the speed by a constant amount. 更进一步,这意味着对于每个更新事件,您需要将速度更改为恒定值。 This is probably nothing more than saturation arithmetic : 这可能仅仅是饱和算法

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

Just do something like this for each time step and you'll get constant acceleration. 只需对每个时间步执行这样的操作,您将获得恒定的加速度。 A similar algorithm can be used for deceleration, and you could even use fancier algorithms to simulate nonlinear functions or to compensate for the fact that the motor does not instantly go to the PWM-specified speed. 可以使用类似的算法进行减速,甚至可以使用更高级的算法来模拟非线性函数或补偿电动机无法立即达到PWM规定速度的事实。

As you seem to be a beginner on AVR programming, I suggest you go the easy way: start with Arduino . 您似乎是AVR编程的初学者,所以我建议您采用简单的方法: 从Arduino开始

The Arduino environment offers simple functions so you don't need to manipulate the processor registers directly. Arduino环境提供了简单的功能,因此您无需直接操作处理器寄存器。 For instance, to control a PWM output, you simply have to call analogWrite() ( documentation here ) 例如,要控制PWM输出,您只需要调用analogWrite()此处的文档

Here is a tutorial to hook up a motor to an Arduino . 这是将电动机连接到Arduino的教程

Here is a tutorial to program a ATMega32 from Arduino IDE 这是从Arduino IDE编程ATMega32的教程

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM