Збільшення дозволу біт ШІМ


10

Я хотів би збільшити роздільну здатність ШІМ для Arduino Uno. На даний момент це 8-бітний, який я вважаю занадто низьким. Чи можливо це без втрати здатності переривань і затримок?

Koen

РЕДАКТУВАННЯ Ця настройка забезпечує 16-бітну результативність

void setupPWM16() {
    DDRB |= _BV(PB1) | _BV(PB2);        /* set pins as outputs */
    TCCR1A = _BV(COM1A1) | _BV(COM1B1)  /* non-inverting PWM */
        | _BV(WGM11);                   /* mode 14: fast PWM, TOP=ICR1 */
    TCCR1B = _BV(WGM13) | _BV(WGM12)
        | _BV(CS11);                    /* prescaler: clock / 8 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> (16000000/8)/(65535+1)=30.5175Hz
*/

/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */
void analogWrite16(uint8_t pin, uint16_t val)
{
    switch (pin) {
        case  9: OCR1A = val; break;
        case 10: OCR1B = val; break;
    }
}

Відповіді:


16

Arduino Uno базується на мікроконтролері ATmega382P. Цей чіп має два 8-бітових таймерів, що управляють двома ШІМ-каналами кожен, і один 16-бітний таймер, що управляє останніми двома каналами.

Ви не можете збільшити роздільну здатність 8-бітових таймерів. Однак ви можете помістити 16-бітний таймер в 16-бітний режим замість 8-бітного режиму, який використовується в основній бібліотеці Arduino. Це дасть вам два 16-бітні ШІМ-канали зі зниженою частотою 244 Гц (максимум). Ймовірно, вам доведеться самостійно налаштувати таймер, і це не скористається простотою у користуванні analogWrite()функцією. Детальніше дивіться розділ про Таймер 1 в таблиці ATmega328P .

Оновлення : Ось реалізація 16-бітної analogWrite(). Він працює лише на штифтах 9 і 10, оскільки це єдині штирі, підключені до 16-бітного таймера.

/* Configure digital pins 9 and 10 as 16-bit PWM outputs. */
void setupPWM16() {
    DDRB |= _BV(PB1) | _BV(PB2);        /* set pins as outputs */
    TCCR1A = _BV(COM1A1) | _BV(COM1B1)  /* non-inverting PWM */
        | _BV(WGM11);                   /* mode 14: fast PWM, TOP=ICR1 */
    TCCR1B = _BV(WGM13) | _BV(WGM12)
        | _BV(CS10);                    /* no prescaling */
    ICR1 = 0xffff;                      /* TOP counter value */
}

/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */
void analogWrite16(uint8_t pin, uint16_t val)
{
    switch (pin) {
        case  9: OCR1A = val; break;
        case 10: OCR1B = val; break;
    }
}

Ви можете помітити, що вершина послідовності лічильників налаштована явно. Ви можете змінити це на менше значення, щоб зробити ШІМ швидше, ціною зменшеної роздільної здатності.

Ось приклад ескізу, що ілюструє його використання:

void setup() {
    setupPWM16();
}

/* Test: send very slow sawtooth waves. */
void loop() {
    static uint16_t i;
    analogWrite16(9, i);
    analogWrite16(10, 0xffff - i);
    i++;
    delay(1);
}

Дуже дякую, саме це мені потрібно. Я хочу, щоб результати ШІМ були такими ж, як і моя роздільна здатність. Якби я змінив ваш код на <подивитись на мою редагування>, це буде 13-розрядний результат? Якщо так, якою була б частота? Я буду їхати з ним мотор постійного струму, так що 244 Гц буде трохи менше, я здогадуюсь
KoenR

@KoenR: Ні, prescaler не впливає на дозвіл, його мета - уповільнити підрахунок. Якщо встановити дошкільник на 8, ви отримаєте частоту ШІМ 30,5 Гц. Якщо ви хочете 13 - бітове дозвіл, набір ICR1для 0x1fff, тоді ваша частота буде 1953 Гц (F_CPU / (TOP + 1)) з подільником на 1.
Едгар Бонет

Дякую за пояснення. Редагував моє запитання так, щоб воно охоплювало ці помилки. Тож інші люди можуть бачити це безпосередньо. Дякую!
KoenR

1
@Edgar Bonet Це чудово, проте я не можу повністю вимкнути світлодіод. Я використовую, ICR1 = 0x03FFі при 0 я бачу крихітний імпульс на масштабі, достатній для того, щоб засвітити світлодіод. Будь-які ідеї?
davidvid

1
@davivid: Так, ви не можете мати нульовий цикл роботи. analogWrite16(pin, val)дає робочий цикл (val + 1) / ICR1. Як вирішення, Ардуїно це analogWrite()робить if (val == 0) digitalWrite(pin, LOW); else if (val == 255) digitalWrite(pin, HIGH);. Але тоді ви не можете отримати робочий цикл 1 / ICR1 ...
Едгар Бонет

3

За допомогою деякої калібрування ви можете підсумувати виходи двох каналів ШІМ з різними ваговими резисторами. В крайньому випадку, ви можете навмисно використати один вихід, щоб надати 8 біт роздільної здатності та масштабувати інший на 1/256-й рівень та додати їх, щоб 2-й канал охоплював один біт діапазону, і ви (знову усвідомлено) отримуєте 16 біт роздільної здатності. Без величезної турботи та налаштування все, що ви отримаєте, було б безладом.
Однак, розділивши 2-й канал на 16 або 32, ви можете додати кілька додаткових розрядів ШІМ. Лише додаючи 2 канали ШІМ аналогових відфільтрованих виходів, ви додаєте додатковий біт (оскільки діапазон потенціалів збільшується вдвічі за незмінний мВ / біт).
Умовно (знову ж таки) за кожен додатковий поділ на 2 ви отримуєте додатковий біт роздільної здатності, але це може бути здійснено лише для, можливо, 4 або 5 або 6 додаткових біт, із збільшенням вимог до точності масштабування резисторів та більш важкої калібрування та схильності до помилок .

Короткий приклад.
Якщо одну ШІМ зменшити, щоб сказати 0 - 255 мВ на кроці 1 мВ, то підсумовування двох ШІМ з однаковою амплітудою дало б діапазон від 0 до 510 мВ за кроки 1 мВ.
Якщо одну ШІМ зменшити на коефіцієнт 32, то замість того, щоб додати початковий діапазон ШІМ 255 мВ, до верхнього кінця було б додано лише 8 мВ (0,256,32 = 8 мВ, але роздільна здатність буде 0,03125 (1/32 ) кроки мВ.

Хоча це, можливо, може бути досягнуто виключно за допомогою підбиття резисторів та фільтрації на RC, використання літрів підсилювача значно покращить результати.

Також пульсація ШІМ може бути відфільтрована за допомогою простого RC-фільтра, але використання одного оппаму в якості буфера (або навіть просто одного транзистора як послідовник випромінювача) дасть вам 3 або 5 полюсів низькочастотної фільтрації та набагато більше шансів на отримання додаткової ШІМ дозвіл. Я не перевіряв "фазову узгодженість" виходів ШІМ, але очікую, що вони рухаються у відносному стоп-шасі, щоб ви не отримали корисної переваги додавання двох некоррельованих форм сигналів.

Більше коментарів можна зробити за потреби. Запитайте, чи зацікавлені.


Це розумно! Здається, бібліотека синтезу звуку Mozzi використовує цей трюк для так званого режиму «HIFI».
Едгар Бонет

Це чудовий нас із ШІМ. Але хіба це не згладить форму хвилі? Я запитую це, оскільки ви використовуєте RC-фільтр. Я не згадував це у своєму питанні, але я за кермом двигуна постійного струму з ним <соромлюсь>. Дякую за вклад!
KoenR

@KoenR (fwiw: Я не бачу нічого, чого слід соромитися.) Я не знаю, яку частоту відповідь / швидкість зміни ви хочете у своєму виході АЦП. Або чому ви хочете N біт або як достатньо великого. Зазвичай мотори не будуть корисно керуватися більш ніж 8 бітами - залежить від того, наскільки точна програма у вас є. Двигун виступає частиною згладжуючого фільтра через індуктивність. Вам потрібно сказати, що це за мотор і як керують. І схема принципово важлива. Якщо мотор крихітний, у вас є водій. ШИМ, що живиться з щіткою, повинен мати діод уловлювача для пропускання струму двигуна, коли ШІМ вимкнено. Додавання двох ...
Рассел Макмахон

... ШІМ тут можна по-справжньому виконати, але деталі схеми потрібно знати.
Рассел Макмахон

Остерігайся! У деяких випадках згладжування ШІМ з низькочастотним RC не бажано. Наприклад, якщо ви підключите вихід Arduino до воріт MOSFET, MOSFET буде залишатися холодним, доки він керується чистою ШІМ. Але якщо ви його згладите, MOSFET почне розсіювати набагато більше тепла. Іноді це не дуже добре.
Флорін Андрій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.