适当实现Timer1用于PWM生成

问题描述 投票:0回答:1

在Atmel ATmega328P(datasheet)上,有三个定时器可用于PWM生成(timer0,timer1和timer2)。

我已经拥有了使用8位timer2所需的东西,我只关心使用timer2的不同定时器instad,因为timer2用于各种库,我希望有更多的粒度。因此,我想使用16位timer1。

以下是我使用timer2生成25 kHz可变占空比的方法。对于此示例,我们考虑35%的占空比:

void setup() 
{

    /*
    16*10^6/ [prescalar] / ([OCR2A]) / 2 = [desired frequency]
    16*10^6/ 8 / [OCR2A] / 2 = 25*10^3

    Prescalar table for Timer2 (from datasheet section 17-9):
    CS22    CS21    CS20
      0     0       0       = No clock source (Timer/couter stopped)
      0     0       1       = clkT2S/(No prescaling)
      0     1       0       = clkT2S/8 (From prescaler)
      0     1       1       = clkT2S/32 (From prescaler)
      1     0       0       = clkT2S/64 (From prescaler)
      1     0       1       = clkT2S/128 (From prescaler)
      1     1       0       = clkT2S/256 (From prescaler)
      1     1       1       = clkT2S/1024 (From prescaler)
    */

    pinMode(3, OUTPUT);
    TCCR2B = _BV(WGM22) | _BV(CS21);
    TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(COM2B0) | _BV(WGM20);
    OCR2A = 40; 
    OCR2B = 16; //40*0.35=16
}

void loop()
{ 
}

要使用timer1获得相同的结果必须非常简单,但我不熟悉这些寄存器。我一直在寻找数据表之外的解释。我发现这篇文章:Secrets of Arduino PWM,但它只涵盖了timer2的使用。

我根据Stephan的建议尝试了以下内容,但它只是导致两个输出(D9和D10)保持高电平:

void setup() 
{

    pinMode(9, OUTPUT); //D9
    pinMode(10, OUTPUT); //D10

    // Set GPIO for timer1 output for OC1A and OC1B
    //DDRB |= (1 << DDB1) | (1 << DDB2);

    ICR1 = 0xFFFF;

    // 25% duty cycle
    OCR1A = 0x0009;

    // 75% duty cycle
    //OCR1B = 0xBFFF;

    //20.14.1, pg170
    // set none-inverting mode
    TCCR1A |= ((1 << COM1A1) | (1 << COM1B1));

    //Table 20-6, pg171
    // Fast PWM mode
    TCCR1A |= (1 << WGM11);
    TCCR1B |= (1 << WGM12) | (1 << WGM13);

    // START the timer with no prescaler
    TCCR1B |= (1 << CS10);

}

void loop()
{
}

我尝试改变所有东西(ICR1,OCR1A,TCCR1A),但唯一不同的组合是以下,它在D10上提供25kHz频率,D9保持高电平,但无论寄存器如何,HIGH持续时间都停留在4μs。 (我只是猜测并用OCR1A检查得到25kHz。我不知道为什么会有效。)

void setup() 
{

    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);

    // Set GPIO for timer1 output for OC1A and OC1B
    //DDRB |= (1 << DDB1) | (1 << DDB2);

    ICR1 = 0xFFFF;

    // 25% duty cycle
    OCR1A = 0x0009;

    // 75% duty cycle 
    //This line causes both outputs to be held HIGH
    //OCR1B = 0xBFFF;

    //20.14.1, pg170
    // set none-inverting mode
    TCCR1A |= ((1 << COM1A1) | (1 << COM1B1));

    //Table 20-6, pg171
    // Fast PWM mode
    TCCR1A |= (1 << WGM11);
    TCCR1B |= (1 << WGM12) | (1 << WGM13);

    // START the timer with no prescaler
    TCCR1B |= (1 << CS10);

}

void loop()
{
}

我正在使用Arduino Nano分线板进行原型设计,D9和D10是timer1输出引脚:

Arduino Nano pins highlighted for B1 and B2(图片来自https://bigdanzblog.wordpress.com

我试过更换电路板,但结果相同。

以下是数据表中的相关信息:

atmega28p table 20-3 through 20-5

atmega328p table 20-6

atmega328p table 20-7 timer prescaler

c++ timer arduino cpu-registers pwm
1个回答
0
投票

Timer1有2个输出,OC1AOC1B。两者都运行相同的硬件定时器,因此同步。定时器能够以三种不同的模式运行:快速PWM模式,相位校正PWM模式以及相位和频率校正模式。您需要为您选择正确的模式以及适合您应用的正确计时器预分频器。以下是一个例子。

// Timer1 Resolution 16-bit
// Timer1 A output at 25% Duty Cycle, Fast PWM Mode
// Timer1 B output at 75% Duty Cycle, Fast PWM Mode 

#include <avr/io.h>

int main(void)
{
    // Set GPIO for timer1 output for OC1A and OC1B
    DDRB |= (1 << DDB1) | (1 << DDB2);

    ICR1 = 0xFFFF;

    // 25% duty cycle
    OCR1A = 0x3FFF;

    // 75% duty cycle
    OCR1B = 0xBFFF;

    // set none-inverting mode
    TCCR1A |= ((1 << COM1A1) | (1 << COM1B1));

    // Fast PWM mode
    TCCR1A |= (1 << WGM11);
    TCCR1B |= (1 << WGM12)|(1 << WGM13);

    // START the timer with no prescaler
    TCCR1B |= (1 << CS10);

    while (1);
}
© www.soinside.com 2019 - 2024. All rights reserved.