Увеличьте битовое разрешение ШИМ


9

Я хотел бы увеличить разрешение PWM бит 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;
    }
}

Ответы:


15

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: Нет, прескалер не влияет на разрешение, его цель - замедлить подсчет. Установка прескалера на 8 даст вам частоту ШИМ 30,5 Гц. Если вы хотите разрешение 13 бит, установите ICR1на 0x1fff, тогда ваша частота будет 1953 Гц (F_CPU / (TOP + 1)) с прескалером на 1.
— Эдгар Бонет

Спасибо за объяснение. Отредактировал мой вопрос так, чтобы он покрывал эти ошибки. Так что другие люди могут видеть это напрямую. Спасибо!
— KoenR

1
@ Эдгар Бонет: Это здорово, но я не могу полностью выключить светодиод. Я использую, ICR1 = 0x03FFи в 0 я вижу крошечный пульс на прицеле, достаточный, чтобы зажечь светодиод. Любые идеи?
— Давид

1
@davivid: Да, у вас не может быть нулевого рабочего цикла. analogWrite16(pin, val)дает рабочий цикл (val + 1) / ICR1. Как обходной путь, Arduino analogWrite()делает if (val == 0) digitalWrite(pin, LOW); else if (val == 255) digitalWrite(pin, HIGH);. Но тогда вы не можете получить рабочий цикл 1 / ICR1 ...
— Эдгар Бонет

3

С помощью некоторой калибровки вы можете суммировать выходы двух каналов ШИМ с различными весовыми резисторами. В крайнем случае вы можете условно использовать один выход для обеспечения 8-битного разрешения, а другой масштабировать до 1/255-го уровня и добавлять их так, чтобы 2-й канал покрывал один бит диапазона, и вы (опять же условно) получили 16-битное разрешение. Без огромной заботы и настройки все, что вы получите, будет беспорядок.
Однако, разделив 2-й канал на 16 или 32, вы можете добавить несколько дополнительных битов PWM-разрешения. Просто добавив 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.