AVRタイマー–PWMモード-パートII

AVRシリーズこの記事は前回のPWM記事に続きます。 PWMモードで動作するようにタイマーをプログラムする方法を学びます! それでは始めましょう!

こんにちは! お久しぶりです!!!!!!!!!! 🙂

前回の記事では、PWMの基本的な概念について説明しました。 まずそれを要約しましょう:

  • PWMはパルス幅変調の略です。
  • 所定の波形を基準電圧レベルと比較するか、単純なアナログ回路を作ることによって生成することができます。
  • PWM波形のデューティサイクルは以下の関係で与えられます。
使用率
  • PWM動作には、高速PWM、位相補正PWM、周波数と位相補正PWMの三つのモードがあります
  • タイマ、動作モードを選択し、所望のPWMを生成するための出力モードを比較
だから今、多くの手間をかけずに、AVRマイクロコントローラを使用してそれを実装する方法を見てみましょう。 私たちが進む前に、私はあなたがタイマーとPWMに私の以前の記事を通過することをお勧めします。

問題文を見てみましょう。 45%のデューティサイクルを持つ50Hz PWM信号を生成する必要があります。

分析

Frequency = 50 Hz

つまり、期間、T

T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms

また、

Duty Cycle = 45%

したがって、上記の式に従って解くと、

T(on) = 9 msT(off) = 11 ms

今、これは次のようになります。二つの方法で達成:

  1. CTCモードでタイマーを使用する
  2. PWMモードでタイマーを使用する

方法論–CTCモード

さて、私はここにコードを書くことはありません(擬似コードだけ)。 私は私の以前の記事を読んだ後、あなたは自分自身を書くのに十分スマートであると仮定します! 概念のみについて説明します。

まず、適切なタイマーを選択します。 このアプリケーションでは、ATMEGA32で利用可能な三つのタイマーのいずれかを選択することができます。 適切なプリスケーラを選択します。 その後、タイマーを設定し、いつものように進みます。 ここにあるのは、OCRx registerの比較値を毎回更新する必要があるということです。 そのような方法の1つは、以下の擬似コードで説明されています。

これは、オン時間とオフ時間が異なることを除いて、従来のLEDフラッシャーに似ています。

擬似コード

#include <avr/io.h>#include <avr/interrupt.h> uint8_t count = 0; // global counter // initialize timer, interrupt and variablevoid timerX_init(){ // set up timerX with suitable prescaler and CTC mode // initialize counter // initialize compare value // enable compare interrupt // enable global interrupts} // process the ISR that is firedISR (TIMERx_COMPA_vect){ // do whatever you want to do here // say, increment the global counter count++; // check for the global counter // if count == odd, delay required = 11 ms // if count == even, delay required = 9 ms // thus, the value of the OCRx should be constantly updated if (count % 2 == 0) OCRx = 9999; // calculate and substitute appropriate value else OCRx = 10999; // calculate and substitute appropriate value} int main(void){ // initialize the output pin, say PC0 DDRC |= (1 << 0); // initialize timerX timerX_init(); // loop forever while(1) { // do nothing }}

今、これは一つの方法です。 そして、それは非常に非効率的です。 より良いCコード(構文的に)を記述することで効率を高めることができますが、概念は同じままです。 他の方法/概念がある場合は、ここでそれを共有することを大歓迎です! 🙂

更新:maxEmbeddedの読者の一人、”coolpales”はこのコードを書いており、彼のために働いていました。

このコードはまだテストされていないことに注意してください! だから、あなたのうちのどれかがそれを試しているなら、ここにあなたの結果を投稿してください、私はそれらを見て幸せになるでしょう! 🙂

方法論–PWMモード

さて、今PWMモードについて学ぶことができます。 AVRのPWMモードはハードウェア制御です。 これは、すべてが、私が「すべて」を意味するすべてによって、AVR CPUによって行われることを意味します。 あなたがする必要があるのは、タイマーを初期化して起動し、デューティサイクルを設定することです! クール、えっ?! のは、方法を学びましょう!

ここでは、デモのためにATMEGA32のTimer0を使用しました。 他の他のタイマーかAVRのマイクロ制御回路をまた選ぶことができます。 それでは、レジスタを見てみましょう。

TCCR0–Timer/Counter0コントロールレジスタ

私のTimer0チュートリアルでこのレジスタに遭遇しました。 ここでは、PWMモードでタイマーを実行するために適切なビットを設定する方法を学びます。

TCCR0レジスタ

TCCR0レジスタ

ここでは、興味のあるビットのみについて説明します。

  • ビット6,3–WGM01:0–波形生成モード–これらのビットは、生成するPWMのタイプに応じて”00″または”01″のいずれかに設定できます。 ルックアップテーブルは次のとおりです。
    波形生成モードのビット説明

    波形生成モードのビット説明

  • Bit5,4-COM01:0–Compare Match Output Mode-これらのビットは、WGM01:0ビットに従って、出力比較ピン(OC0、ATMEGA32のピン4)の動作を制御するために設定されます。 以下のルックアップテーブルは、高速PWMモードでのOC0ピンの動作を決定します。
    出力モードの比較、高速PWMモード

    出力モードの比較、高速PWMモード

    ここで、高速PWM波形を見てみましょう。 詳細な説明は私の前のチュートリアルで見つけることができます。

    Fast PWM

    Fast PWM

    AVR PWMは完全にハードウェア制御されていることを思い出させてください。 私たちがする必要があるのは、一致が発生したら何をすべきかをCPUに伝えることだけです。 COM01:0ピンはここに遊びに来ます。 「10」または「11」に設定すると、出力ピンOC0がセットまたはクリアされます(つまり、PWMが反転モードであるか非反転モードであるかを判断します)。

    同様に位相補正PWMの場合、ルックアップテーブルと波形は次のようになります。

    出力モード比較、位相補正PWMモード

    出力モード比較、位相補正PWMモード

    位相補正PWM

    位相補正PWM

    ここでも、COM01:0を”10″または”11″に設定すると、OC0端子の動作が決まります。 波形に示すように、2つのインスタンスがあります–1つはアップカウント中、もう1つはダウンカウント中です。 この動作は、ルックアップテーブルに明確に記述されています。

    OC0は出力端子ですのでご注意ください。 したがって、DDRxレジスタが適切に設定されていない限り、WGMとCOMの効果は発揮されません。 詳細については、このチュートリアルを参照してください。

  • ビット2:0–CS02:0–クロック選択ビット–これらのビットはTimer0チュートリアルで既に説明されています。

OCR0–出力比較レジスタ

私のTimer0チュートリアルでは、このレジスタにも遭遇しました。 このレジスタを使用して比較値を格納します。 しかし、PWMモードでTimer0を使用すると、その中に格納されている値はデューティサイクルとして機能します(明らかに!). 問題の声明では、デューティサイクルが45%であることを考えると、それは

OCR0 = 45% of 255 = 114.75 = 115

を意味し、それだけです! 今、私たちはそれのためのコードを書く準備ができています! 🙂

編集:注

次のコードは、所望のデューティサイクルのPWM信号を作成する方法について説明します。 周波数を変更したい場合は、ICRXレジスタ(8ビットタイマではサポートされていません)を使用して行うことができるTOP値を変更する必要があります。 16ビットTimer1の場合はICR1Aを使用して変化させることができます。

コード

だからここにコードが行きます。 AVRでのI/Oポート操作については、こちらを参照してください。 ビット操作について知るには、これを見てください。 AVR Studio5の使用方法については、こちらをご覧ください。 このコードがどのように構造化されているかを学ぶには、前回のTIMER0投稿を参照してください。

#include <avr/io.h>#include <util/delay.h>void pwm_init(){ // initialize TCCR0 as per requirement, say as follows TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t duty; duty = 115; // duty cycle = 45% of 255 = 114.75 = 115 // initialize timer in PWM mode pwm_init(); // run forever while(1) { OCR0 = duty; }}

問題文

それでは、別の問題文を見てみましょう。 これは、以前のものとは違って実用的なものの多くになるだろう!

特定の周波数でLEDを点滅させる必要がある従来のLEDフラッシャーを見てみましょう。 がこんにちは、待てないので戻るこのスクロールを下に向けての)? うーん、PWMを組み込むように修正しましょう。 従来のLEDフラッシャー(Ledがオンまたはオフのいずれか)とは異なり、最大輝度で輝きを与え、ゼロに達するまでゆっくりと明るさを下げ、最大になるま

分析とコード

では、どうすればいいですか? はい、あなたはそれを正しく推測しました! デューティサイクルを255からゼロにゆっくり下げてから、ゼロから255に増やします。 デューティサイクルに応じて、LEDに印加される電圧が変化し、したがって明るさが変化します。 次の式は、電圧とデューティサイクルの関係を示しています。

V_Out方程式

だからここにコードが行きます。 私はそれを説明しません、あなたはそれを自分で解読することができます。 AVRでのI/Oポート操作については、こちらを参照してください。 ビット操作について知るには、これを見てください。 AVR Studio5の使用方法については、こちらをご覧ください。 このコードがどのように構造化されているかを学ぶには、前回のTIMER0投稿を参照してください。

// program to change brightness of an LED// demonstration of PWM #include <avr/io.h>#include <util/delay.h> // initialize PWMvoid pwm_init(){ // initialize timer0 in PWM mode TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t brightness; // initialize timer0 in PWM mode pwm_init(); // run forever while(1) { // increasing brightness for (brightness = 0; brightness < 255; ++brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // decreasing brightness for (brightness = 255; brightness > 0; --brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // repeat this forever }}

だからここで私の別の待望の長いチュートリアルを終了します! 次は…. シリアル通信! またね!! 🙂

そして、ええ、あなたが何か提案、疑問、建設的な批判などがあれば、あなたは以下のメモをドロップすることが最も歓迎されています! 私のblogを予約購読するか、または更新済とどまるためにRSSの供給をつかみなさい!

Write a Comment

メールアドレスが公開されることはありません。