PWM frekansını 25 kHz olarak ayarlayın


12

Şu anda dört PWM pini aşağıdaki kodla yaklaşık 31 kHz'e ayarlayabilirim:

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
}

Bu kurulumu bir yerde buldum, ancak bu dört PWM pimini nasıl 25 kHz'e ayarlayabileceğimi bilmiyorum. Bu nasıl mümkün olabilir?


3
AVR zamanlayıcılarının nasıl çalıştığını anlıyor musunuz?
Ignacio Vazquez-Abrams

3
Zamanlayıcılar hakkındaki sayfama bakın .
Nick Gammon

1
@ IgnacioVazquez-Abrams Tanıdık değilim ve başlangıçta bu dört pimi 25kHz civarında ayarlamam gerekiyor. Bir projeyi bitirmek için acele ediyorum ve herhangi bir yardımdan memnuniyet duyarım. Sahip olduğum kod 31kHz olarak ayarlanmış. 25kHz olarak değiştirebilir miyim? DC motorlar bu frekansı gerektirir.
user16307

1
@NickGammon Teşekkürler ama gerçekten şu anda bunları incelemek için yeterli zamanım yok. 25kHz kurulumu için bana kod kısmını verebilir misiniz? Kayboldum
user16307

2
Görev döngüleri biraz farklı olacak şekilde tam devirlerini ayarlamam gerekiyor. 2 pimi sadece 25 kHz'e ayarlamak nasıl mümkün olabilir?
user16307

Yanıtlar:


10

Bu ikinci cevabı, tek bir Arduino Uno'da 161 adımla 25 kHz'de 4 PWM kanalına sahip olmanın mümkün olduğunu fark ettiğim için gönderiyorum. Bu, ana saat frekansının 8 MHz olarak değiştirilmesini içerir , bu da tüm programın yarısı kadar hızlı çalışacağından bazı yan etkilere sahiptir. Ayrıca üç süreleri, Arduino zamanlama fonksiyonlarını kaybetme araçları yeniden yapılandırma içermektedir ( millis(), micros(), delay()ve delayMicroseconds()). Eğer bu değiş tokuşlar kabul edilebilirse, işte böyle gidiyor:

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
}

Diğer cevabın aksine, bunun değiştirilmiş bir versiyonuna ihtiyacı yoktur analogWrite(): standart olan iyi çalışır. Sadece dikkatli olunmalıdır:

  1. Yazılan değer, 0 (her zaman DÜŞÜK anlamına gelir) ile 160 (her zaman YÜKSEK) arasında olmalıdır.
  2. Sadece 3, 5, 9 ve 10 pinleri mevcuttur. analogWrite() Pim 6 veya 11'e girişmek sadece bir PWM çıkışı iletmekle kalmaz, aynı zamanda pim 5 veya 3'teki frekansı da değiştirir.

Çok uzun zaman oldu ve şimdi başka bir işlemci kullanan Arduino Due ile aynı şeyle sıkışıp kaldım. Burada herhangi bir girdi olsaydı sevinirim arduino.stackexchange.com/questions/67053/…
user16307

11

Zamanlayıcı 1'i faz doğru PWM modunda 25 kHz'de dönecek şekilde yapılandırabilir ve 9 ve 10 pinlerinde iki çıkışı aşağıdaki gibi kullanabilirsiniz:

// 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 ile bir değer yazmak analogWrite25k()pimin her zaman DÜŞÜK olacağı anlamına gelirken, 320 her zaman YÜKSEK anlamına gelir. Düzenli analogWrite() gerektiği neredeyse eser, ancak 255 (yani her zaman YÜKSEK) 320 ile aynı yorumlayacaktır.

Bu kod bir Arduino Uno veya benzeri bir kartı (ATmega168 veya 328 @ 16 MHz) varsayar. Burada kullanılan yöntem 16 bitlik bir zamanlayıcı gerektirir ve bu nedenle Uno'da kullanılabilen tek zamanlayıcı olduğu için Zamanlayıcı 1'i kullanır; bu yüzden sadece iki çıkış mevcuttur. Yöntem, 16 bitlik bir zamanlayıcı ile diğer AVR tabanlı kartlara uyarlanabilir. Gerben'in belirttiği gibi, bu zamanlayıcının karşılık gelen bir ICRx kaydına sahip olması gerekir. Arduino Mega'da her biri 3 çıkışlı 4 zamanlayıcı var.


1
Diğer zamanlayıcıların ICRxkaydı olmadığı için bu yöntemin yalnızca timer1 için çalıştığını açıklamak yararlı olabilir . Zamanlayıcı başına en fazla 0 ve 2. zamanlayıcılar için yalnızca bir PWM pinine sahip olabilirsiniz
Gerben

1
@Gerben: 16-bit zamanlayıcıların hepsinde bu kayıt yok mu? En azından Mega'da yapıyorlar.
Edgar Bonet

1
Evet, ancak ATMega328'de sadece zamanlayıcı1 16 bittir. Geri kalanı 8 bit. Ve OP 4 PWM çıkışı istiyor ve çözümünüz sadece 2 sağlıyor. Yoksa yanılıyor muyum?
Gerben

1
@Gerben: Hayır, haklısın. Sadece ICRx'e ihtiyaç duymanın, zamanlayıcının 16 bit olmasını gerektiren gereksiz görünüyor. En azından Uno ve Mega için diğer AVR tabanlı Arduino'lardan emin değilim. OP bunun sadece 2 PWM kanalı sağladığını anlıyor: sorusu ve cevabı hakkındaki yorumuma bakın.
Edgar Bonet

2
@ techniche: 1. Benim için çalışıyor. Belki kurmayı unuttuğu COM4C1içinde TCCR4A? 2. Sorun bu değilse, nasıl iyi bir soru sorabilirim? Başlıklı konuyu okuyun. , daha sonra tam kaynak kodunuzu ekleyerek ve programın ne yapmasını beklediğinizi ve bunun yerine ne yaptığını açıkça belirterek sorunuzu güncelleyin (“Herhangi bir başarı göremiyorum” geçerli bir sorun bildirimi sayılmaz).
Edgar Bonet
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.