インターバルタイマー割り込みによるLEDの点灯消灯

20140530 coskx
T.SATOH

1.はじめに

設定した時間間隔で,割り込みをかけ,2つのLEDを交互に点滅させる。
通常の関数はプログラム内で呼び出されて起動するが,割り込み関数(ハンドラ,割り込みハンドラとも呼ばれる)は,マイクロコントローラにあることが生じた場合に呼び出される関数である。
このプログラムではSystick割り込みという一定時間間隔(ここで示す例では1msecごと)で起動する割り込みが使われており,割り込み関数内でLEDの点灯消灯が行われている。
main関数は通常他の作業を行っているはずだが,ここでは作業なしの無限ループに入っているので何もしない。割り込み関数内でLEDに関する作業が行われている。

2.プログラムの要点


割り込み関数を使うには次のような準備が必要である。
(1)割り込みハンドラを用意する。
(2)Systick割り込みを設定する。

2.1 割り込みハンドラの用意
ハンドラの名前(割り込み関数の名前)は決まっていて,startup_stm32f0xx.sのg_pfnVectors:で始まるベクタテーブル中に書いてある。
SysTick_HandlerがSystick割り込みを受けた時に動作するハンドラの名前である。
リファレンスマニュアルdm00031936.pdf(RM0091)のTable33. Vector tableにSystick(System tick timer)というのがあり,addressが3Cになっている。
0,4,8,c,10,...のように4バイトずつ割り込みハンドラのアドレスが並ぶので,16個目がSystick_Handlerである。startup_stm32f0xx.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_cm0.h内で定義されており,この関数内でNVICの設定で割り込み優先度の設定を行い,またSystick割り込みを有効に している。(優先度の値は3が設定されている。一 番低い!)
したがって,関数SysTick_Config()が呼び出された後は,Systick割り込みが指定時間(ここでは1ms)ごとに生じている。
(割り込み設定の一般的なことは,プシュスイッチによる割り込みのところで述べる)

3.プログラム

フレームワークプロジェクトを使って,以下のプログラムを行う。

main.c
/* Includes ------------------------------------------------------------------*/
#include <stm32f0xx.h>
#include <stdint.h>
#include "stm32f0xx_conf.h"
#include "stm32f0_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);
    }
}