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

20140530 coskx
T.SATOH

1.はじめに

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

2.プログラムの要点


割り込み関数を使うには次のような準備が必要である。
(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)ごとに生じている。
(割り込み設定の一般的なことは,プシュスイッチによる割り込みのところで述べる)

3.プログラム

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

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);
    }
}