設定した時間間隔で,割り込みをかけ,2つのLEDを交互に点滅させる。
通常の関数はプログラム内で呼び出されて起動するが,割り込み関数(ハンドラ,割り込みハンドラとも呼ばれる)は,マイクロコントローラにあることが生じた場合に呼び出される関数である。
このプログラムではSystick割り込みという一定時間間隔(ここで示す例では1msecごと)で起動する割り込みが使われており,割り込み関数内でLEDの点灯消灯が行われている。
main関数は通常他の作業を行っているはずだが,ここでは作業なしの無限ループに入っているので何もしない。割り込み関数内でLEDに関する作業が行われている。
割り込み関数を使うには次のような準備が必要である。
(1)割り込みハンドラを用意する。
(2)Systick割り込みを設定する。
2.1 割り込みハンドラの用意
ハンドラの名前(割り込み関数の名前)は決まっていて,startup_stm32f30x.sのg_pfnVectors:で始まるベクタテーブル中に書いてある。
SysTick_HandlerがSystick割り込みを受けた時に動作するハンドラの名前である。
リファレンスマニュアルDM00043574.pdf(RM0316)のTable 32. STM32F303xB/C and STM32F358xC vector tableにSystick(System tick timer)というのがあり,addressが3Cになっている。
0,4,8,c,10,...のように4バイトずつ割り込みハンドラのアドレスが並ぶので,16個目がSystick_Handlerである。startup_stm32f30x.sのベクタテーブルの16個目になっているのと一致する。
そこで void SysTick_Handler(void) (名前は固定)が1msecごとに起動する割り込みハンドラなので,ここにやりたいことを書く。
また,関数 void SysTick_Handler(void) は自分が起動してもcount変数によって500回の起動につき1回だけLEDの作業を行っている。そのため,0.5秒ごとにLEDの状態が変化(点滅)する。
2.2 Systick割り込みの設定
Systick割り込みの設定は明示的ではないが,initIntervaltimer関数内で,割り込み周期を設定するために関数SysTick_Config()を呼び出してい る。この関数はcore_cm4.h内で定義されており,この関数内でNVICの設定で割り込み優先度の設定を行い,またSystick割り込みを有効にしている。
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
ここで
__NVIC_PRIO_BITS
はcore_cm4.h内で
#define __NVIC_PRIO_BITS 4
このようになっているので,
優先度の値は3が設定されていることになり,一 番低い! 優先度を上げるには,initIntervaltimer()中で,0を設定すると良い。
NVIC_SetPriority (SysTick_IRQn, 0); /* set Priority for Cortex-M0 System Interrupts */
関数SysTick_Config()が呼び出された後は,Systick割り込みが指定時間(ここでは1ms)ごとに生じている。
(割り込み設定の一般的なことは,プシュスイッチによる割り込みのところで述べる)
フレームワークプロジェクトを使って,以下のプログラムを行う。
main.c
/* Includes ------------------------------------------------------------------*/
#include <stm32f30x.h>
#include <stdint.h>
#include "stm32f30x_conf.h"
#include "stm32f3_discovery.h"
#include <stdio.h>
void initIntervaltimer(int32_t frequency);
int main(void)
{
/* Configure LED3 and LED4 on STM32F0-Discovery */
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
/* SysTick end of count event each 1ms */
initIntervaltimer(1000); /* 1000Hz, 1000 interrupts/sec */
/* Turn on LED3 Green LED */
STM_EVAL_LEDOn(LED3);
/* Turn off LD4 Blue LED */
STM_EVAL_LEDOff(LED4);
while(1);
}
/*インターバルタイマー割り込み初期設定 割り込み周波数[Hz]を引数で渡す*/
void initIntervaltimer(int32_t frequency)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / frequency);
}
//インターバルタイマー割り込み関数
void SysTick_Handler(void)
{
static int32_t count=0;
count++;
if (count==500) {
count=0;
/* LED3 LED4 toggles each 500 ms */
STM_EVAL_LEDToggle(LED3);
STM_EVAL_LEDToggle(LED4);
}
}