为什么我总是得到零 PWM 输出?
Why I am always getting Zero PWM output?
我想以 10 位分辨率输出两个不同的模拟值,即 dac_value 范围为 0-1023。我正在使用外部 crystal 4MHz 的 ATmega16。我也试过在输出端连接 RC 滤波器,但没有任何改变。
我经常得到零输出,有人可以帮忙吗??
#include <avr/io.h>
#include <avr/interrupt.h>
void initPWM()
{
TCCR1A |= (1<<WGM11) | (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) ;
TCCR1B |= (1<<WGM12) | (1<<CS10);
}
uint16_t dac_value1 = 100, dac_value2 = 200;
int main(void)
{
initPWM();
while(1) {
OCR1A = dac_value1;
OCR1B = dac_value2;
}
for (;;) {}
}
您将错误的位分配给了错误的寄存器。
澄清一下:PWM 不是模拟输出。它快速改变高或低输出状态。 PWM 值决定输出在定时器周期内处于每种状态(高电平或低电平)的时间。
如果你想"analog"输出,你需要对输出信号进行滤波,比如通过一个RC-filter,同时你需要尽可能快的输出,也就是说你需要select 降低预分频比,并选择 Fast-PWM 模式。在您当前的配置中,您将获得带有 1024 预分频器的 pwm。 IE。每秒少于 4 个定时器周期。
因此,如果您将分配一个带有预分频器 1 的快速 pwm(这将为我们提供 3906 Hz 的输出)和反向输出(即较高的 OCR1x 值导致较低的输出值),它将是这样的:
void initPWM()
{
TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0);
// here bits WGM10 WGM11 (with WGM12 in TCCR1B) will select the Fast PWM mode with 10 bit resolution;
// COM1A1 COM1A0 COM1B1 COM1B0 select an inverted PWM output on pins OC1A OC1B
TCCR1B = (1<<WGM12) | (1<<CS10);
// CS10 will select 1:1 prescaler (i.e. 4000000/1024 timer periods per second)
// Also, your PWM output will not be visible on corresponding pins, unless you will configure an DDR bits for these pins to output. Those pins are PD5 and PD4 on ATmega16
DDRD |= (1 << 4) | (1 << 5);
}
接下来您需要考虑的事情是:当您的应用程序 main() 函数执行结束时,它将跳转到重置向量。所以,在 main():
的末尾放置一个空循环
int main(void)
{
uint16_t dac_value1, dac_value2;
dac_value1 = 123; // do not forget to init variables!!!
dac_value2 = 987;
initPWM();
OCR1A = dac_value1;
OCR1B = dac_value2;
for(;;) {
// main loop. Now it's empty
}
}
我想以 10 位分辨率输出两个不同的模拟值,即 dac_value 范围为 0-1023。我正在使用外部 crystal 4MHz 的 ATmega16。我也试过在输出端连接 RC 滤波器,但没有任何改变。 我经常得到零输出,有人可以帮忙吗??
#include <avr/io.h>
#include <avr/interrupt.h>
void initPWM()
{
TCCR1A |= (1<<WGM11) | (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) ;
TCCR1B |= (1<<WGM12) | (1<<CS10);
}
uint16_t dac_value1 = 100, dac_value2 = 200;
int main(void)
{
initPWM();
while(1) {
OCR1A = dac_value1;
OCR1B = dac_value2;
}
for (;;) {}
}
您将错误的位分配给了错误的寄存器。 澄清一下:PWM 不是模拟输出。它快速改变高或低输出状态。 PWM 值决定输出在定时器周期内处于每种状态(高电平或低电平)的时间。
如果你想"analog"输出,你需要对输出信号进行滤波,比如通过一个RC-filter,同时你需要尽可能快的输出,也就是说你需要select 降低预分频比,并选择 Fast-PWM 模式。在您当前的配置中,您将获得带有 1024 预分频器的 pwm。 IE。每秒少于 4 个定时器周期。
因此,如果您将分配一个带有预分频器 1 的快速 pwm(这将为我们提供 3906 Hz 的输出)和反向输出(即较高的 OCR1x 值导致较低的输出值),它将是这样的:
void initPWM()
{
TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0);
// here bits WGM10 WGM11 (with WGM12 in TCCR1B) will select the Fast PWM mode with 10 bit resolution;
// COM1A1 COM1A0 COM1B1 COM1B0 select an inverted PWM output on pins OC1A OC1B
TCCR1B = (1<<WGM12) | (1<<CS10);
// CS10 will select 1:1 prescaler (i.e. 4000000/1024 timer periods per second)
// Also, your PWM output will not be visible on corresponding pins, unless you will configure an DDR bits for these pins to output. Those pins are PD5 and PD4 on ATmega16
DDRD |= (1 << 4) | (1 << 5);
}
接下来您需要考虑的事情是:当您的应用程序 main() 函数执行结束时,它将跳转到重置向量。所以,在 main():
的末尾放置一个空循环int main(void)
{
uint16_t dac_value1, dac_value2;
dac_value1 = 123; // do not forget to init variables!!!
dac_value2 = 987;
initPWM();
OCR1A = dac_value1;
OCR1B = dac_value2;
for(;;) {
// main loop. Now it's empty
}
}