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

12

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

void setup()
{
    TCCR1B = TCCR1B & B11111000 | B00000001; // Set PWM frequency for D9 & D10:
    pinMode(pwmPin9, OUTPUT); // Sets the pin as output
    pinMode(pwmPin10, OUTPUT); // Sets the pin as output


    TCCR2B = TCCR2B & B11111000 | B00000001; // Set PWM for D3 & D11
    pinMode(pwmPin3, OUTPUT); // Sets the pin as output
    pinMode(pwmPin11, OUTPUT); // Sets the pin as output
}

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

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

Ответы:

10

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

void setup()
{
    // Set the main system clock to 8 MHz.
    noInterrupts();
    CLKPR = _BV(CLKPCE);  // enable change of the clock prescaler
    CLKPR = _BV(CLKPS0);  // divide frequency by 2
    interrupts();

    // Configure Timer 0 for phase correct PWM @ 25 kHz.
    TCCR0A = 0;           // undo the configuration done by...
    TCCR0B = 0;           // ...the Arduino core library
    TCNT0  = 0;           // reset timer
    TCCR0A = _BV(COM0B1)  // non-inverted PWM on ch. B
        | _BV(WGM00);  // mode 5: ph. correct PWM, TOP = OCR0A
    TCCR0B = _BV(WGM02)   // ditto
        | _BV(CS00);   // prescaler = 1
    OCR0A  = 160;         // TOP = 160

    // Same for Timer 1.
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
        | _BV(COM1B1)  // same on ch. B
        | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
        | _BV(CS10);   // prescaler = 1
    ICR1   = 160;

    // Same for Timer 2.
    TCCR2A = 0;
    TCCR2B = 0;
    TCNT2  = 0;
    TCCR2A = _BV(COM2B1)  // non-inverted PWM on ch. B
        | _BV(WGM20);  // mode 5: ph. correct PWM, TOP = OCR2A
    TCCR2B = _BV(WGM22)   // ditto
        | _BV(CS20);   // prescaler = 1
    OCR2A  = 160;
}

void loop()
{
    analogWrite( 3,   1);  // duty cycle = 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, который использует другой процессор. Я был бы рад, если у вас есть какой-либо вклад здесь arduino.stackexchange.com/questions/67053/…
user16307
11

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

// PWM output @ 25 kHz, only on pins 9 and 10.
// Output value should be between 0 and 320, inclusive.
void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // no other pin will work
            break;
    }
}

void setup()
{
    // Configure Timer 1 for PWM @ 25 kHz.
    TCCR1A = 0;           // undo the configuration done by...
    TCCR1B = 0;           // ...the Arduino core library
    TCNT1  = 0;           // reset timer
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
           | _BV(COM1B1)  // same on ch; B
           | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
           | _BV(CS10);   // prescaler = 1
    ICR1   = 320;         // TOP = 320

    // Set the PWM pins as output.
    pinMode( 9, OUTPUT);
    pinMode(10, OUTPUT);
}

void loop()
{
    // Just an example:
    analogWrite25k( 9, 110);
    analogWrite25k(10, 210);
    for (;;) ;  // infinite loop
}

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

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

Эдгар Бонет
источник
1
Может быть полезно объяснить, что этот метод работает только для timer1, так как другие таймеры не имеют ICRxрегистра. Самое большее, вы можете иметь только один вывод ШИМ на таймер для таймеров 0 и 2.
Гербен
1
@ Гербен: Разве не все 16-битные таймеры имеют этот регистр? По крайней мере, на Меге они делают.
Эдгар Бонет
1
Да, но только timer1 является 16-разрядным на ATMega328. Остальные 8-битные. И ОП хочет 4 выхода ШИМ, а ваше решение предоставляет только 2. Или я ошибаюсь?
Гербен
1
@ Гербен: Нет, ты прав. Я просто говорю, что требование ICRx кажется избыточным с требованием, чтобы таймер был 16-битным. По крайней мере, для Uno и Mega, не уверен насчет других Arduinos на базе AVR. ОП понимают, что это обеспечивает только 2 канала ШИМ: см. Мой комментарий к его вопросу и его ответ.
Эдгар Бонет
2
@techniche: 1. У меня работает. Может быть , вы забыли установить COM4C1в TCCR4A? 2. Если это не проблема, тогда прочитайте Как мне задать хороший вопрос? затем обновите свой вопрос , включив полный исходный код и четко указав, что вы ожидаете от программы и что она делает вместо этого («я не вижу успеха» не считается действительным заявлением о проблеме).
Эдгар Бонет