STM HAL Timer

 

Timerの動作について理解を深める。


File-NewからSTM32Projectを選択して適当な名前のプロジェクトを作る。ここでは、HAL_Timerとしておいた。

LEDを動作の確認に使うので、PC13をGPIO OUTPUTに指定する。

またタイマーを使うのでRCCを選択して、high speed clockをCrystal/Ceramic Resonatorを選択する。

Clock configrationのタブを開いて、クロックの設定をする。PLLの倍率を9にして、APB1のペリフェラルクロックが36MHzになるようにセットした。一番早いのという理由。




Prescaler & Counter Periodの設定


CategoriesのTimerを開いて、用いるタイマーを選択する。

データシートを覗くと、TIM1はAPB2を基に動き、TIM2~TIM4はAPB1が基に動く事がわかる。APB1のタイマークロックは、72MHzに設定した。

Prescaler:分周器 何Hzでカウントアップするかを決めるために、Prescalerで割る。

TIM4はAPB1の72MHzで動作するように設定した。
ここで、Prescalerを例えば72kHzに設定すると、
 72,000kHz / 72kHz=1000
となり1kHzでカウントが一つ変わる設定になる。
ところが、Configrationで設定できるPrescalerは16ビットで入力する必要がある。16ビットの最大値は65,536なので入力できない。
72,000kHz / 7200Hz=10000
一桁落として、7200Hzで設定した。なので1カウントの時間は100usecで1万カウントして1秒になる。

Counter Period:カウントがこの設定値になったら割り込みを発生させるかの値。
Counter Periodを10000に設定すると、1秒で割り込みが入る。1000にしてやると0.1秒で1回の割り込みとなる。

設定する時に「72000-1」や「10000-1」のように設定するのは、0からスタートするので1引いた値を設定。


次に同じタイマーのConfigrationの"NVIC Setting"のタブがあるので開き、TIM4 global interruptのEnableのチェックを入れる。

NVICってなんぞえ?
ARMコアマイコンでは割り込みはNVIC(Nested Vectord Interrupt Contoller)が管理していていて、ネストとは複数の割り込みが発生したときに優先順位の高いものから順次処理するタイプという事。NVICの動きについては必要がある時に詳細は勉強する事にする。

Ctrl+Sで保存し、ソースコードを自動で生成させる。


コードの記載

タイマーはセットしただけでは動かないので、スタートさせる。whileの外でスタートさせればよいので、  MX_TIM4_Init();の後に  HAL_TIM_Base_Start_IT(&htim4);を記述する。

 /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim4);
  /* USER CODE END 2 */

タイマー割り込みが発生した時に呼ばれるコールバック関数HAL_TIM_PeriodElapsedCallback
というのが用意されている。 Private user code の所に、以下の関数を配置する。

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    if (htim == &htim4){
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
}
/* USER CODE END 0 */

この関数のhtimに入った値からどのタイマーの割り込みが発生したのかif文で判別して処理を行う。ここでは、オンボードのLEDPC13ピンをトグルしている。

練習

2つのLEDを同時に違う周期で点灯させみる。

PC14もGPIO OUTPUTに設定し、以下のようにソースコードを変更する。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    if (htim == &htim3){
     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
    if (htim == &htim4){
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);
    }
}


回路の方は、LED2つを別途用意。LEDのプラスをVccにさして、その後100Ωの抵抗を介してそれぞれPC13、PC14に接続した。これでまあクリスマスツリーですな。

    if (htim == &htim3){
     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        HAL_Delay(500);
    }
    if (htim == &htim4){
     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);
        HAL_Delay(1000);
    }

と、HAL_Delay(500);を置いてみる。TIM3は、0.5秒間隔の点滅で、TIM4は1秒間隔なんでこれを置いたからといって動きはかわらないはず

と思いきや。これを書き込むと動かないはず。

HAL_DelayはSysTick で動いていて、優先度はデフォルトではゼロになっている

そのため、一度SysTick 割り込みがブロックされてしまい,関数から戻ってこなくなる。
この点は注意が必要。


NVICで優先度を変更してみる。Time base:System tick timerが今ゼロなんで、それより大きい数字に変更してみる。
今度は両方点滅するんだが、ちょっと思った動きと違うはず。二つ同じタイミングで点灯する、または二つが同じタイミングで消灯することがない。

TIM3側でHAL_Delayの優先度が高いので処理が終わってから、TIM4と順に処理するためである。
HAL_Delayっての優先度を気にしないといけませんねというお話でした。






コメント

このブログの人気の投稿

Attiny85とAQM0802A(LCD)のI2C接続

Attiny85 FuseRest

HS101 STM32の自作お手軽オシロスコープ