PWM bit çözünürlüğünü artırın


10

Arduino Uno'nun PWM bit çözünürlüğünü arttırmak istiyorum. Şu anda çok düşük olduğunu düşündüğüm 8 bit. Kesinti ve gecikme yeteneğini kaybetmeden bu mümkün müdür?

Koen

DÜZENLE Bu kurulum 16 bit sonuç verir

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;
    }
}

Yanıtlar:


16

Arduino Uno, bir ATmega382P mikrodenetleyicisine dayanmaktadır. Bu çipin her biri iki PWM kanalı süren iki adet 8 bit zamanlayıcı ve son iki kanalı süren bir 16 bit zamanlayıcı vardır.

8 bitlik zamanlayıcıların çözünürlüğünü artıramazsınız. Bununla birlikte, 16 bit zamanlayıcıyı Arduino çekirdek kütüphanesi tarafından kullanılan 8 bit modu yerine 16 bit moduna koyabilirsiniz. Bu, 244 Hz (maksimum) frekansı azaltılmış iki adet 16 bit PWM kanalı verecektir. Muhtemelen zamanlayıcıyı kendiniz yapılandırmanız gerekecek ve kullanımı kolay analogWrite()işlevden yararlanamayacaksınız. Ayrıntılar için, ATmega328P veri sayfasındaki Zamanlayıcı 1 ile ilgili bölüme bakın .

Güncelleme : İşte 16 bitlik bir uygulama analogWrite(). 16-bit zamanlayıcıya bağlı olan tek pim oldukları için sadece 9 ve 10 pinlerinde çalışır.

/* 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;
    }
}

Sayaç sırasının üst kısmının açıkça yapılandırıldığını fark edebilirsiniz. PWM'yi düşük çözünürlük pahasına daha hızlı hale getirmek için bunu daha küçük bir değere değiştirebilirsiniz.

Ve kullanımını gösteren bir örnek çizim:

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);
}

Vay canına çok teşekkür ederim, tam da ihtiyacım olan şey bu. PWM sonucumun Sensör Çözünürlüğüm ile aynı olmasını istiyorum. Kodunuzu <düzenlememe bak> olarak değiştirirsem 13 bit sonuç olur mu? Eğer öyleyse, frekans ne olurdu? Onunla bir DC motor kullanacağım, bu yüzden 244Hz biraz daha az olacak
KoenR

@KoenR: Hayır, ölçeklendiricinin çözünürlük üzerinde bir etkisi yoktur, amacı sayımı yavaşlatmaktır. Ön ölçekleyiciyi 8 olarak ayarlamak size 30,5 Hz PWM frekansı verecektir. Eğer 13 bit çözünürlük seti istiyorsanız ICR1için 0x1fff1. bir ön ölçekleme ile, sonra frekans 1953 Hz olacaktır (F_CPU / (TOP + 1))
Edgar Bonet

Açıklama için teşekkürler. Sorumu bu hataları kapsayacak şekilde düzenledi. Böylece diğer insanlar doğrudan görebilir. Teşekkür ederim!
KoenR

1
@Edgar Bonet Bu harika, ancak bir LED'i tamamen kapatamıyorum. Kullanıyorum ICR1 = 0x03FFve 0'da, led'i yakacak kadar küçük bir darbe görüyorum. Herhangi bir fikir?
davivid

1
@davivid: Evet, sıfır görev döngünüz olamaz. analogWrite16(pin, val)(val + 1) / ICR1 görev döngüsünü verir. Çözüm olarak, Arduino analogWrite()bunu yapar if (val == 0) digitalWrite(pin, LOW); else if (val == 255) digitalWrite(pin, HIGH);. Ama sonra 1 / ICR1 görev döngüsünü alamazsınız ...
Edgar Bonet

3

Bazı kalibrasyonlarda, farklı ağırlık dirençlerine sahip iki PWM kanalının çıkışlarını toplayabilirsiniz. En uçta, 8 bit çözünürlük sağlamak ve diğerini seviyenin 1 / 256'sına kadar ölçeklendirmek ve bunları eklemek için 2. kanal bir aralık aralığını kapsayacak şekilde ekleyebilir ve (yine de) 16 bit çözünürlük elde edebilirsiniz. Muazzam bir bakım ve ayar olmadan elde edeceğiniz her şey bir karışıklık olacaktır.
Ancak 2. kanalı 16 veya 32'ye bölerek birkaç ekstra PWM çözünürlüğü ekleyebilirsiniz. Sadece 2 PWM kanalı ekleyerek analog filtrelenmiş çıkışlar ekstra bir bit eklersiniz (değişmeyen mV / bit için potansiyel aralık iki katına çıktığından).
Notion olarak (tekrar) 2'ye kadar her ek bölünme için ekstra bir çözünürlük elde edersiniz, ancak bu sadece 4 veya 5 veya 6 ekstra bit için yapılabilir, ölçekleme dirençlerinin artan doğruluk gereksinimleri ve daha zor kalibrasyon ve hatalara yatkınlık .

Kısa bir örnek.
Bir PWM, 1 mV'lik adımda 0 - 255 mV verecek şekilde ölçeklendirilirse, eşit genliğe sahip iki PWM'nin toplanması 1 mV'lik adımlarda 0 - 510 mV aralığı verecektir.
Bir PWM 32 faktörü ile ölçeklendirilirse, ilk PWM aralığına 255 mV eklemek yerine üst uca sadece 8 mV ekler (0.256.32 = 8 mV, ancak çözünürlük 0.03125 (1 / 32nd) olur ) mV adımları.

Bu sadece direnç toplaması ve RC filtrelemesi ile elde edilebilirse de, bir op amp yaz kullanımı sonuçları büyük ölçüde geliştirecektir.

Ayrıca PWM dalgalanması basit bir RC filtresi ile filtrelenebilir, ancak bir opampın tampon olarak kullanılması (veya bir verici takipçisi olarak sadece tek bir transistör) size 3 veya 5 kutuplu düşük geçişli filtreleme ve ekstra PWM elde etme şansı verir çözüm. PWM çıkışlarının "faz tutarlılığı" nı kontrol etmedim, ancak göreceli kilit adımında hareket etmelerini bekledim, böylece iki ilişkisiz dalga formu eklemenin düzgünleştirme avantajını elde edemezsiniz.

Gerekirse daha fazla yorum yapılabilir. İlgilenip ilgilenmediğinizi sorun.


Bu akıllıca! O görünüyor Mozzi sesin sentez kütüphane o kadar “HIFI” modunda denir bu hile kullanır.
Edgar Bonet

Bu PWM'nin büyük bir bizleri. Ama bu dalga formunu düzeltemez mi? RC filtresi kullandığınız için bunu soruyorum. Sorumda bundan bahsetmedim ama <utanç hissi> veren bir DC motor kullanıyorum. Giriş için teşekkürler!
2015 KoenR

@KoenR (fwiw: Utanılacak hiçbir şey görmüyorum.) ADC çıktınızda hangi frekans tepkisini / değişim hızını istediğinizi bilmiyorum. Ya da N bitini neden istiyorsun ya da ne kadar büyük. Motorlar genellikle 8 bitten fazla tarafından kullanışlı bir şekilde kontrol edilmez - bir uygulamanın sahip olduğunuz hassasiyete bağlıdır. Motor, endüktans nedeniyle bir düzeltme filtresinin bir parçası olarak hareket eder. Ne tür bir motor ve nasıl sürüldüğünü söylemelisiniz. Ve bir devre şeması esastır. Motor küçük olmadığı sürece bir sürücünüz var. PWM beslendiğinde, fırçalı bir PWM motorunda motor akımını geçmek için bir yakalama diyodu olmalıdır. İki ekleme ...
Russell McMahon

... Buradaki PWM'ler tamamen yapılabilir ancak devre detaylarının bilinmesi gerekir.
Russell McMahon

Dikkat! Bazı durumlarda, PWM'yi düşük geçişli bir RC ile yumuşatmak istenmez. Örneğin, Arduino çıkışını bir MOSFET'in kapısına takarsanız, MOSFET temiz PWM tarafından sürüldüğü sürece soğuk kalacaktır. Ancak yumuşatırsanız, MOSFET çok daha fazla ısı yaymaya başlayacaktır. Bazen bu iyi bir şey değildir.
Florin Andrei
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.