9

我正在尝试将 PWM 用于 ATmega8 上的 LED,端口 B 的任何引脚。设置定时器一直很烦人,我不知道如何处理我的 OCR1A。这是我的代码,我希望得到一些反馈。

我只是想弄清楚如何使用PWM。我知道这个概念,OCR1A 应该是我想要脉冲的整个计数器时间的一部分。

#define F_CPU 1000000  // 1 MHz

#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>

int main(void){

    TCCR1A |= (1 << CS10) | (1 << CS12) | (1 << CS11);
    OCR1A = 0x0000;
    TCCR1A |= ( 0 << WGM11 ) | ( 1 << WGM10 ) | (WGM12 << 1) | (WGM13 << 0);
    TCCR1A |= ( 1 << COM1A0 ) | ( 0 << COM1A1 );
    TIMSK |= (1 << TOIE1); // Enable timer interrupt
    DDRB = 0xFF;
    sei(); // Enable global interrupts
    PORTB = 0b00000000;

    while(1)
    {
        OCR1A = 0x00FF; //I'm trying to get the timer to alternate being on for 100% of the time,
        _delay_ms(200);
        OCR1A = 0x0066; // Then 50%
        _delay_ms(200);
        OCR1A = 0x0000; // Then 0%
        _delay_ms(200);
    }
}

ISR (TIMER1_COMA_vect)  // timer0 overflow interrupt
{
    PORTB =~ PORTB;
}
4

2 回答 2

6

您需要使用以下两行初始化 OCR1A:

TCCR1A = (1 << WGM10) | (1 << COM1A1);
TCCR1B = (1 << CS10) | (1 << WGM12);

然后使用这个:

OCR1A = in

并且知道范围是0-255。计算你的百分比,你就有了!

#define F_CPU 1000000  // 1 MHz
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>

int main(void){
    TCCR1A = (1 << WGM10) | (1 << COM1A1);
    TCCR1B = (1 << CS10) | (1 << WGM12);
    DDRB = 0xFF;
    sei(); // Enable global interrupts
    PORTB = 0b00000000;

    while(1)
    {
        OCR1A = 255;
        _delay_ms(200);
        OCR1A = 125;
        _delay_ms(200);
        OCR1A = 0;
        _delay_ms(200);
    }
}
于 2012-02-28T21:34:14.573 回答
6

不,这不是你应该做 PWM 的方式。例如,您如何设置 PWM 速率,例如 42%?此外,代码量很大,可以以更有效的方式完成。此外,您浪费了一个 16 位计时器来执行 8 位操作。您有 2 个 8 位定时器(定时器/计数器 0 和 2)和一个 16 位定时器,Timer/Counter 1.

将未使用的端口引脚设置为输出也是一个坏主意。所有未连接到任何东西的端口引脚都应保留为输入。

ATmega8 在定时器 1 和 2 上内置了 PWM 发生器,无需通过软件模拟。您甚至不必手动设置端口(您只需将相应的端口引脚设置为输出)

你甚至不需要任何中断。

#define fillrate OCR2A 


 //...

 // main()

PORTB=0x00;
DDRB=0x08;  //We use PORTB.3 as output, for OC2A, see the atmega8 reference manual

// Mode: Phase correct PWM top=0xFF
// OC2A output: Non-Inverted PWM
TCCR2A=0x81;
// Set the speed here, it will depend on your clock rate.
TCCR2B=0x02;

// for example, this will alternate between 75% and 42% PWM
while(1)
{
    fillrate = 191; // ca. 75% PWM
    delay_ms(2000);

    fillrate = 107; // ca. 42% PWM
    delay_ms(2000);
}

请注意,您可以通过使用相同的定时器并设置 OCR2B 而不是 OCR2A 来将另一个 LED 与另一个 PWM 一起使用。不要忘记设置 TCCR2A 以启用 OCR2B 作为 PWM 的输出,因为在此示例中仅允许 OCR2A。

于 2012-03-23T07:35:36.677 回答