Awazaru's Blog

筆者の覚え書きです。内容は電子工作とかその他いろいろ。

タイマー割り込みで気をつけること

サーボモータを動かす、だけのプログラムを書きました。
「ある2つの位置を一秒ごとに往復する」ものですが書き込んでもサーボモータが動いてくれません。
結論はタイマー割り込みの設定の中でTIMSKレジスタで必要以上の数に許可を設定していた、ということでした。使わなければ設定してあっても関係ないだろうといろいろ試す途中で直すことを放棄していたのですがそれが原因となっていたわけです。今回の教訓は「レジスタ設定では必要な設定だけを行い使わないものはちゃんと切っておく」ということです。当たり前といえば当たり前ですが(笑)

今回の動作の仕組みについて説明します。16bitタイマーを使って20msの周期のPWMを設定し、20msのタイマー割り込み関数の中で50をカウントすることで1秒を数えます。そこで1秒ごとにservoの値を1と0に変わるようにしそれをif文で判断することで交互に動くことになります。

このような動作をします。

ソースコードです。

//PWM制御

#include <avr/io.h>
#include <avr/interrupt.h>

#define max_clockwise 89 //時計回り最大(90度くらい)
#define max_counterclockwise 390//反時計回り最大(-90度くらい)
#define nutral 234

int count=0;//割り込み関数に入った回数をカウントする変数
int servo=0;//サーボを交互に動かすための変数


ISR(TIMER1_CAPT_vect){//タイマー1捕獲割り込み
    count++;
    if(count>0&&count==50){
        servo = 1 - servo;
        count = 0;
    }
 
}

int main(void){
    //マイコンの初期化
    DDRB = 0b00000010; //PB1を出力設定
    DDRD = 0b10000000;//PD7を出力設定
    
    TCCR1A = 0b10000010;//非反転高速PWM 比較一致でLow BottomでHigh
    TCCR1B = 0b00011010;//64分周 TOP値ICR1
    ICR1H = 9;//周期20ms TOP 3125値
    ICR1L = 195;
    TIMSK1 = 0b00100000;//タイマ/カウンタ1捕獲割り込み許可
    
      sei();
    
    while(1){
        if(servo==0){
            OCR1A = max_clockwise;
            PORTD = 0b00000000;//LED消灯
        }else if(servo==1){
            OCR1A = max_counterclockwise;
            PORTD = 0b10000000;//LED点灯
        }
        
    }
    return 0;
}