FrontPage > マイクロコントローラ > AVRの覚書

PWM

ATmega328Pの16-bitタイマ/カウンタのMode 15(Fast PWM)を使用して
周期:20ms、パルス幅:2msの波形を出力してみる。
出力はOC1B(PB2)ピン

1. 波形生成の仕組み

PWMの波形は下図のように、カウンタが最大値までカウントを繰り返している状態で、
0のときにセット、比較値と一致したときにクリアされる。(逆も可)

pwm.png
  • 最大値を求める
    今回はカウンタのクロックにシステムクロック16MHzを8分周して用いるので、
    1カウントの時間は
    8 / 16Mhz = 0.5μs

    周期が20msとなるカウンターの最大値は
    20ms/0.5μs -1 = 39999 = 0x9C3F

  • 比較値を求める
    パルス幅が2msとなる比較値は
    2ms/0.5μs = 4000 = 0xFA0

2. レジスタ

  • TCCR1A, TCCR1B (Timer/Counter1 Control Register A,B)
    (TCCR1A)
    bit7bit6bit5bit4bit3bit2bit1bit0
    COM1A1COM1A0COM1B1COM1B0--WGM11WGM10
    (TCCR1B)
    bit7bit6bit5bit4bit3bit2bit1bit0
    ICNC1ICES1-WGM13WGM12CS12CS11CS10
    • COM1A1,COM1A0(Compare Output Mode)
      OC1Aピンは未使用のため"00"を設定。
    • COM1B1,COM1B0(Compare Output Mode)
      OC1Bピンへ比較一致でクリア、0でセット出力なので"10"を設定。
    • ICNC1, ICES1
      未使用のため"00"
    • WGM[13:10](Waveform Generation Mode)
      Fast PWMモードで最大値はOCR1Aの値を使用するので"1111"を設定。
    • CS[12:10](Clock Select)
      8分周するので、"010"を設定。

  • OCR1A(Output Compare Register 1A)
    最大値"39999"を設定。
  • OCR1B(Output Compare Register 1B)
    比較値"4000"を設定

3. プログラム

(PWm_test.c)

#include <avr/io.h>

int main(void)
{
	// カウント最大値設定(20ms周期)
	OCR1A = 0x9C3F;
	// パルス幅設定(2ms)
	OCR1B = 0x0FA0;
	
	// Timer/Counter1 Controlレジスタ設定
	TCCR1A = _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);
	TCCR1B = _BV(WGM13) | _BV(WGM12) |_BV(CS11);

	// PORT-BのBit-2(OC1Bピン)を出力に指定
	DDRB |= _BV(DDB2);
	
	while(1)
    {
        //TODO:: Please write your application code 
    }
}

4. 実行結果

  • 出力された波形をオシロスコープで確認

    周期20msを確認。
    AVR_PWM_OUT_0.png

    パルス幅2msを確認
    AVR_PWM_OUT_1.png

5. サーボモータを制御する。

ホビー用サーボモータの角度はPWMによって制御される。
試しにPWM出力をサーボモータに接続して
0°→ -90°→ 90°→ 0°と動かしてみる。

5.1 接続図

AVR_SERVO_0_回路図.png

5.2 プログラム

  • 今回使用するサーボモータのPWM周期は20msで、 角度とパルス幅の関係は以下の通りなので、
    パルス幅に対応する値をOCR1Bレジスタにセットすればよい。
    角度パルス幅
    -90°1ms
    1.5ms
    90°2ms

    (PWM_test.c)
    #ifndef F_CPU
    #define F_CPU 16000000UL    // 動作周波数に16MHzを指定
    #endif
    
    #include <avr/io.h>
    #include <util/delay.h>
    
    int main(void)
    {
    	// カウント最大値設定(20ms周期)
    	OCR1A = 0x9C3F;
    	// パルス幅設定(1.5ms)
    	OCR1B = 3000;
    	
    	// Timer/Counter1 Controlレジスタ設定
    	TCCR1A = _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);
    	TCCR1B = _BV(WGM13) | _BV(WGM12) |_BV(CS11);
    
    	// PORT-BのBit-2(OC1Bピン)を出力に指定
    	DDRB |= _BV(DDB2);
    
    	_delay_ms(1000);
    	
    	// パルス幅設定(1ms)
    	OCR1B = 2000;
    
    	_delay_ms(1000);
    
    	// パルス幅設定(2ms)
    	OCR1B = 4000;
    
    	_delay_ms(1000);
    
    	// パルス幅設定(1.5ms)
    	OCR1B = 3000;
    	
    	while(1)
        {
            //TODO:: Please write your application code 
        }
    }
    

    AVR_PWM_SERVO.jpg




添付ファイル: fileAVR_PWM_SERVO.jpg 220件 [詳細] fileAVR_SERVO_0_回路図.png 170件 [詳細] fileAVR_PWM_OUT_1.png 220件 [詳細] fileAVR_PWM_OUT_0.png 205件 [詳細] filepwm.png 230件 [詳細]

トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-07-10 (金) 01:39:41 (833d)