STM32-TIMER

一定時間ごとの割込み

タイマーを使って5秒毎にLEDを点滅させるスケッチです。
タイマーをスタートした瞬間に割り込みを入れたい場合
timer1.setCompare(TIMER_CH1, 1);
タイマーをスタートして1回分の周期後に割り込みを入れたい場合
timer1.setCompare(TIMER_CH1, timer1.getOverflow());
タイマーをスタートして1回分の周期の半分後に割り込みを入れたい場合
timer1.setCompare(TIMER_CH1, timer1.getOverflow() * 0.5);
動作を変更させたい場合は上記の部分をコメントアウトして利用してください。
#define LED_RATE 5000000//5秒間隔
HardwareTimer timer1(1);
void setup() {
    pinMode(BOARD_LED_PIN, OUTPUT);//青LEDのつながっているピンを出力モードに
    timer1.pause();//タイマーを停止
    timer1.setPeriod(LED_RATE);//周期を5秒に設定
    //タイマー1のチャンネル1をコンパレータモードに設定
    timer1.setChannel1Mode(TIMER_OUTPUT_COMPARE);

    //タイマーをresumeした瞬間に1回目の割り込みが入る。
    timer1.setCompare(TIMER_CH1, 1);

    //タイマーをresumeして5秒に1回目の割り込みが入る。
    //timer1.setCompare(TIMER_CH1, timer1.getOverflow());

    //タイマーをresumeして2.5秒に1回目の割り込みが入る。
    //timer1.setCompare(TIMER_CH1, timer1.getOverflow() * 0.5);
    timer1.attachCompare1Interrupt(handler_led);
    timer1.refresh();//タイマーをクリア
    timer1.resume();//タイマーをスタート
}
void loop() {
}
void handler_led(void) {//
    toggleLED();//基板上の青LEDを点滅
}

エンコーダのカウント

STM32のタイマーにはエンコーダをカウントするモードが存在します。
この機能を使わずに、割込み処理で行うことも可能ですが、こちらのほうが処理の負荷を少なくすることが可能です。mapleIDEの機能として実装されおらず、扱うのはかなり面倒なのでライブラリ化してみました。mapleIDEのlibrariesに解凍したデータをインストールすると利用できます。
EncoderModeTimerVer0.01.rar
タイマーから値をそのまま読み出すバージョンです。
16ビット(0-65535)を超えるとオーバーフローします。
EncoderModeTimerVer0.02.rar
タイマーのオーバーフロー対策をしたバージョンです。
getCount関数をオーバーフローする周期より短い周期でアクセスすると
オーバーフローしても整合がとれるように処理します。
符号付32ビットで値を返します。
EncoderModeTimerVer0.03.rar
プリスケーラの設定に対応したバージョンです。
setPrescaleFactor関数とgetPrescaleFactor関数を追加しています。

ライブラリの使い方

まず、対応するタイマーのピンとエンコーダを接続しておきます。
タイマーとエンコーダの入力ピンの関係
TIMER1 PA(8),PA(9) 5Vトレラント
TIMER2 PA(0),PA(1) MAX4.0V
TIMER3 PA(6),PA(7) MAX4.0V
TIMER4 PB(6),PB(7) 5Vトレラント
※5Vトレラントでないピンに5Vレベルのエンコーダをつなぐ時は抵抗やショットキーダイオードなどを使って、端子を保護する必要があるので注意してください。オープンドレイン出力のものや、プルアップ仕様のエンコーダであればそのまま使える場合もあります。なお、内蔵のダイオードに5mA以上の電流が流れると壊れます。

ライブラリの関数

  • EncoderModeTimer EncoderTimer(タイマーの番号);
タイマーをエンコーダモードで初期化します。
値の読み出し
  • int32 getCount関数
エンコーダの値の読み出します。Ver0.02以降は符号付きint32の範囲で、Ver0.01は符号なしint16の範囲で値が返ります。
※ただし、タイマーを使うプログラムは動作しなくなります。
例えばタイマーと関連があるPWM出力など。http://www37.atwiki.jp/kisarazu_maicon/pages/116.html
  • void setPrescaleFactor(uint32 factor)関数
プリスケーラの値(1~65536)を設定します。
getCount関数で読み出される値は、このプリスケーラ値で割った値になります。
高速なエンコーダを使う場合や、キリの良い数にしたい場合に使うと良いと思います。
なお、標準では1がセット(プリスケーラ無効)されています。
  • uint32 getPrescaleFactor()関数
プリスケーラに設定されている値を読み出します。

サンプルプログラム

#include "EncoderModeTimer.h"
EncoderModeTimer EncoderTimer1(1);//タイマー1:エンコーダモード
//EncoderModeTimer EncoderTimer2(2);//タイマー2:エンコーダモード
//EncoderModeTimer EncoderTimer3(3);//タイマー3:エンコーダモード
//EncoderModeTimer EncoderTimer4(4);//タイマー4:エンコーダモード
void setup() {
  pinMode(PA(8), INPUT);//TIM1 CH1
  pinMode(PA(9), INPUT);//TIM1 CH2
  //pinMode(PA(0), INPUT);//TIM2 CH1
  //pinMode(PA(1), INPUT);//TIM2 CH2
  //pinMode(PA(6), INPUT);//TIM3 CH1
  //pinMode(PA(7), INPUT);//TIM3 CH2
  //pinMode(PB(6), INPUT);//TIM4 CH1
  //pinMode(PB(7), INPUT);//TIM4 CH2
  Serial3.begin(9600);
}
void loop() {
  Serial3.print("encoderPosition1=");
  Serial3.println(EncoderTimer1.getCount());
  //Serial3.print("encoderPosition2=");
  //Serial3.println(EncoderTimer2.getCount());
  //Serial3.print("encoderPosition3=");
  //Serial3.println(EncoderTimer3.getCount());
  //Serial3.print("encoderPosition4=");
  //Serial3.println(EncoderTimer4.getCount());
  delay(1000);
}


こちらはライブラリを使わない場合のサンプルです。STM32VLD以外で試す場合はこちらをお勧めします。
#include <timer.h>
#include <string.h>
HardwareTimer timer1(1);

void setup() {
  pinMode(PA(8), INPUT);//TIM1 CH1
  pinMode(PA(9), INPUT);//TIM1 CH2

  Serial3.begin(9600);
  delay(1000);
  
  *bb_perip(&((TIMER1->regs).gen->CR1), TIMER_CR1_CEN_BIT) = 0;
  memset( (TIMER1->regs).gen, 0, sizeof(timer_adv_reg_map) );
  uint32 tmp;
  (TIMER1->regs).gen->ARR = 0xFFFF;
  tmp = (TIMER1->regs).gen->CCMR1;
  tmp &= ~TIMER_CCMR1_CC1S;
  tmp |= TIMER_CCMR1_CC1S_INPUT_TI1;
  tmp &= ~TIMER_CCMR1_CC2S;
  tmp |= TIMER_CCMR1_CC2S_INPUT_TI1;
  (TIMER1->regs).gen->CCMR1 = tmp;
  tmp = (TIMER1->regs).gen->SMCR;
  tmp &= ~TIMER_SMCR_SMS;
  tmp |= TIMER_SMCR_SMS_ENCODER3;
  (TIMER1->regs).gen->SMCR = tmp;
  *bb_perip(&((TIMER1->regs).gen->CCER), TIMER_CCER_CC1P_BIT) = 0;
  *bb_perip(&((TIMER1->regs).gen->CCER), TIMER_CCER_CC2P_BIT) = 0;
  *bb_perip(&((TIMER1->regs).gen->CR1), TIMER_CR1_CEN_BIT) = 1;

}
void loop() {
  Serial3.print("encoderPosition=");
  Serial3.println(timer1.getCount());
  delay(1000);
}
最終更新:2011年12月12日 00:43