Atur frekuensi PWM ke 25 kHz

12

Saat ini saya dapat mengatur empat pin PWM menjadi sekitar 31 kHz dengan kode berikut:

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
}

Saya menemukan pengaturan ini di suatu tempat, tetapi saya tidak tahu bagaimana saya dapat mengatur empat pin PWM ini menjadi sekitar 25 kHz. Bagaimana mungkin?

pengguna16307
sumber
3
Apakah Anda mengerti cara kerja penghitung waktu AVR?
Ignacio Vazquez-Abrams
3
Lihat halaman saya tentang timer .
Nick Gammon
1
@ IgnacioVazquez-Abrams Saya tidak terbiasa dan saya perlu mengatur empat pin sekitar 25kHz di awal. Saya sudah terburu-buru menyelesaikan sebuah proyek dan saya akan dengan senang hati membantu. Kode saya set ke 31kHz. Bisakah saya memodifikasinya menjadi 25kHz? Motor DC membutuhkan freq itu.
user16307
1
@NickGammon Terima kasih, tetapi saya benar-benar tidak punya cukup waktu untuk mempelajarinya saat ini. Bisakah Anda memberi saya bagian kode untuk pengaturan 25kHz. Saya hilang
user16307
2
Saya perlu menyetel rpm yang tepat sehingga siklus tugas mereka akan sedikit berbeda. Bagaimana mungkin menetapkan 2 pin hanya untuk 25kHz?
user16307

Jawaban:

10

Saya memposting jawaban kedua ini karena saya menyadari mungkin untuk memiliki 4 saluran PWM pada 25 kHz dengan 161 langkah pada satu Arduino Uno. Ini melibatkan mengubah frekuensi clock utama ke 8 MHz , yang memiliki beberapa efek samping karena seluruh program akan berjalan setengah lebih cepat. Hal ini juga melibatkan konfigurasi ulang tiga timer, yang berarti kehilangan Arduino waktu fungsi ( millis(), micros(), delay()dan delayMicroseconds()). Jika pertukaran ini dapat diterima, berikut adalah caranya:

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
}

Tidak seperti jawaban yang lain , ini tidak memerlukan versi modifikasi analogWrite(): yang standar akan berfungsi dengan baik. Hanya harus diperhatikan bahwa:

  1. Nilai yang ditulis harus antara 0 (artinya selalu RENDAH) dan 160 (selalu TINGGI), inklusif.
  2. Hanya pin 3, 5, 9 dan 10 yang tersedia. Mencoba ke analogWrite() pin 6 atau 11 tidak hanya akan gagal memberikan output PWM, itu juga akan mengubah frekuensi masing-masing pada pin 5 atau 3.
Edgar Bonet
sumber
Sudah sangat lama dan sekarang saya terjebak dengan hal yang sama dengan Arduino Due yang menggunakan prosesor lain. Saya akan senang jika Anda memiliki input apa pun di sini arduino.stackexchange.com/questions/67053/…
user16307
11

Anda dapat mengkonfigurasi Timer 1 untuk siklus pada 25 kHz dalam mode PWM fase yang benar, dan menggunakannya dua output pada pin 9 dan 10 seperti:

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

Menulis nilai 0 dengan analogWrite25k()berarti pin akan selalu RENDAH, sedangkan 320 berarti selalu TINGGI. Biasa analogWrite() harus hampir bekerja, tetapi itu akan menafsirkan 255 sama dengan 320 (yaitu selalu TINGGI).

Kode ini mengasumsikan Arduino Uno atau papan serupa (ATmega168 atau 328 @ 16 MHz). Metode yang digunakan di sini memerlukan timer 16-bit, dan karenanya menggunakan Timer 1 karena itu hanya satu-satunya yang tersedia di Uno; itu sebabnya hanya dua output yang tersedia. Metode ini dapat disesuaikan dengan papan berbasis AVR lainnya dengan timer 16-bit. Seperti yang dicatat Gerben, timer itu harus memiliki register ICRx yang sesuai. Ada 4 timer seperti itu di Arduino Mega, masing-masing dengan 3 output.

Edgar Bonet
sumber
1
Mungkin bermanfaat untuk menjelaskan bahwa metode ini hanya berfungsi untuk timer1, karena penghitung waktu lain tidak memiliki ICRxregister. Paling banyak, Anda hanya dapat memiliki satu pin PWM per timer, untuk timer 0 dan 2.
Gerben
1
@Gerben: Tidak semua timer 16-bit memiliki register itu? Setidaknya pada Mega yang mereka lakukan.
Edgar Bonet
1
Ya, tetapi hanya timer1 yang 16-bit pada ATMega328. Sisanya 8-bit. Dan OP menginginkan 4 output PWM, dan solusi Anda hanya menyediakan 2. Atau saya salah?
Gerben
1
@Gerben: Tidak, Anda benar. Saya hanya mengatakan bahwa membutuhkan ICRx tampaknya berlebihan dengan membutuhkan timer menjadi 16-bit. Untuk Uno dan Mega setidaknya, tidak yakin tentang Arduino berbasis AVR lainnya. OP mengerti ini hanya menyediakan 2 saluran PWM: lihat komentar saya pada pertanyaannya dan jawabannya.
Edgar Bonet
2
@ techniche: 1. Bekerja untuk saya. Mungkin Anda lupa untuk mengatur COM4C1di TCCR4A? 2. Jika bukan itu masalahnya, maka baca Bagaimana cara saya mengajukan pertanyaan yang bagus? , kemudian perbarui pertanyaan Anda dengan memasukkan kode sumber lengkap Anda dan dengan jelas menyatakan apa yang Anda harapkan untuk dilakukan oleh program dan apa yang dilakukannya (“Saya tidak melihat keberhasilan apa pun” tidak dianggap sebagai pernyataan masalah yang valid).
Edgar Bonet