Генерация частоты ШИМ выше 125 кГц с помощью Arduino Uno
Мне нужно получить частоту ШИМ не ниже 125 кГц. Я планирую управлять парой полевых МОП-транзисторов, используя этот ШИМ в качестве сигнала драйвера. В приведенном ниже коде указана частота 1 кГц. Могу ли я просто изменить значения задержки, чтобы получить меньший период времени и, следовательно, более высокую частоту?
void setup()
{
pinMode(13, OUTPUT);
}
void loop()
{
digitalWrite(13, HIGH);
delayMicroseconds(100); // Приблизительно 10% рабочего цикла при 1 кГц
digitalWrite(13, LOW); // Могу ли я изменить задержку на 1 и 9 для общего T = 10 мкс и, следовательно, f = 100 кГц?
delayMicroseconds(900);
}
Обновить
Просматривая предоставленные ответы, я наткнулся на несколько руководств. Я использовал приведенный ниже код, и это дало 125 кГц и 1,6 МГц (измерено с помощью CRO, а не моделирования). Но код должен был обеспечить 250 кГц и 8 МГц.
Мое требование 125 kHz удовлетворено, но мне просто любопытно узнать, почему скетч не работает как следует.
Второй набросок:
// Скетч, который создает ШИМ с частотой 8 МГц, рабочим циклом 50% и 250 кГц,
// ШИМ с 6-битным разрешением и переменным рабочим циклом (меняется каждые 5 мкс
// или о каждом периоде.
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
pinMode(3, OUTPUT); // Выходной контакт для OCR2B
pinMode(5, OUTPUT); // Выходной контакт для OCR0B
// Настраиваем выход 250 кГц (но cro измеряет только 125 кГц)
TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS20);
OCR2A = 63;
OCR2B = 0;
// Настраиваем выход 8 МГц
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
TCCR0B = _BV(WGM02) | _BV(CS00);
OCR0A = 1;
OCR0B = 0;
// Делаем прокатку 250 кГц
while (1) {
_delay_us(5);
if (OCR2B < 63)
OCR2B += 5;
else
OCR2B = 0;
}
}
@user276998, 👍5
Обсуждение4 ответа
Это немного выходит за рамки обычных возможностей Arduino, поэтому вам нужно углубиться в настройку некоторых регистров непосредственно для вашего чипа ATMEGA. См. «Непосредственное использование регистров ATmega PWM» http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
Я полностью согласен с вашим советом, но я бы рассматривал такое программирование таймера как идеальное в рамках «обычных возможностей Arduino»., @microtherion
microtherion, я имел в виду, что он находится за пределами набора функций «языка Arduino», которые будут работать во многих вариантах AVR (таких как задержка, цифровая запись и т. д.), и вместо этого углубляется в регистры, которые, вероятно, будут специфичны для данного чипа AVR., @darwinawardee
Да, вы можете уменьшить задержку.
Из документации:
Эта функция работает очень точно в диапазоне от 3 микросекунд и выше. Мы не можем гарантировать, что
delayMicroseconds
будет работать точно при меньшем времени задержки.
Обратите внимание, что между задержками есть несколько циклов, поэтому чем короче периоды времени, тем меньше точность.
Вы можете указать задержку вручную. Я бы предположил, что вы могли бы получить до 1 МГц, но с небольшим контролем рабочего цикла (на этой частоте). Вам нужно было бы отключить прерывания, и вы вообще ничего не могли бы сделать.
Если вы хотите еще больше, вы можете установить предохранитель на ATmega и получить исходную тактовую частоту на контакте 14 CKO (это отображается как цифровой контакт 8 на плате Arduino) — я ожидаю 50% рабочий цикл; у вас НЕ будет никакого контроля - вы не можете включить или выключить его или повлиять на рабочий цикл. Его можно использовать для запуска нескольких микросхем с одной и той же тактовой частотой.
Мое требование 125 кГц удовлетворено, но мне просто любопытно узнать, почему скетч не работает должным образом.
По моим измерениям, да. Используя эту слегка измененную версию вашего кода:
// Скетч, создающий ШИМ с частотой 8 МГц, рабочим циклом 50% и 250 кГц,
// ШИМ с 6-битным разрешением и переменным коэффициентом заполнения (меняется каждые 5 мкс)
// или о каждом периоде.
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
pinMode(3, OUTPUT); // Выходной контакт для OCR2B
pinMode(5, OUTPUT); // Выходной контакт для OCR0B
// Настраиваем выход 250 кГц
TCCR2A = bit(COM2A1) | bit(COM2B1) | bit(WGM21) | bit(WGM20);
TCCR2B = bit(WGM22) | bit(CS20);
OCR2A = 63;
OCR2B = 31;
// Настраиваем выход 8 МГц
TCCR0A = bit(COM0A1) | bit(COM0B1) | bit(WGM01) | bit(WGM00);
TCCR0B = bit(WGM02) | bit(CS00);
OCR0A = 1;
OCR0B = 0;
}
Я получаю ожидаемую частоту 8 МГц на контакте 5:
И выход 250 кГц на контакте 3:
Отвечая на ваш первоначальный вопрос: вы можете уменьшить задержку, но существует ограничение на то, насколько малой может быть задержка.
Две причины: во-первых, функция loop() имеет некоторые накладные расходы, а во-вторых, код, который вы пишете, требует времени для выполнения. Вот почему аппаратный ШИМ-таймер ценен — он генерирует импульсы без особого вмешательства программного обеспечения.
Я использовал приведенный ниже код и получил 125 кГц и 1,6 МГц (измерено с помощью CRO, а не моделирования).
Это просто добавление к ответу Ника... (Чтобы понять, что происходит, вам нужно обратиться к техническому описанию. Судя по вашим вопросам, я предполагаю, что вы недостаточно долго его изучали.)
В первом случае: 125 кГц.
Я не уверен, знаете ли вы, но вы используете специальный режим "Fast PWM" который немного отличается от аналога Write() в Arduino.
В этом режиме ваш период ШИМ определяется временем, которое требуется вашему счетчику таймера, чтобы соответствовать значению в регистре OCR2A. Это означает, что при тактовой частоте 16 МГц ваш выход переключается с частотой 16 МГц/63 = 250 кГц (примерно).
Пока все хорошо, но что видит CRO? CRO считает, что период состоит как из высокого, так и из низкого сигнала. Для переключения сигнала вверх и вниз требуется ДВА цикла по 250 кГц. Следовательно, показание показывает 125 кГц.
Что касается того, почему перекатывание может затруднить чтение: подумайте, какая волна появится, когда OCR0B = 0. ;-)
Вариант 2: 8 МГц
То же самое относится и ко второму случаю, и вы должны ожидать цикл 16 МГц, который переключает сигнал вверх и вниз (что дает показание 8 МГц на CRO). Что касается того, почему вы получаете 1,6 МГц - это странный случай. Можете ли вы опубликовать показания CRO?
«CRO считает, что период состоит как из высокого, так и из низкого сигнала» - действительно. Исходный код имел такой короткий импульс, что осциллограф мог интерпретировать каждый импульс как половину периода и, таким образом, вдвое уменьшить сообщаемую частоту. Возможно, он пропустил очень короткий рабочий цикл, поэтому я увеличил рабочий цикл до 50%., @Nick Gammon
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
- Как устранить шум от вентилятора 12 В с ШИМ-управлением на низкой скорости
- Увеличить разрядность PWM
- Как вывести истинное аналоговое напряжение на выходной контакт
- ПИД-регулятор для управления скоростью двигателя
- Как управлять 6 шаговыми двигателями с помощью Arduino?
- Синусоидальный инвертор
- Не могу контролировать скорость двигателей постоянного тока с помощью analogWrite()
Из-за вращающейся части было трудно увидеть в моем прицеле, избавившись от этого и установив OCR2B на 30, я, кажется, получил форму волны 250 кГц. Странный., @darwinawardee
Я сделал это, и это работает, я заметил, что нет доступного рабочего цикла 0%. Как я могу сделать 0% рабочий цикл?, @Juan Manuel Oviedo