Установите частоту ШИМ на 25 кГц.

В настоящее время я могу установить четыре контакта ШИМ на частоту около 31 кГц с помощью следующего кода:

void setup()
{
    TCCR1B = TCCR1B & B11111000 | B00000001; // Установить частоту ШИМ для D9 & Д10:
    pinMode(pwmPin9, OUTPUT); // Устанавливает пин как выход
    pinMode(pwmPin10, OUTPUT); // Устанавливает пин как выход


    TCCR2B = TCCR2B & B11111000 | B00000001; // Установить ШИМ для D3 & Д11
    pinMode(pwmPin3, OUTPUT); // Устанавливает пин как выход
    pinMode(pwmPin11, OUTPUT); // Устанавливает пин как выход
}

Я где-то нашел эту настройку, но не знаю, как установить эти четыре контакта ШИМ на частоту около 25 кГц. Как это возможно?

, 👍15

Обсуждение

Вы понимаете, как работают таймеры AVR?, @Ignacio Vazquez-Abrams

См. [моя страница о таймерах](http://www.gammon.com.au/timers)., @Nick Gammon

@ IgnacioVazquez-Abrams Я не знаком, и мне нужно сначала установить эти четыре контакта примерно на 25 кГц. Спешу закончить проект и буду рад любой помощи. Код у меня установлен на 31 кГц. Могу ли я изменить его на 25 кГц? Двигатели постоянного тока требуют этой частоты., @user16307

@NickGammon Спасибо, но сейчас у меня действительно нет времени на их изучение. Не могли бы вы предоставить мне часть кода для настройки 25 кГц. Я заблудился, @user16307

Почему четыре контакта? Будут ли у них у всех разные рабочие циклы? Почему бы не отправить один вывод в четыре разных места?, @Nick Gammon

«В настоящее время я могу установить четыре контакта PWM примерно на 31 кГц с помощью следующего кода» - я только что попробовал ваш код, и он ничего не вывел., @Nick Gammon

Мне нужно настроить их точные обороты, чтобы их рабочие циклы были немного разными. Как насчет того, чтобы установить 2 контакта только на 25 кГц?, @user16307

Этот код можно легко адаптировать для установки частоты 31400, 3920, 490, 123 или 30,6 Гц. Другие частоты не будут такими простыми и, скорее всего, будут связаны с изменением разрешения на выходе ШИМ. Можете ли вы жить с разрешением всего в 41 шаг? Или 80 шагов, но без функции «корректировка фазы»? Или 321 шаг, но только на пинах 9 и 10?, @Edgar Bonet

Я думаю, что последний вариант был бы отличным, тогда я использую два Ard. Можете ли вы помочь мне с этой частью? я не знаком, @user16307

Обсуждая с Гербеном, я только что подумал о четвертой возможности: вы можете замедлить основные системные часы до 8 МГц и использовать три таймера. Тогда у вас будет 4 канала ШИМ на частоте 25 кГц с 161 шагом на одном Arduino Uno. Цена будет заключаться в потере функций синхронизации (millis(), delay() и т. д.), необходимости корректировать скорость последовательной передачи данных и том, что вся программа будет работать вдвое медленнее. Будет ли это интересным вариантом?, @Edgar Bonet

@EdgarBonet Спасибо за ваши подробные отличные ответы. В моем текущем коде я могу управлять четырьмя штырями PWM с частотой 31 кГц. В то же время я могу использовать ЖК-экран (здесь я использую delay() для предотвращения мерцания), а скорость передачи данных составляет 9600. Итак, если я использую ваше предложение 8 МГц, какую скорость мне следует использовать?, @user16307

С ЦП @ 8 МГц, если вы Serial.begin(19200), фактическая скорость передачи будет 9600 бит/с. delay() может работать, но в единицах 39,0625 мкс., @Edgar Bonet

Лучший материал, объясняющий ШИМ с таймерами AVR, который я нашел до сих пор, - это видео на YouTube * "[8. Таймеры и счетчики Arduino](https://www.youtube.com/watch?v=faCVhp7gm-g) *" ( 1 ч 00 м 08 с)., @Peter Mortensen

искал это, это правильно то, что мне нужно. Как можно изменить его для вывода около 14 кГц? на самом деле между 11 - 19 кГц ОК. Спасибо, @laoadam


2 ответа


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

14

Я публикую этот второй ответ, так как понял, что можно 4 канала ШИМ на частоте 25 кГц с 161 шагом на одном Arduino Uno. Этот предполагает изменение основной тактовой частоты на 8 МГц, что имеет некоторые побочные эффекты, так как вся программа будет работать вдвое медленнее. Это также включает в себя перенастройку трех таймеров, что означает потерю Функции синхронизации Arduino (millis(), micros(), delay() и delayMicroseconds()). Если эти компромиссы приемлемы, вот как это идет:

void setup()
{
    // Установите основные системные часы на 8 МГц.
    noInterrupts();
    CLKPR = _BV(CLKPCE);  // разрешить изменение тактового предделителя
    CLKPR = _BV(CLKPS0);  // делим частоту на 2
    interrupts();

    // Настройте Таймер 0 для корректной фазы PWM @ 25 кГц.
    TCCR0A = 0;           // отменить настройку, сделанную...
    TCCR0B = 0;           // ...основная библиотека Arduino
    TCNT0  = 0;           // сброс таймера
    TCCR0A = _BV(COM0B1)  // неинвертированный ШИМ на кан. Б
        | _BV(WGM00);  // режим 5: тел. правильный ШИМ, ВЕРХ = OCR0A
    TCCR0B = _BV(WGM02)   // то же самое
        | _BV(CS00);   // прескалер = 1
    OCR0A  = 160;         // ВЕРХ = 160

    // То же самое для Таймера 1.
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    TCCR1A = _BV(COM1A1)  // неинвертированный ШИМ на кан. А
        | _BV(COM1B1)  // то же самое на гл. Б
        | _BV(WGM11);  // режим 10: тел. правильный ШИМ, ВЕРХ = ICR1
    TCCR1B = _BV(WGM13)   // то же самое
        | _BV(CS10);   // прескалер = 1
    ICR1   = 160;

    // То же самое для Таймера 2.
    TCCR2A = 0;
    TCCR2B = 0;
    TCNT2  = 0;
    TCCR2A = _BV(COM2B1)  // неинвертированный ШИМ на кан. Б
        | _BV(WGM20);  // режим 5: тел. правильный ШИМ, ВЕРХ = OCR2A
    TCCR2B = _BV(WGM22)   // то же самое
        | _BV(CS20);   // прескалер = 1
    OCR2A  = 160;
}

void loop()
{
    analogWrite( 3,   1);  // рабочий цикл = 1/160
    analogWrite( 5,  53);  // ~ 1/3
    analogWrite( 9, 107);  // ~ 2/3
    analogWrite(10, 159);  // 159/160
}

В отличие от другого ответа, здесь не требуется модифицированная версия analogWrite(): стандартный будет работать нормально. Только забота должна быть принято, что:

  1. Записанное значение должно находиться в диапазоне от 0 (всегда НИЗКИЙ) до 160. (всегда ВЫСОКИЙ), включительно.
  2. Доступны только контакты 3, 5, 9 и 10. Попытка analogWrite() к контактам 6 или 11 не только не будет выдаваться ШИМ-выход, но и также измените частоту на контакте 5 или 3 соответственно.
,

Прошло очень много времени, и теперь я застрял с тем же самым с Arduino Due, который использует другой процессор. Я был бы рад, если бы у вас был какой-либо вклад здесь https://arduinoprosto.ru/q/67053/trouble-with-setting-the-pwm-frequency-for-arduino-due, @user16307


13

Вы можете настроить Таймер 1 на циклическую работу с частотой 25 кГц в режиме фазовой корректировки ШИМ и использовать его два выхода на контактах 9 и 10 следующим образом:

// ШИМ-выход @ 25 кГц, только на контактах 9 и 10.
// Выходное значение должно быть между 0 и 320 включительно.
void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // никакой другой пин не будет работать
            break;
    }
}

void setup()
{
    // Настройте Таймер 1 для ШИМ @ 25 кГц.
    TCCR1A = 0;           // отменить настройку, сделанную...
    TCCR1B = 0;           // ...основная библиотека Arduino
    TCNT1  = 0;           // сброс таймера
    TCCR1A = _BV(COM1A1)  // неинвертированный ШИМ на кан. А
           | _BV(COM1B1)  // то же самое на канале; Б
           | _BV(WGM11);  // режим 10: тел. правильный ШИМ, ВЕРХ = ICR1
    TCCR1B = _BV(WGM13)   // то же самое
           | _BV(CS10);   // прескалер = 1
    ICR1   = 320;         // ВЕРХ = 320

    // Установите выводы ШИМ в качестве выходных.
    pinMode( 9, OUTPUT);
    pinMode(10, OUTPUT);
}

void loop()
{
    // Просто пример:
    analogWrite25k( 9, 110);
    analogWrite25k(10, 210);
    for (;;) ;  // бесконечная петля
}

Запись значения 0 с помощью analogWrite25k() означает, что вывод будет всегда НИЗКИЙ, тогда как 320 означает всегда ВЫСОКИЙ. Обычный analogWrite() должен почти работать, но он будет интерпретировать 255 так же, как 320 (т.е. всегда ВЫСОКИЙ).

В этом коде предполагается плата Arduino Uno или аналогичная (ATmega168 или 328 @). 16 МГц). Используемый здесь метод требует 16-битного таймера, поэтому использует Таймер 1, так как он единственный, доступный на Uno; вот почему только доступны два выхода. Метод может быть адаптирован к другим Платы на базе AVR с 16-битным таймером. Как заметил Гербен, этот таймер должен иметь соответствующий регистр ICRx. Таких таймеров 4 штуки. Arduino Mega, каждый с 3 выходами.

,

Может быть полезно объяснить, что этот метод работает только для таймера 1, так как другие таймеры не имеют регистра ICRx. В лучшем случае вы можете иметь только один вывод ШИМ на таймер, для таймеров 0 и 2., @Gerben

@Gerben: Разве у всех 16-битных таймеров нет этого регистра? По крайней мере, на Меге они есть., @Edgar Bonet

Да, но только timer1 на ATMega328 16-битный. Остальные 8-битные. И ОП хочет 4 выхода ШИМ, а ваше решение обеспечивает только 2. Или я ошибаюсь?, @Gerben

@Gerben: Нет, ты прав. Я просто говорю, что требование ICRx кажется излишним с требованием, чтобы таймер был 16-битным. По крайней мере, для Uno и Mega, не уверен насчет других Arduino на базе AVR. ОП понимает, что это обеспечивает только 2 канала ШИМ: см. мой комментарий к его вопросу и его ответ., @Edgar Bonet

На ATMega328 (который использует OP) только timer1 имеет регистр ICRx. Для других вам придется использовать OCRxA как TOP, что сделает невозможным использование PWM на выводе OCxA. ОП сказал, что он / она в порядке только с двумя контактами PWM, но затем сказал, что он / она будет использовать 2 Arduino. По-прежнему можно обойтись только 1 Uno, если OP желает потерять «миллис» и «задержку»., @Gerben

@Gerben: Только один Уно? Вы говорите о двух других вариантах, которые я предложил (т.е. установка прескалеров на 8)? О, можно было бы также изменить частоту основных часов и иметь 161 шаг, я не думал об этом. Это то, что вы имеете в виду?, @Edgar Bonet

Я действительно не следил за основной веткой комментариев. Я действительно говорил о вашей альтернативе из 41 шага. (Я не уверен, действительно ли OP нужно более 41 шага для контроля оборотов.), @Gerben

@Эдгар Боне Я пытаюсь следовать этому и генерировать те же 25 кГц на выводе 8 arduino mega, которым управляет ТАЙМЕР 4; я не вижу никакого успеха; не могли бы вы помочь?, @techniche

@techniche: 1. У меня работает. Может быть, вы забыли установить COM4C1 в TCCR4A? 2. Если это не проблема, то прочитайте [Как задать хороший вопрос?](https://arduino.stackexchange.com/help/how-to-ask), затем обновите [ваш вопрос](https:/ /arduinoprosto.ru/q/44750), включив свой полный исходный код и четко указав, что вы ожидаете от программы и что она делает вместо этого («Я не вижу никакого успеха» не считается допустимым описанием проблемы)., @Edgar Bonet

@EdgarBonet - большое спасибо за ответ и помощь; Я могу генерировать сигнал ШИМ, и кто-то еще проверил его с помощью вентилятора alpine 64 gt, и, похоже, он работает; он не работает с вентилятором, который у меня есть https://www.amazon.in/StorinTM-CPU-Cooler-Cooling-Connector/dp/B06XJV1SH8/. Это стандартный вентилятор процессора с 4 проводами, и он часто используется; может дело в вентиляторе, а провод ШИМ только для понты?, @techniche