ШИМ частотного сигнала?
Работаю над своим первым настоящим наброском, поэтому постараюсь быть кратким. При необходимости не стесняйтесь спрашивать дополнительную информацию.
Для питания обратноходового трансформатора мне нужно подать ШИМ-сигнал на ШИМ-сигнал. Самый простой способ описать это так: хотя стандартный ШИМ-сигнал включен в течение некоторого установленного времени, а затем выключен в оставшуюся часть периода, мне нужно отправить сигнал, где «включено» на самом деле является прямоугольным сигналом частотой 14 кГц. с коэффициентом заполнения 50 %... затем подайте импульс этому сигналу с коэффициентом заполнения от ~1 до 100 % с частотой ~500 Гц.
С ШИМ 14 кГц проблем нет — я нашел библиотеку PWM.h и настроил ее.
Но как лучше всего справиться с этим с помощью второго ШИМ, скажем, на частоте 500 Гц?
Смогу ли я, приложив немного усилий, «пошутить» с помощью DO – WHILE? Будет ли WHILE читать переменную вне цикла? Есть ли более простые способы?
i=1;
do { // Импульсные микросекундные «кадры» высокочастотного сигнала?
//т.е. несущая 14 кГц ШИМ с частотой 500 Гц = 2000 микросекунд на цикл «кадра»
//при нагрузке 50% будет 1000 микрон в высоту и 1000 микрон в низ
pwmWrite( outpin, 128 ); //Включаем несущую 14 кГц при нагрузке 50%
delayMicroseconds(1000); //Задержка для создания «ВЫСОКОЙ» части кадра
pwmWrite( outpin, 0 ); //Выключаем несущую 14 кГц
delayMicroseconds(1000); //Задержка для создания «LOW» части кадра
} while (i == 1); //...и продолжаем выполнять цикл, пока состояние равно '1' или 'ON'
delay(1000); //?Позволит ли это повторить приведенный выше цикл, ожидая здесь 1 секунду?
i=0; //i != 1, значит, выходим из цикла while выше?
//затем продолжаем делать другие вещи ниже...
Любая помощь приветствуется.
@Sam43, 👍1
Обсуждение2 ответа
Ваша несущая 14 кГц может быть сгенерирована функцией tone()
, которая является частью ядра Arduino. Затем вы можете использовать библиотеку TimerOne для включения и выключения звукового сигнала.
Вот непроверенный пример эскиза, демонстрирующий использование:
#include <TimerOne.h>
const uint8_t outpin=4;
void setup() {
// поместите сюда свой код установки для однократного запуска:
pinMode(outpin, OUTPUT);
Timer1.initialize(1000); // 1000 микросекунд на полупериод
Timer1.attachInterrupt(toggleCarrier);
}
void loop() {
// поместите сюда свой основной код для повторного запуска:
}
void toggleCarrier() {
static uint8_t isPlaying;
if (isPlaying) {
noTone(outpin);
isPlaying=0;
} else {
tone(outpin, 14000);
isPlaying=1;
}
}
Этот код отлично работает, как написано, для случая рабочего цикла 50% при частоте 500 Гц. Спасибо!! Мне предстоит еще многое изучить с таймерами и прерываниями. Последняя часть головоломки заключается в том, что я считываю переменный потенциометр и преобразую это показание 0–1023 в коэффициент заполнения 1–100% для сигнала 500 Гц. Таким образом, учитывая полный цикл 2000 микросекунд, я считывал потенциометр, а затем циклически переключался от 20 мкс вкл./1800 мкс выкл. до полного включения 2000 мкс. Подозреваю, что можно было бы добавить больше кода в раздел toggleCarrier(), но лучший ли это метод? поставить еще один таймер? ТИА!, @Sam43
На Arduino Mega (или Uno с заменой ATmega328P на ATmega328PB, но тогда вам придется немного адаптировать код) это можно сделать с помощью модулятора сравнения выходов:
void setup() {
// CTC, OC0A переключение на совпадение сравнения, предварительный масштаб 1/8
TCCR0A = _BV(COM0A0)|_BV(WGM01);
TCCR0B = _BV(CS01);
// переключение каждые 35,5 мкс при частоте 16 МГц и масштабе 1/8
OCR0A = 70;
// ШИМ с корректировкой фазы и частоты, TOP — OCR1A, OC1C очищается при повышении и установке при понижении, без предварительного масштабирования
TCCR1A = _BV(COM1C1)|_BV(WGM10);
TCCR1B = _BV(WGM13)|_BV(CS10);
// период 2 мс при 16 МГц и без предварительного масштабирования
OCR1A = 16000;
// время включения 1 мс на частоте 16 МГц и без предварительного масштабирования
OCR1C = 8000;
// нет прерываний от таймеров
TIMSK0 = 0;
TIMSK1 = 0;
// выводим 1 только тогда, когда оба таймера выдают 1
PORTB &= ~_BV(PORTB7);
// останавливаем таймеры и сбрасываем прескалер
GTCCR |= _BV(TSM);
GTCCR |= _BV(PSRSYNC);
// сбрасываем оба таймера
TCNT0 = 0;
TCNT1 = 0;
// включаем вывод
DDRB |= _BV(DDB7);
// позволяем таймерам работать
GTCCR &= ~_BV(TSM);
}
void loop() {
// Просто отрегулируйте частоты и рабочий цикл, как требуется здесь.
// Все обрабатывается аппаратно и вступает в силу сразу после записи в регистр.
// OCR1A: желаемый период более медленного сигнала, в 8-х микросекундах. Может быть до 65535.
// OCR1C: желаемое время включения более медленного сигнала в 8-х микросекундах. Может быть до 65535.
// OCR0A: на 1 меньше желаемого периода более быстрого сигнала в микросекундах. Может быть до 255.
// Время включения более быстрого сигнала всегда равно половине периода.
// При необходимости вы можете обменять точность на больший диапазон для любого из вышеуказанных значений, настроив прескалер.
}
В этом эскизе контакт 13 на Mega будет иметь желаемую форму сигнала. У этого метода есть два больших преимущества. Во-первых, после настройки он вообще не требует никаких ресурсов ЦП (никаких циклов или прерываний), поэтому вы можете посвятить весь loop
чтению потенциометра и настройке рабочего цикла, не беспокоясь о сбоях. на выходе. Во-вторых, полностью аппаратное управление означает, что его выходной сигнал будет точным и абсолютно последовательным (компонент 500 Гц идеален, а компонент 14 кГц составляет примерно 14085 Гц). Однако единственным недостатком является то, что millis
и все остальное в библиотеке Arduino, использующее внутренние таймеры, не будет работать правильно, поскольку мы используем те же аппаратные таймеры, от которых они зависят.
@Sam43 Sam43 Теперь это обновлено, чтобы вы могли изменять рабочий цикл сигнала 500 Гц., @Joseph Sible-Reinstate Monica
- Установите частоту ШИМ на 25 кГц.
- Какова частота PWM-выхода на Arduino
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
- Как устранить шум от вентилятора 12 В с ШИМ-управлением на низкой скорости
- Генерация частоты ШИМ выше 125 кГц с помощью Arduino Uno
- Увеличить разрядность PWM
- Как вывести истинное аналоговое напряжение на выходной контакт
- PWM-вывод Arduino Nano не функционирует
50% ШИМ 14 кГц — это не ШИМ, это тон 14 кГц. Насколько точными должны быть несущая 14 кГц и частота модуляции 500 Гц? Это возможно с помощью «тона» для 14 кГц и «миллиса» для 500 Гц., @Jot
Ваше
do... while
здесь представляет собой бесконечный цикл., @Edgar BonetСпасибо за вклад. Я также рассмотрел командуtone(). В этом случае они практически взаимозаменяемы. tone() может сэкономить один шаг, потому что это автоматически составляет 50%, а мне приходится указывать 50% (128) при каждом вызове pwmWrite. Точность не критична. Тон/ШИМ 14 кГц, который у меня сейчас есть, более чем достаточно точен. Частота 500 Гц тоже может немного колебаться. Похоже, мне нужно настроить переменную i, входящую в цикл, и увеличить ее изнутри?, @Sam43
Рассмотрите возможность использования библиотеки [TimerOne](https://github.com/PaulStoffregen/TimerOne) для настройки обратного вызова на основе таймера/прерывания для части 500 Гц, которая переключает
tone()
14 кГц., @jose can u cВозможно, это лучший способ атаковать со стороны WHILE? (извините, код не работает) ' я = 1; пока (я<=100) { pwmWriteHR (распиновка, 128); задержкамикросекунды (500); pwmWriteHR (распиновка, 0); задержкамикросекунды (500); (я++); }', @Sam43
Это должно работать, но это надуманный способ написать базовый цикл for., @Edgar Bonet
Использование
tone()
(который использует Timer2) для сигнала несущей и Timer1 для модуляции позволяет использовать периферийные устройства, которые являются частью микроконтроллера и, следовательно, не нуждаются в цикле while для управления. Вы просто настраиваете/запускаете его и все работает. Если вы используете библиотеку TimerOne, единственным важным дополнительным кодом будет включение и выключение функцииtone(). Функция, которую вы для этого пишете, вызывается повторно со скоростью, установленной вами в TimerOne., @jose can u c