gpt4 book ai didi

c++ - 正确实现 Timer1 以生成 PWM

转载 作者:行者123 更新时间:2023-12-03 07:02:48 30 4
gpt4 key购买 nike

在 Atmel ATmega328P (datasheet) 上,有三个定时器可用于 PWM 生成(定时器 0、定时器 1 和定时器 2)。

我已经有了使用 8 位 timer2 所需的东西,我只关心使用 timer2 的不同计时器,因为 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 保持高电平,但无论寄存器如何,高电平持续时间都停留在 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 分线板进行原型(prototype)设计,其中 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

最佳答案

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);
}

关于c++ - 正确实现 Timer1 以生成 PWM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52083686/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com