我一直在尝试ATMega328P上的PWM波形生成模式。我得到了一些奇怪的结果,我无法弄清楚它是如何写我的固件或我如何解释datasheet。
这是我为模拟analogWrite()函数编写的第一段代码:
// Waveform Generation Mode 0
// Table 15-4 of the datasheet
void setup()
{
DDRB = (1<<PB1); // set pin 9 as output
TCCR1A |= (1<<COM1A1);
OCR1A = 125;
}
void loop()
{
}
上面的代码从引脚9产生大约2.5V(49%占空比)的平均电压输出。奇怪的是(对我而言)根据数据表,TIMER1是一个16位定时器,所以它应该溢出在65536滴答。根据我的理解,在0到65535之间设置OCR1A将改变脉冲的占空比。因此,将OCR1A设置为125,我不应该得到大约0.01 V而不是2.5V的输出吗?结果似乎暗示时钟在255处溢出。
我第二次涉足PWM领域,我想尝试使用ATMega的快速PWM模式创建一个2.5V信号。这就是我得到的:
// Waveform Generation Mode 14
// Table 15-4 of the datasheet
void setup()
{
DDRB = (1<<PB1);
TCCR1A |= (1<<COM1A1) | (1<<WGM11);
TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS10);
ICR1 = 19999;
OCR1A = 10000;
}
void loop()
{
}
我将ICR1(溢出值)任意设置为20000个刻度,然后将OCR1A(比较值)设置为大约一半。我将通道A设置为非反相模式,但是(我认为)如果我将其设置为反相模式则不会产生影响。当我把它闪存到Arduino上时,我从引脚9获得了一个稳定的5V平均电压(100%占空比),我不能为我的生活找出原因。
我很感激您提供的任何见解。
答案 0 :(得分:2)
joeymorin对AVRfreaks的回答:
请注意,在Uno上,在setup()之前运行的Arduino初始化代码配置了很多东西,包括328P上的所有三个定时器。
来自 wiring.c :
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
sbi(TIMSK0, TOIE0);
sbi(TCCR1B, CS11);
sbi(TCCR1B, CS10);
sbi(TCCR1A, WGM10);
sbi(TCCR2B, CS22);
sbi(TCCR2A, WGM20);
这将使用预分频器64启动所有三个定时器。
TIMER0进入模式3(快速PWM),并启用溢出中断以支持定时功能(millis(),micros()和delay())。
TIMER1置于模式1(固定的8位相位校正PWM)。
TIMER2置于模式1(相位校正PWM)。
void setup()
{
DDRB = (1<<PB1); // set pin 9 as output
TCCR1A |= (1<<COM1A1);
OCR1A = 125;
}
void loop()
{
}
由于TCCR1A中的WGM10已经设置,设置COM1A1将使PWM输出处于非反相模式,就像analogWrite()一样。
TIMER1是一个16位定时器,所以它应该以65536个时钟周期溢出。从 据我所知,将OCR1A设置在0到65535之间会改变 脉冲的占空比。所以,将OCR1A设置为125,我不应该 得到大约0.01 V而不是2.5V的输出?结果 似乎暗示时钟在255处溢出。
在模式1中,它的行为类似于8位定时器。
void setup()
{
DDRB = (1<<PB1);
TCCR1A |= (1<<COM1A1) | (1<<WGM11);
TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS10);
ICR1 = 19999;
OCR1A = 10000;
}
void loop()
{
}
由于TCCR1A中的WGM10已经设置,因此设置WGM11,WGM13和WGM12将选择模式15,而不是模式14.模式15是快速PWM,TOP = OCR1A(不是ICR1)。由于您还使用COM1A1将PWM的OC1A输出设置为PWM,这将导致OC1A保持高电平。
如前所述,如果你想在Arduino环境中配置定时器,你应该从头开始使用=而不是| =。
theusch写道:
而且,据我所知,更多可能会在setup()
之后运行
来自Arduino的main.cpp: 代码:
#include <Arduino.h>
int main(void)
{
init();
#if defined(USBCON)
USB.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
JJ
答案 1 :(得分:1)
OCR1A
控制频率(溢出重启定时器),而OCR1B
控制占空比(溢出会改变输出引脚状态)
在第二个例子,为什么您使用我不能uderstand ICR1
怎么可能你正在8V的输出作为Arduino的电压为5V运行...或者你fryng它还是你的阅读是不准确
请看一下这里,它将解释很多关于PWM,快速PWM等的事情。
http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
编辑:我错过了您使用ICR1
作为TOP而OCR1A
作为计数器。然后问题是:
默认情况下,arduino库会将寄存器初始化为某个值。
TCCR1A
= 1 - &gt; (WMG10
ON,这很糟糕)
TCCR1B
= 11 - &gt; (预分频器= 64)
你没有覆盖这个值,只是把它放到1位;这样,您不会使用WGM11
,WMG12
和WMG13
激活,而是会启用位WMG10
,从而导致模式15落入。
最终的预分频器仍然是16而不是8。
解决方案是更改| = with =,因此您将覆盖默认值。