PB7 上的 Atmega2560 PWM

Posted

技术标签:

【中文标题】PB7 上的 Atmega2560 PWM【英文标题】:Atmega2560 PWM on PB7 【发布时间】:2017-06-06 08:52:20 【问题描述】:

我试图通过 Atmega2560 上的 timer0 从 PB7 引脚获取 PWM 输出,但没有成功。它应该为连接的 repro 生成音调。我的 PWM 设置是:

DDRB    = 0b11100000;
PORTB   = 0b00000000;

OCR0A = 0x04;
TCCR0A = (0 << COM0A1) | (1 << COM0A0) | (1 << WGM01) | (0 << WGM00);
TCCR0B = (0 << WGM02) | (0 << CS02) | (0 << CS01) | (0 << CS00);

然后我有了这个函数,它应该会产生声音:

void SoundOutput(unsigned int uintTone)

    if (uintTone != 0)
    
        LED_2(1);
        OCR0A = uintTone;

        TCCR0B |= (1 << CS02) | (1 << CS01) | (1 << CS00);
    
    else
    
        TCCR0B &= ~((1 << CS02) | (1 << CS01) | (1 << CS00));
    

但是当我用音调参数调用它时没有任何反应。你能帮我么?

【问题讨论】:

我认为设置源的是这一行:TCCR0B |= (1 &lt;&lt; CS02) | (1 &lt;&lt; CS01) | (1 &lt;&lt; CS00);。如果所有三个都设置,则意味着: T0 引脚上的外部时钟源。时钟上升沿。如果您在 T0 上没有外部时钟源,只需设置 CS00 以获取例如 CPU 频率作为源,而无需任何预分频器。 这个行得通,我现在PB7上有输出,但是现在频率太高了。当我调用 SoundOutput(400) 时,我可以选择 12.5us 的 O-scope 周期,这对于音调生成来说太高了。 是的,因为 2560 的 CPU 频率是 16MHz。所以你的音频信号的周期是:t = (1/f_CPU) * uintTone / 2。您希望参数uintTone 成为结果频率吗?我稍后会发布它,因为我有时间作为答案。 "您希望参数uintTone 成为结果频率吗?"是的,那太好了,但是我有 11059200Hz 外部晶体而不是 16MHz。 【参考方案1】:

根据您的 cmets,您使用 ~12MHz 时钟作为定时器的输入,并且从您的代码中,您在 CTC 模式下使用 8 位定时器 0,以 OCR0A 作为顶部。您已将 OC0A 设置为开启比较匹配。

根据 2560 数据表,您的定时器的频率由下式给出:

F_CLK/(2*(1 + OCR0A)) | F_CLK ~= 12MHz

这是一个 8 位定时器,这意味着您的 PWM 可以产生的最小频率由下式给出:

12e6/(2*(1 + 255)) ~= 20KHz

除非您放慢用于计时器的时钟或使用可以计数更高的计时器,否则您根本无法使用该配置生成可听音。

1) 使用 16 位计数器(即 timer1)。这将为您提供 ~90Hz 的最小频率和 ~6MHz 的最大频率,这将为您提供足够的范围来生成音调:

/* WGM BITS = 0100: CTC Mode */
/* COMA BITS = 01: Toggle OC1A on compare match */
/* CS BITS = 111: External clock source on rising edge */

TCCR1A = (0 << COM1A1) | (1 << COM1A0) | (0 << WGM01) | (0 << WGM00);
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS02) | (1 << CS01) | (1 << CS00);

2) 使用内部时钟源作为定时器时钟,而不是外部源。除非您更改了熔丝位或您在某处的代码中更改它,否则时钟将为 1MHz。将时钟预分频 8 为您提供 ~250Hz - ~60KHz 的频率范围。

/* WGM BITS = 010: CTC Mode */
/* COMA BITS = 01: Toggle OC1A on compare match */
/* CS BITS = 010: Prescale the internal clock by 8 */

TCCR0A = (0 << COM0A1) | (1 << COM0A0) | (1 << WGM01) | (0 << WGM00);
TCCR0B = (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00);

【讨论】:

是的!我使用了第二种解决方案,效果很好。非常感谢:) 没问题:以下是有关如何使用 PWM 的更多参考信息的链接:allaboutavr.com/index.php/2017/05/13/… 嗯,我的喜悦有点初步。我现在可以发出声音,但频率很奇怪。我需要从扬声器中输出准确的频率,但我能够输出(使用安捷伦频率计数器测量)范围为 230KHz (OCR0A = 2) 和 2.69 KHz (OCR0A = 255) 和 0Hz 与OCR0A = 0 或 @ 987654327@ 你到底在测量什么?我给你的计算是针对 PWM 的频率,而不是你会产生的声音。 我正在测量扬声器的频率。我需要在 165Hz 和 680Hz 之间产生声音。

以上是关于PB7 上的 Atmega2560 PWM的主要内容,如果未能解决你的问题,请参考以下文章

Atmega2560 中的圆形 LED 回路使用组装

在 Atmel AVR studio 中使用 ATMega2560 读取 RC PWM 信号

Arduino使用所有端口ATMega2560

删除 Arduino 上的引导加载程序

谁有uno和2560的尺寸图,要做个板固定住arduino

Arduino基本数据类型