#norelated #contents * PWMサンプル [#z3543dfc] PWM(パルス幅変調)というAVRに内蔵されている機能を使って、LEDを明滅させてみる。~ 要は、細かいON/OFFを繰り返して、そのON時間を調整することにより、時間あたりの流れる電流量を調整する技術なのかな。~ ** 回路図 [#ne97aa60] #ref(PWMTest.png,left,nowrap,PWMサンプル) 基本の回路から増えているのは、PB3から出ている、抵抗とLEDのみ。~ 8bitタイマ0を使ってPWMの出力をする場合には、OC0AかOC0Bのピンを使用し、これはそれぞれPD6とPD5の兼用機能になるんだけど、PDには前回やったLCDがついてて、はずすのも面倒。~ なので、8bitタイマ2を使ってOC2AからPWM出力するようにし、これは空いてるPB3の兼用機能なので、PB3に繋いだ。~ 上の回路図には、ちゃんと書かれてないけど、データシートには、PD3は(MOSI/OC2A/PCINT3)と書いてある。~ 後で直しておくか……。~ あと、今回追加した抵抗を使用せず、LEDのみを繋げてしまうと、ISPのMOSIがそのままGNDに落ちてしまうせいか、プログラムの書き込みに失敗した。~ ちゃんと抵抗はつけるべきですね……。~ 実際の動作はこのムービーのような感じ。~ #u2b(V3PKjTetWa8,w=480,h=385) ** ソースコード [#seb357a6] #include <avr/io.h> #include <util/delay.h> void delay_ms( int time ) { // 指定ms分ループ while( time-- ){ _delay_ms( 1 ); } } int main( void ) { uint8_t duty = 0; // Duty比 duty/256 int8_t dir = 1; // 増減量 DDRB = 0x08; // PB3を出力に設定 PORTB = 0x00; // ポートBをLowに初期化 OCR2A = duty; // Duty比初期化 TCCR2A = 0b10000011; // 8bit高速PWM動作 比較A出力選択でOC2Aへの非反転動作 TCCR2B = 0b00000001; // タイマ/カウンタ2入力クロック前置分周なし while(1){ // 0〜255〜0で、512msを1周期とした明滅を繰り返す delay_ms(1); if( 0x00 == duty ) dir = 1; // 正方向に増やす(明るくする) if( 0xFF == duty ) dir = -1; // 負方向に増やす(暗くする) duty += dir; OCR2A = duty; // Duty比更新 } return 0; } *** 基本動作 [#pb12880e] 今回使用するのは、高速PWM動作という、タイマ/カウンタの機能。~ 0〜255までを繰り返すのこぎり波に、閾値を与えてやって、閾値未満だったらHigh、以上だったらLowを、決まったピンに出力させる。~ この辺りは、図がないと、なかなかわかりにくい。~ #ref(Timing.png,left,nowrap,タイミング) ソースでは、まず、タイマ/カウンタ比較Aレジスタ(OCR2A)を初期化している。~ この値が閾値となり、図の、のこぎり波にかかっている、赤の直線を意味する。~ 次に、タイマ/カウンタ2制御レジスタAとBを設定し、0〜255まで上がって0に戻るのこぎり波を生成し、OCR2Aの閾値より下の値の時にOC2AピンにLowを出力、上の値の時にHighをOC2Aピンに出力するモードに設定する。~ 最初の閾値は0なので、のこぎり波の値は常に閾値以上となり、Lowが出力(LEDが消灯)となる。~ クロック自体は前置分周なしとし、のこぎり波1周期にかかる時間は、1MHz駆動なので、256/1000000sで、0.25ms程度。~ 図の1〜6のそれぞれが、while一周分を意味しており、while内では1msほどウェイトをかけているので、while一周でのこぎり波が4つくらいか。~ なので、while分一周でのこぎり波を4つほど生成した後、閾値を1つあげて、再びのこぎり波を4つほど生成ということを繰り返していく事になる。~ これをどんどん繰り返していくと、1→2→3→4→5→6というように、徐々にHighの出力が多くなっていき、最終的にはほぼHighの状態(LEDが点灯)となる。~ 中間の状態では、0.25ms程度の一つののこぎり波の中で、HighとLowの状態の切り替えが発生しており、LEDは細かい点灯と消灯の繰り返しになるが、人間の目ではわからないレベルであるため、点滅ではなく中間の明度で点灯しているように見える。~ 閾値が最大までいったら、今度は閾値を減らしていき、6→5→4→3→2→1というように、明度を下げていく。~ この結果、閾値を0〜255〜0と増減させ、1段階につき1ms程度の時間をかけているため、0.5秒とちょっとくらいでの明滅を繰り返すように見える。~