PWMビットの解像度を上げる


9

Arduino UnoのPWMビット解像度を上げたいのですが。現時点では8ビットですが、低すぎると思います。これは、割り込みと遅延の機能を失うことなく可能ですか?

公園

編集このセットアップは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マイクロコントローラーに基づいています。このチップには、2つのPWMチャネルをそれぞれ駆動する2つの8ビットタイマーと、最後の2つのチャネルを駆動する1つの16ビットタイマーがあります。

8ビットタイマーの分解能を上げることはできません。ただし、Arduinoコアライブラリで使用される8ビットモードの代わりに、16ビットタイマーを16ビットモードにすることができます。これにより、周波数が244 Hz(最大)に低減された2つの16ビットPWMチャネルが得られます。おそらく自分でタイマーを設定する必要があり、使いやすいanalogWrite()機能から利益を得ることはありません。詳細については、ATmega328P データ シートのタイ 11に関する項をご覧ください。

更新:これは16ビットの実装ですanalogWrite()。これらは16ビットタイマーに接続されている唯一のピンであるため、ピン9と10でのみ機能します。

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

カウンターシーケンスの上部が明示的に構成されていることに気付くでしょう。これをより小さい値に変更すると、分解能が低下しますが、PWMが高速になります。

そして、これはその使用法を説明するスケッチ例です:

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

わぁありがとうございます、これがまさに私が必要としていることです。PWM結果をセンサー解像度と同じにしたい。コードを<look at my edit>に変更すると、13ビットの結果になりますか?もしそうなら、頻度は何ですか?私はそれでDCモーターを駆動するので、244Hzは少し少ないと思います
KoenR

@KoenR:いいえ、プリスケーラは分解能に影響を与えません。それは、カウントを遅くすることを目的としています。プリスケーラを8に設定すると、PWM周波数は30.5 Hzになります。あなたは13ビットの分解能、セットしたい場合ICR1には0x1fff、その後、あなたの頻度は1で、プリスケーラと1953ヘルツ(F_CPU /(TOP + 1))になります
エドガー・ボネット

ご説明ありがとうございます。これらの間違いをカバーするように私の質問を編集しました。他の人はそれを直接見ることができます。ありがとうございました!
KoenR

1
@Edgar Bonetこれは素晴らしいですが、LEDを完全にオフにできないようです。私は使用ICR1 = 0x03FFしていて、0で、LEDを点灯するのに十分な小さなパルスがスコープに表示されています。何か案は?
davivid 2017年

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のデューティサイクルを取得することはできません...
エドガーボネット2017年

3

いくつかのキャリブレーションを使用すると、異なる重み付け抵抗を持つ2つのPWMチャネルの出力を合計できます。極端な場合、1つの出力を使用して8ビットの解像度を提供し、もう1つの出力をレベルの1/256にスケーリングし、それらを追加して、2番目のチャネルが1ビットの範囲をカバーし、(概念的には)16ビットの解像度を得ることができます。計り知れない注意と調整がなければ、あなたが得るすべては混乱です。
ただし、2番目のチャネルを16または32で除算することにより、PWM分解能のビットをさらに追加できます。2つのPWMチャネルアナログフィルター出力を追加するだけで、ビットが1つ追加されます(変化するmV /ビットに対して電位範囲が2倍になるため)。
理論上(再び)2で除算するたびに、追加のビットの解像度が得られますが、これは、4または5または6の追加ビットでのみ実行でき、スケーリング抵抗の精度要件が高くなり、キャリブレーションが難しくなり、エラーが発生しやすくなります。 。

簡単な例。
1つのPWMを1 mVステップで0〜255 mVに縮小する場合、2つのPWMを同じ振幅で加算すると、0〜510 mVの範囲が1 mVステップで得られます。
1つのPWMを32倍に縮小すると、最初のPWM範囲に255 mVを追加する代わりに、8 mVだけがトップエンドに追加されます(0.256.32 = 8 mVですが、分解能は0.03125(1 / 32nd )mVステップ。

これはおそらく純粋に抵抗加算とRCフィルタリングで実現できますが、オペアンプサマーを使用すると結果が大幅に改善されます。

また、PWMリップルは単純なRCフィルターでフィルター処理できますが、バッファーとして1つのオペアンプ(またはエミッターフォロアーとして単一のトランジスターのみ)を使用すると、3つまたは5つの極のローパスフィルターが得られ、追加のPWMを達成する可能性が高くなります。解決。私はPWM出力の「位相コヒーレンス」を検査していませんが、それらが相対ロックステップで移動するため、2つの非相関波形を追加することによる平滑化の利点が得られないことを期待しています。

必要に応じてコメントを追加できます。興味があるか尋ねてください。


これは賢いです!思われMozzi音声合成ライブラリは、それがそのように「HIFI」モードと呼ばれるためにこのトリックを使用しています。
Edgar Bonet、2015年

それはPWMの素晴らしい私たちです。しかし、これは波形を滑らかにしませんか?RCフィルターを使用しているため、これをお願いします。私の質問ではこれについて言及していませんが、DCモーターを<恥ずかしい気持ち>で駆動しています。ご入力ありがとうございます!
KoenR

@KoenR(fwiw:恥ずかしいことは何も見当たらない。)ADC出力にどのような周波数応答/変化率が必要かわからない。または、なぜNビットが必要なのか、それとも十分な大きさで十分なのか。モーターは通常、8ビット以上では効果的に制御されません-アプリケーションの精度に依存します。モーターはインダクタンスにより平滑フィルターの一部として機能します。どのようなモーターとどのように駆動されるかを言う必要があります。そして回路図は必須です。モーターが小さい場合を除き、ドライバーがいます。PWMが供給されているブラシ付きモーターには、PWMがオフのときにモーター電流を流すためのキャッチダイオードが必要です。2つ追加しています...
ラッセルマクマホン

...ここのPWMは完全に実行可能ですが、回路の詳細を知る必要があります。
ラッセルマクマホン

注意してください!場合によっては、ローパスRCでPWMを平滑化することが望ましくありません。たとえば、Arduinoの出力をMOSFETのゲートに接続すると、クリーンなPWMで駆動されている限り、MOSFETは低温のままになります。しかし、それを滑らかにすると、MOSFETはより多くの熱を放散し始めます。時にはそれは良いことではありません。
Florin Andrei、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.