我一直在研究如何使用我的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 中做。任何帮助将不胜感激。
好吧,我想你对所有端口 B 和 C 引脚都是输出都没问题。此外,您不需要在 AVR 上的汇编中执行任何操作。仅程序集的东西在 avr-libc 中作为宏提供。
设置
首先,您设置了错误的TCCR0。您必须一次设置所有位,或者必须使用读取-修改-写入操作(通常TCCR0 |= _BV(bit_num);
设置位或TCCR0 &= ~_BV(bit_num);
清除它)。(_BV(N)
是一个 avr-libc 宏,它比你正在使用的(1<<N)
的东西更清晰,但做同样的事情。此外,您还缺少由COM00和COM01位设置的PWM输出的极性。现在,您(隐式)禁用了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
,对于8MHz的CPU时钟来说,大约是33毫秒。因此,每个PWM时钟,这个计数器从0计数到255,然后循环回0并重复。
实际PWM由表40中的OC电路产生。对于我们拥有的COM0*
设置,它说:
在比较匹配时清除OC0,在底部设置OC0
这意味着每次计数器计数时,它都会将计数值与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 个步骤,即提供 257 个选项。因此,他们不是阻止0%或100%的情况,而是使100%的案例消失。表40的注1说:
当 OCR0 等于 TOP 并且设置 COM01 时,会出现特殊情况。在这种情况下,比较匹配将被忽略,但设置或清除是在 BOTTOM 完成的。
还有一件事:如果你在PWM周期中间写入OCR0
,它只会等到下一个周期。
模拟加速度
现在要获得您想要的"恒定加速度",您需要有某种标准时基。TOV0
(计时器 0 溢出)中断可能有效,或者您可以使用另一个计时器或某种外部引用。您将使用此标准时基来了解何时更新OCR0
。
恒定加速度只是意味着速度随时间线性变化。更进一步,这意味着对于每个更新事件,您需要将速度更改恒定量。这可能只不过是饱和度算法:
#define kAccelStep 4
void accelerate_step() {
uint8_t x = OCR0;
if(x < (255 - kAccelStep))
OCR0 = x + kAccelStep;
else
OCR0 = 255;
}
只需为每个时间步长做这样的事情,你就会得到恒定的加速度。类似的算法可用于减速,您甚至可以使用更高级的算法来模拟非线性函数或补偿电机不会立即达到PWM指定速度的事实。
由于您似乎是AVR编程的初学者,因此我建议您采用简单的方法:从Arduino开始。
Arduino环境提供了简单的功能,因此您无需直接操作处理器寄存器。例如,要控制PWM输出,您只需调用analogWrite()
(此处的文档)
这是一个将电机连接到Arduino的教程。
这是一个从Arduino IDE编程ATMega32的教程