3

ATMega328P で PWM 波形生成モードを試しています。奇妙な結果が得られましたが、それがファームウェアの書き方に問題があるのか​​、それともデータシートの解釈に問題があるのか​​ わかりません。

analogWrite() 関数をエミュレートするために私が書いた最初のコードは次のとおりです。

// Waveform Generation Mode 0
// Table 15-4 of the datasheet

void setup()
{
  DDRB = (1<<PB1); // set pin 9 as output

  TCCR1A |= (1<<COM1A1);
  OCR1A = 125;
}

void loop()
{
}

上記のコードは、ピン 9 から約 2.5V (49% のデューティ サイクル) の平均電圧出力を生成します。(私にとって) 奇妙なことは、データシートによると、TIMER1 は 16 ビット タイマーであるため、65536 ティックでオーバーフローするはずです。 . 私が理解していることから、OCR1Aを0から65535に設定すると、パルスのデューティサイクルが変更されます。では、OCR1A を 125 に設定すると、2.5V ではなく約 0.01V の出力が得られるのではないでしょうか? 結果は、クロックが 255 でオーバーフローしていることを示しているようです。

PWM ランドへの 2 回目の進出では、ATMega の高速 PWM モードを使用して 2.5V 信号を作成してみました。これが私が得たものです:

// Waveform Generation Mode 14
// Table 15-4 of the datasheet

void setup()
{
  DDRB = (1<<PB1);

  TCCR1A |= (1<<COM1A1) | (1<<WGM11);
  TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS10);

  ICR1 = 19999;
  OCR1A = 10000;
}

void loop()
{
}

ICR1 (オーバーフロー値) を任意に 20000 ティックに設定し、OCR1A (比較値) をその約半分に設定します。チャンネル A を非反転モードに設定しましたが、反転モードに設定しても違いはなかったと思います。これを Arduino にフラッシュしたとき、ピン 9 から平均 5V (100% デューティ サイクル) の安定した電圧が得られました。

あなたが提供できる洞察をいただければ幸いです。

4

2 に答える 2

3

AVRfreaks の joeymorin による回答:

Uno では、setup() の前に実行される Arduino 初期化コードが、328P の 3 つのタイマーすべてを含む多くのものを構成することに注意してください。

Wiring.cから:

   sbi(TCCR0A, WGM01); 
   sbi(TCCR0A, WGM00); 
   sbi(TCCR0B, CS01); 
   sbi(TCCR0B, CS00); 
   sbi(TIMSK0, TOIE0); 

   sbi(TCCR1B, CS11); 
   sbi(TCCR1B, CS10); 
   sbi(TCCR1A, WGM10); 

   sbi(TCCR2B, CS22); 
   sbi(TCCR2A, WGM20);

これにより、プリスケーラ 64 で 3 つすべてのタイマーが開始されます。

TIMER0 は、タイミング関数 (millis()、micros()、および delay()) をサポートするために有効化されたオーバーフロー割り込みでモード 3 (高速 PWM) に配置されます。

TIMER1 はモード 1 (固定 8 ビット位相補正 PWM) になります。

TIMER2 はモード 1 (位相補正 PWM) になります。

void setup() 
{ 
  DDRB = (1<<PB1); // set pin 9 as output 

  TCCR1A |= (1<<COM1A1); 
  OCR1A = 125; 
} 

void loop() 
{ 
} 

TCCR1A の WGM10 は既に設定されているため、COM1A1 を設定すると、analogWrite() と同様に、非反転モードで PWM 出力が有効になります。

TIMER1 は 16 ビット タイマーなので、65536 ティックでオーバーフローするはずです。私が理解していることから、OCR1Aを0から65535に設定すると、パルスのデューティサイクルが変更されます。では、OCR1A を 125 に設定すると、2.5V ではなく約 0.01V の出力が得られるのではないでしょうか? 結果は、クロックが 255 でオーバーフローしていることを示しているようです。

モード 1 では、8 ビット タイマーのように動作します。

void setup() 
{ 
  DDRB = (1<<PB1); 

  TCCR1A |= (1<<COM1A1) | (1<<WGM11); 
  TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS10); 

  ICR1 = 19999; 
  OCR1A = 10000; 
} 

void loop() 
{ 
}

TCCR1A の WGM10 は既に設定されているため、WGM11、WGM13、および WGM12 を設定すると、モード 14 ではなくモード 15 が選択されます。モード 15 は、TOP = OCR1A (ICR1 ではない) の高速 PWM です。COM1A1 で PWM 用の OC1A 出力の設定も使用しているため、これにより OC1A がハイのままになります。

すでに述べたように、Arduino 環境でタイマーを設定する場合は、|= の代わりに = を使用してゼロから設定する必要があります。

theusch さんが書きました:

そして、私が知っている限りでは、 setup() の後にさらに実行される可能性があります

Arduino の main.cpp から: コード:

#include <Arduino.h> 

int main(void) 
{ 
   init(); 

#if defined(USBCON) 
   USB.attach(); 
#endif 

   setup(); 

   for (;;) { 
      loop(); 
      if (serialEventRun) serialEventRun(); 
   } 

   return 0; 
}

JJ

于 2014-01-29T02:42:53.640 に答える
1

OCR1A周波数を制御し(オーバーフローはタイマーを再起動します)、OCR1Bデューティサイクルを制御します(オーバーフローは出力ピンの状態を変更します)

2番目の例では、なぜ使用ICR1しているのか、arduinoが5Vで動作するときに出力として8Vを取得している可能性があるのか​​ 理解できません...または、それを揚げているか、読み取りが不正確です。

こちらをご覧ください。PWM、高速 PWM などについて多くのことが説明されています。

http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM

ICR1編集: TOPおよびOCR1Aカウンターとして使用しているのを見逃しました。問題は次のとおりです。デフォルトでは、レジスタは arduino ライブラリによって何らかの値で初期化されます。 TCCR1A= 1 -> (WMG10オン、これは悪い) TCCR1B= 11 -> (プリスケーラ = 64)

この値をオーバーライドするのではなく、少し 1 にするだけです。そうすれば、activatid pin WGM11WMG12、およびの代わりに、WMG13ビットもWMG10オンになり、モード 15 になります。

また、最終的なプリスケーラーは 8 ではなく 16 のままです。

解決策は |= を = で変更することです。そのため、デフォルト値をオーバーライドします。

于 2014-01-27T14:26:00.383 に答える