Встановіть частоту ШІМ на 25 кГц


12

На даний момент я можу встановити чотири ШІМ-штифта приблизно до 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
}

Я десь знайшов цю установку, але не знаю, як я можу встановити ці чотири ШІМ-шпильки приблизно на 25 кГц. Як це можливо?


3
Ви розумієте, як працюють таймери AVR?
Ігнасіо Васкес-Абрамс


1
@ IgnacioVazquez-Abrams Я не знайомий, і мені потрібно встановити ці чотири штифта приблизно на 25 кГц на початку. Я поспішаю закінчити проект і буду рада будь-якій допомозі. Код у мене встановлюється на 31 кГц. Чи можу я змінити його на 25 кГц? Двигуни постійного струму вимагають такої частоти.
користувач16307

1
@ NickGammon Дякую, але в даний момент я не маю достатньо часу, щоб вивчити їх. Чи можете ви надати мені кодову частину для встановлення 25 кГц. Я програв
користувач16307

2
Мені потрібно налаштувати їх точні обороти, щоб їхні робочі цикли були дещо іншими. Як щодо того, чи можна встановити 2 штифта тільки на 25 кГц?
користувач16307

Відповіді:


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, який використовує інший процесор. Буду радий, якщо ви надасте
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()означає, що PIN-код буде завжди НИЗКОМ, тоді як 320 означає ВИСОКИЙ. Регулярний analogWrite() повинен майже працювати, але він буде тлумачити 255 так само, як 320 (тобто завжди ВИСОКИЙ).

Цей код передбачає Arduino Uno або подібну плату (ATmega168 або 328 @ 16 МГц). Метод, який використовується тут, вимагає 16-бітного таймера, і тому він використовує Таймер 1, оскільки це єдиний доступний в Uno; тому доступні лише два виходи. Метод може бути адаптований до інших плат на основі AVR з 16-бітовим таймером. Як зазначив Гербен, цей таймер повинен мати відповідний регістр ICRx. У Arduino Mega є 4 таких таймера, кожен з яких має 3 виходи.


1
Може бути корисним пояснити, що цей метод працює лише для таймера1, оскільки інші таймери не мають ICRxреєстру. Максимум, у вас може бути лише один штифт ШІМ на таймер, для таймерів 0 та 2.
Гербен

1
@Gerben: Чи не всі 16-бітові таймери мають такий реєстр? Принаймні, на Мезі вони роблять.
Едгар Боне

1
Так, але в таймері ATMega328 є лише 16-бітний timer1. Решта 8-бітні. І ОП хоче вивести 4 ШІМ, а ваше рішення забезпечує лише 2. Або я помиляюся?
Гербен

1
@ Гербен: Ні, ти маєш рацію. Я просто говорю, що вимагати ICRx видається зайвим, тому що таймер повинен бути 16-бітним. Принаймні, для Uno та Mega не впевнені в інших Arduinos на базі AVR. ОП розуміє, що це лише 2 канали ШІМ: дивіться мій коментар до його питання та його відповідь.
Едгар Бонет

2
@techniche: 1. Працює для мене. Може бути , ви забули встановити COM4C1в TCCR4A? 2. Якщо це не проблема, то прочитайте Як мені поставити гарне запитання? , то оновіть своє запитання , включивши повний вихідний код і чітко вказавши, що ви очікуєте від програми і що вона робить замість цього ("Я не бачу успіху" не вважається дійсним твердженням проблеми).
Едгар Бонет
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.