PWMサンプル †PWM(パルス幅変調)というAVRに内蔵されている機能を使って、LEDを明滅させてみる。 回路図 †基本の回路から増えているのは、PB3から出ている、抵抗とLEDのみ。 あと、今回追加した抵抗を使用せず、LEDのみを繋げてしまうと、ISPのMOSIがそのままGNDに落ちてしまうせいか、プログラムの書き込みに失敗した。 実際の動作はこのムービーのような感じ。 ソースコード †#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; } 基本動作 †今回使用するのは、高速PWM動作という、タイマ/カウンタの機能。 ソースでは、まず、タイマ/カウンタ比較Aレジスタ(OCR2A)を初期化している。 次に、タイマ/カウンタ2制御レジスタAとBを設定し、0〜255まで上がって0に戻るのこぎり波を生成し、OCR2Aの閾値より下の値の時にOC2AピンにLowを出力、上の値の時にHighをOC2Aピンに出力するモードに設定する。 最初の閾値は0なので、のこぎり波の値は常に閾値以上となり、Lowが出力(LEDが消灯)となる。 クロック自体は前置分周なしとし、のこぎり波1周期にかかる時間は、1MHz駆動なので、256/1000000sで、0.25ms程度。 閾値が最大までいったら、今度は閾値を減らしていき、6→5→4→3→2→1というように、明度を下げていく。 この結果、閾値を0〜255〜0と増減させ、1段階につき1ms程度の時間をかけているため、0.5秒とちょっとくらいでの明滅を繰り返すように見える。 |