Генерировать 1,7 МГц с PWM в Uno?

У меня есть этот код:

void setup() {
  pinMode(11, OUTPUT);
  TCCR2B = 0;
  TCNT2 = 0;
  TCCR2A = _BV(WGM21);
  TCCR2A |= _BV(COM2A0);
  OCR2A = 249;
}

void loop() {
  soundBuzzer();
}

void soundBuzzer() {
  TCCR2B |= _BV(CS21);
}

void silenceBuzzer() {
  TCCR2B &= ~_BV(CS21);
  TCNT2 = 0;
}

(Получено из здесь).

И у меня есть ультразвуковой распылитель воды, работающий на частоте 1,7 МГц. Запись другого числа вместо 249 в строку "OCR2A=249;", частота генерируемого меняется. С 249 он генерирует частоту 4 кГц. Итак, мой вопрос: какое число мне нужно написать, чтобы получить примерно 1,7 МГц?

, 👍4

Обсуждение

Вы можете разделить тактовую частоту только на целое число, поэтому с тактовой частотой 16 МГц максимально близкое значение, которое вы можете получить, составляет 2 МГц. Лист данных покажет вам, как найти настройку регистра соотношения делителя (в частности, если деление будет на единицу больше, чем загруженное число, и если перед тем, что вы хотите разделить, есть предварительный делитель). Если нет перскейлера, может показаться, что переключение платы на кристалл 12 МГц и деление на 7 может подойти, но вам понадобится специальный загрузчик., @Chris Stratton

Более реалистично, чтобы использовать это * с пользой *, вам понадобится усилитель мощности и напряжения из предполагаемой схемы драйвера, так почему бы просто не взять всю исходную схему драйвера, генератор частоты и все такое и найти способ включить / отключить его. от Ардуино? Примите соответствующие меры предосторожности в отношении напряжений, которые он может генерировать!, @Chris Stratton

Вы не можете генерировать 1,7 МГц на Uno. Самое близкое, что вы можете получить, это 16 МГц / 9 = 1,778 МГц., @Edgar Bonet

Вам нужно установить бит CS20, а не CS21. Таким образом, у вас нет предделителя. Затем сосчитайте до 9, как считал Эдгар. Поэтому установите OCR2A на 8., @Gerben

Вау, как я пропустил 16/9? Это не намного хуже, чем 12/7, и гораздо меньше проблем., @Chris Stratton


2 ответа


3

Расширение моего комментария... любой уровень сигнала, генерируемый таким типом микроконтроллер может работать только в течение целого числа циклов процессора. В чтобы сгенерировать его, вам сначала нужно вычислить время характеристики полезного сигнала с точки зрения циклов процессора:

period = 16 MHz ÷ 1.7 MHz = 9.412 cycles

Ближайшее значение, которое вы можете получить, — 9 циклов, что дает частоту

frequency = 16 MHz ÷ 9 = 1.778 MHz

Предполагая, что это приемлемо близко к вашей цели, вы можете настроить таймер, чтобы сделать это. В приведенном вами примере кода используется таймер 2 с Выход OC2A установлен в режим переключения. Этот подход может дать только периоды которые представляют собой четное количество циклов, поэтому я использую обычный вместо этого в приведенном ниже решении используется режим «неинвертирующий быстрый ШИМ». В этом режиме контакт OC2A нельзя использовать с регулируемой частотой, то I изменил его на OC2B (контакт 3 на Uno). Вот код:

const uint8_t OUTPUT_PIN = 3;  // = ОС2В
const uint8_t PERIOD = 9;      // 9 циклов ЦП ~ 1,778 МГц

void setup()
{
    pinMode(OUTPUT_PIN, OUTPUT);
    TCCR2B = 0;           // остановить таймер
    TCNT2  = 0;           // сброс таймера
    TCCR2A = _BV(COM2B1)  // неинвертирующий ШИМ на OC2B
           | _BV(WGM20)   // быстрый режим ШИМ, TOP = OCR2A
           | _BV(WGM21);  // ... то же самое
    TCCR2B = _BV(WGM22);  // ... то же самое
    OCR2A = PERIOD - 1;
    OCR2B = PERIOD/2 - 1;
}

void soundBuzzer() {
    TCCR2B |= _BV(CS20);  // F_ЦП/1
}

void silenceBuzzer() {
    TCCR2B &= ~_BV(CS20);
    TCNT2 = 0;
}

Сгенерированный сигнал немного асимметричен: он остается ВЫСОКИМ в течение 4 циклов и LOW для 5 циклов. Если вам нужен симметричный сигнал (50% рабочий цикл), вы можете установить PERIOD на 10 (5 циклов HIGH и 5 циклов LOW), но затем частота падает до 1,6 МГц.

Обновление: вы также можете заменить Arduino Uno на дешевый ATtiny85. микроконтроллер или, может быть, Arduino-совместимая плата разработки на его основе, например, Trinket или Digispark.

Этот микроконтроллер имеет встроенный PLL, который позволяет ему запускать один из его таймеры работают на частоте 64 МГц, хотя процессор работает намного медленнее. Таймер на 64 МГц позволяет достичь целевой частоты 1,7 МГц. с точностью до 1%:

64 MHz ÷ 38 = 1.684 MHz
,

То же самое для Arduinos на базе SAMD21; встроенный PLL позволяет запускать таймер на частоте 96 МГц., @ocrdu

Это отличный ответ, спасибо, и я мог бы проследить процесс в таблице данных ATmega328P. Однако я не понимаю, почему нельзя вывести частоту на вывод OC2A. Действительно, похоже, что в таблице 17-3 используется тот же режим для OC2A: очистить OC2A при совпадении сравнения, установить OC2A в BOTTOM (неинвертирующий режим). Я пытался, и это не работает, как вы сказали, но я не могу найти часть документов, в которой говорится, почему., @Olivier 'Ölbaum' Scherler

@Olivier'Ölbaum'Scherler: В этом режиме (режим генерации сигнала 7) регистр OCR2A используется для установки периода импульса (через значение «TOP»). Вы не можете использовать один и тот же регистр для установки длины импульса. Если вы установите длину импульса с помощью OCR2B, то сигнал PWM может быть выведен только на контакт OC2B., @Edgar Bonet


-4

И у меня есть ультразвуковой распылитель воды, работающий на частоте 1,7 МГц.

настройте таймер на один из режимов ШИМ и 50% постоянного тока, все в setup().

Семейство ATtiny85 имеет генератор PLL и лучше подходит для этого.

,

Кажется, вы повторяете только часть ответа, опубликованного месяц назад., @Chris Stratton