ATmega328P - проблема с использованием таймера 2 для генерации тона

Я просто пытаюсь использовать таймер 2 для генерации тона, и я получаю очень слабый и странный тон (почти как будто он каким-то образом модулируется, поскольку в нем есть «пульсация»). Вот мой простой код:

#include <Arduino.h>

#define SPEAKER_PORT PORTC
#define SPEAKER_BIT 2

void setup()
{
  pinMode(A2, OUTPUT);

  TCCR2A = _BV(WGM21);  // режим СТС
  TCCR2B = _BV(CS20);   // клик/1

  OCR2A = 200;  // 8-битный таймер, поэтому оставьте меньше 256
  bitSet(TIMSK2, OCIE2A);  // разрешить прерывание OCR2A
}

void loop()
{
  // НЕТ
}

ISR(TIMER2_COMPA_vect)
{
  SPEAKER_PORT ^= _BV(SPEAKER_BIT);
}

Есть очевидные ошибки? Спасибо за помощь!

, 👍0


3 ответа


Лучший ответ:

2

Я попробовал код на Uno, и, как вы сказали, он звучит странно.

По моим расчетам, частота составляет 40 кГц (16 МГц/(200 x 2)), что выше порога слышимости. Звук, который мы на самом деле слышим, вероятно, относится к 3-й или 5-й гармонике, с пониженной интенсивностью и, возможно, с дрожанием.

Я пытался изменить

TCCR2B = _BV(CS20); // клик/1

в

TCCR2B = _BV(CS21); // клик/8

что должно означать, что частота теперь составляет 5 кГц (16 МГц/8/(200 x 2)).

Звучит чище.

,

Только что опубликовал ответ с аналогичным выводом, так как я отправил сообщение на AVRFreaks.net и получил аналогичный совет. Спасибо за помощь! Рад подтвердить, что это было воспроизведено для вас. Я отмечу ваш как решение., @Andrew M.


1

Похоже, частота моего тона была слишком высокой для зуммера, который я использовал, что вызывало странный вывод.

Регулировка делителя часов устранила проблему. То есть я изменил следующее:

TCCR2B = _BV(CS20);   // clk/1

в

TCCR2B = _BV(CS22) | _BV(CS20);  // clk/128

и теперь я получаю разумно звучащие тона.

Обратите внимание, что выбранный вами делитель тактовой частоты в конечном итоге зависит от того, какой частотный диапазон вы хотите поддерживать, и разрядности таймера. Формула примерно такая:

freq = 16000000 / d / n / 2

где d — это значение делителя тактового сигнала (например, 128), а n — это значение счетчика, при котором следует прерывание (что происходит в OCR2A например). n должен соответствовать разрядности конкретного таймера (на ATmega328P таймер 1 имеет ширину 16 бит, а таймер 2 — 8 бит).

Надеюсь, это будет полезно всем, кто столкнется с этими проблемами. Большое спасибо Картману на AVRFreaks.net за то, что указал мне правильное направление.

,

0

Если вы выведете контакт динамика из прерывания, вы неизбежно некоторое дрожание, так как запрос на прерывание иногда срабатывает, когда ЦП обрабатывает другой ISR. Это может привести к тому, что один из уровней удерживается дольше, чем ожидалось, что, в свою очередь, приводит к паразитным частотам в выход. Обратите внимание, что на самом деле это не гармоники (гармоники всегда имеют частоты выше основной), а скорее биение между различными источниками прерываний. Вот почему вы можете слышать что-то даже при том, что основной тон намного выше диапазона слышимости.

Если вы хотите получить чистый ШИМ-сигнал, вам следует его сгенерировать. в оборудовании. Таймер 2, например, может управлять выводами 11 (OC2A) и 3 (OC2B). См. биты COM2{A1,A0,B1,B0} в TCCR2A.

,