PWM周波数を25 kHzに設定


12

現在、次のコードで4つのPWMピンを約31 kHzに設定できます。

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
}

どこかでこの設定を見つけましたが、代わりにこれらの4つのPWMピンを約25 kHzに設定する方法がわかりません。そんなことがあるものか?


3
AVRタイマーの仕組みを理解していますか?
Ignacio Vazquez-Abrams


1
@ IgnacioVazquez-Abrams慣れていないので、最初はこれらの4つのピンを約25kHzに設定する必要があります。私はプロジェクトを急ぐ必要があり、どんな助けでも喜んでいます。私が持っているコードは31kHzに設定しています。25kHzに変更できますか?DCモーターにはその周波数が必要です。
user16307

1
@NickGammonありがとうございます。しかし、現時点でこれらを研究する十分な時間がありません。25kHzを設定するためのコード部分を教えてください。負けました
user16307

2
彼らの正確なrpmを調整する必要があるので、彼らのデューティサイクルは少し異なります。2つのピンを25kHzのみに設定することは可能ですか?
user16307

回答:


10

単一のArduino Unoで161ステップの25 kHzの4つのPWMチャネルを持つことが可能であることを理解したので、この2番目の回答を投稿します。これには、メインクロック周波数を8 MHz変更することが含まれます。これは、プログラム全体が半分の速度で実行されるため、いくつかの副作用があります。また、3個のタイマ、Arduinoのタイミング機能を失う手段を再構成することを含む(millis()micros()delay()および delayMicroseconds())。これらのトレードオフが許容できる場合は、次のようになります。

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
}

他の回答とは異なり、これはの変更されたバージョンを必要としませんanalogWrite()。標準の回答は 正常に機能します。次のことに注意してください。

  1. 書き込まれる値は、0(常にLOW)と160(常にHIGH)の間でなければなりません。
  2. ピン3、5、9、および10のみが使用可能です。analogWrite() ピン6または11に接続しようとすると、PWM出力の配信に失敗するだけでなく、ピン5または3の周波数もそれぞれ変化します。

非常に長い間、今では別のプロセッサを使用するArduino Dueで同じことが起きています。あなたがここに任意の入力をHAE場合、私は喜んでいるだろうarduino.stackexchange.com/questions/67053/...
user16307

11

位相補正PWMモードで25 kHzでサイクルするようにタイマー1を構成し、ピン9と10で2つの出力を使用することができます。

// 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を書き込むanalogWrite25k()と、ピンは常にLOWになりますが、320は常にHIGHを意味します。レギュラーanalogWrite()ほぼ機能するはずですが、255は320と同じように解釈されます(つまり、常にHIGH)。

このコードは、Arduino Unoまたは同様のボード(ATmega168または328 @ 16 MHz)を想定しています。ここで使用する方法には16ビットタイマーが必要です。そのため、Unoで使用できるのはタイマー1だけなので、タイマー1を使用します。そのため、2つの出力しか使用できません。この方法は、16ビットタイマーを備えた他のAVRベースのボードに適応できます。Gerbenが述べたように、そのタイマーには対応するICRxレジスタが必要です。Arduino Megaには4つのタイマーがあり、それぞれに3つの出力があります。


1
他のタイマーにはICRxレジスターがないため、このメソッドはtimer1に対してのみ機能することを説明すると役立つ場合があります。せいぜい、あなただけのタイマー0と2のために、タイマーごとにPWMピンを持つことができます
Gerben

1
@Gerben:すべての16ビットタイマーにそのレジスタがあるわけではありませんか?少なくとも彼らはメガで。
Edgar Bonet

1
はい。ただし、ATMega328ではtimer1のみが16ビットです。残りは8ビットです。そして、OPは4つのPWM出力を必要とし、ソリューションは2つしか提供しません。または、私は間違っていますか?
Gerben 2016年

1
@ガーベン:いいえ、あなたは正しいです。ICRxを要求することは、タイマーを16ビットにすることを要求することと冗長であるように思えます。少なくともUnoとMegaについては、他のAVRベースのArduinoについてはわかりません。OPは、これが2つのPWMチャネルしか提供しないことを理解しています。彼の質問と彼の回答に関する私のコメントを参照してください。
Edgar Bonet、2016年

2
@techniche:1.私のために働く。設定するのを忘れCOM4C1たのTCCR4Aかな?2.それが問題ではない場合は、「良い質問をするにはどうすればよいですか?」をお読みください。次に、完全なソースコードを含め、プログラムが何を期待し、代わりに何を行うかを明確に記載して、質問を更新します(「成功しなかった」は有効な問題ステートメントとは見なされません)。
エドガーボネット2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.