目次

モータ制御

 2個のモータを、PWM(Pulse Width Modulation)で制御します。

 PWMは、モータの回転速度を、パルス幅で制御する方式です。
 1周期の中で、電圧がHとLになっている時間を可変にして
 モータに与える平均電力を変えていきます。

 H8のITU(Integrated Timer Unit)には、PWM用モジュールが
 含まれていますが、データシートの説明がわかりにくいので
 タイマー割込みを利用した単純な方法にしました。

 PWMの原理は、非常に簡単です。

 0〜99までカウンタで数えて、レジスタの値と比較します。
 レジスタの値がNで、カウンタの値がTとすると、次の処理を
 します。
  N < T  → 1出力
    N >= T → 0出力

 この動作を、タイマー割込みの中で実行します。
 Cのコードで記述すると、以下です。
    /* handling counter */
    pwm_cnt++ ;
    if ( pwm_cnt == 100 ) { pwm_cnt = 0 ; }
    /* compare */
    LEFT_OUT = RIGHT_OUT = ON ;
    if ( pwm_cnt >= left_duty  ) { LEFT_OUT  = OFF ; }
    if ( pwm_cnt >= right_duty ) { RIGHT_OUT = OFF ; }
    /* out */

 タイマー割込みの中で、上の動作をすればよいので
 タイマー割込みの種類選択と周期を決めれば、制御できます。
 今回は、H8にあるITU1を利用し、モータを制御します。

 タイマー割込みが使えるワンチップマイコンであれば、大抵
 用意されているコンペアマッチ割込みを使います。


コンペアマッチ割込み

 普通のワンチップマイコンの内蔵タイマー/カウンタには  カウンタとプリスケーラが用意されています。  カウンタは、8ビットか16ビットになっていることが多い  ですが、H8のITUは16ビットです。  カウンタの他に、GRA、GRBという2個の16ビットレジスタ  があります。  これらのレジスタの値とカウンタの値を比較し、値が一致  したとき、割込みを発生するのが、コンペアマッチ割込み  です。コンペアマッチ割込みで、比較する値を入れる所が  2つあるのがH8のITUです。値が一致すると、カウンタを0  にできます。  利用しているH8/3048Fのボードは、16MHzのシステムクロック  になっているので、プリスケーラの分周比を1:1としカウンタ  に16MHzを入力します。  PWM用のカウンタは、100まで数えて0に戻すので、PWMの  1周期を400kHzに設定します。  16MHzから400kHzを生成したいので、16000kHz/400kHz=40を  GRAに設定します。  ITU1の初期化処理は、次の関数で定義しました。  #define ITU1_AREG 40  #define MASKFFFF 0xffff  void init_timer1(void)  {   /* stop timer */   ITU.TSTR.BIT.STR1 = OFF ;   ITU.TOER.BYTE = 0 ;   /* TIOR : Timer I/O Control Register 7 **** -> 0 6 IOB2 -> 0 GRB is not output compare match register 5 IOB1 -> 0 4 IOB0 -> 0 3 **** -> 0 2 IOA2 -> 0 GRA is not output compare match register 1 IOA1 -> 0 0 IOA0 -> 0   */   ITU1.TIOR.BYTE = 0 ;   /* TCR : Timer Control Register 7 **** -> 0 6 CCLR1 -> 0 clear TCNT if GRA = TCNT 5 CCLR0 -> 1 4 CKEG1 -> 0 rising edge 3 CKEG0 -> 0 2 TPSC2 -> 0 φ利用 1 TPSC1 -> 0 0 TPSC0 -> 0   */   ITU1.TCR.BYTE = 0x20 ;   /* TIER : Timer Interrupt Enable Register 7 **** -> 0 6 *** -> 0 5 *** -> 0 4 *** -> 0 3 *** -> 0 2 OVIE -> 0 1 IMIEB -> 0 0 IMIEA -> 1 select compare match interrupt   */   ITU1.TIER.BIT.IMIEA = ON ;   /* reference */   ITU1.GRA = ITU1_AREG ;   ITU1.GRB = MASKFFFF ;   /* counter */   ITU0.TCNT = 0 ;  }

割込み中の処理

 割込みが発生した場合、次のシーケンスを実行します。
  1. 割込みフラグリード
  2. 割込みフラグクリア
  3. カウンタインクリメントと初期化
  4. カウンタとレジスタの値を比較
  5. ポートへ論理値出力
 割込み中の処理(ハンドラ)は、次の関数で定義しました。  void int_imia1(void)  {   UBYTE dummy ;   /* clear flag */   dummy = ITU1.TSR.BIT.IMFA ;   ITU1.TSR.BIT.IMFA = OFF ;   /* increment */   pwm_cnt++ ;   if ( pwm_cnt == 100 ) { pwm_cnt = 0 ; }   /* judge logical level */   LEFT_MOTOR = RIGHT_MOTOR = OFF ;   if ( pwm_cnt < left_duty ) { LEFT_MOTOR = ON ; }   if ( pwm_cnt < right_duty ) { RIGHT_MOTOR = ON ; }   /* put logical level */   PB.DR.BIT.B2 = LEFT_MOTOR ;   PB.DR.BIT.B0 = RIGHT_MOTOR ;  }

回転開始と停止

 必要ない場合に、モータを回転させないように  開始と停止を担当する関数を定義します。  パルスを与えなければよいので、カウンタにクロックを  与えるか与えないかと、ポートへ出力する論理値で回転  の開始、停止を実行します。  回転開始は、カウンタにクロックを与えます。  次のように定義しました。  void start_pwm(void)  {   ITU.TSTR.BIT.STR1 = ON;  }  回転停止は、カウンタに与えるクロックを切ると同時に  出力論理値を0にします。  void stop_pwm(void)  {   ITU.TSTR.BIT.STR1 = OFF;   /* set logical level */   PB.DR.BIT.B0 = OFF ;   PB.DR.BIT.B2 = OFF ;  }

速度制御

 左右のモータのDuty比を変更できるようにします。  グローバル変数left_duty、right_dutyを用意し、  これらの値を更新する関数で実現しました。  UBYTE left_duty;  UBYTE right_duty;  void update_motor(UBYTE dl,UBYTE dr)  {   left_duty = dl ;   right_duty = dr ;  }
目次

inserted by FC2 system