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);
}
Есть очевидные ошибки? Спасибо за помощь!
@Andrew M., 👍0
3 ответа
Лучший ответ:
Я попробовал код на Uno, и, как вы сказали, он звучит странно.
По моим расчетам, частота составляет 40 кГц (16 МГц/(200 x 2)), что выше порога слышимости. Звук, который мы на самом деле слышим, вероятно, относится к 3-й или 5-й гармонике, с пониженной интенсивностью и, возможно, с дрожанием.
Я пытался изменить
TCCR2B = _BV(CS20); // клик/1
в
TCCR2B = _BV(CS21); // клик/8
что должно означать, что частота теперь составляет 5 кГц (16 МГц/8/(200 x 2)).
Звучит чище.
Похоже, частота моего тона была слишком высокой для зуммера, который я использовал, что вызывало странный вывод.
Регулировка делителя часов устранила проблему. То есть я изменил следующее:
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 за то, что указал мне правильное направление.
Если вы выведете контакт динамика из прерывания, вы неизбежно некоторое дрожание, так как запрос на прерывание иногда срабатывает, когда ЦП обрабатывает другой ISR. Это может привести к тому, что один из уровней удерживается дольше, чем ожидалось, что, в свою очередь, приводит к паразитным частотам в выход. Обратите внимание, что на самом деле это не гармоники (гармоники всегда имеют частоты выше основной), а скорее биение между различными источниками прерываний. Вот почему вы можете слышать что-то даже при том, что основной тон намного выше диапазона слышимости.
Если вы хотите получить чистый ШИМ-сигнал, вам следует его сгенерировать. в оборудовании. Таймер 2, например, может управлять выводами 11 (OC2A) и 3 (OC2B). См. биты COM2{A1,A0,B1,B0} в TCCR2A.
- генерировать два сдвинутых по фазе ШИМ-импульса, запускаемых внешним сигналом с частотным разделением, с помощью Arduino uno?
- Точность синхронизации Arduino nano
- Интервальный таймер на Arduino: Сомнения по поводу библиотеки TimerOne
- максимальная частота ШИМ на основе прерываний при 500 Гц
- Можно ли отсоединить прерывание на определенное время
- Заставить TCNT оставаться ниже OCRxA на ATmega328P
- Эмуляция Arduino Uno с помощью QEMU: прерывания не работают
- Может ли Arduino uno регулировать входную квадратную волну, фазу и частоту только с помощью таймера-счетчика?
Только что опубликовал ответ с аналогичным выводом, так как я отправил сообщение на AVRFreaks.net и получил аналогичный совет. Спасибо за помощь! Рад подтвердить, что это было воспроизведено для вас. Я отмечу ваш как решение., @Andrew M.