忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

タイマー割込機能を試す

前回に作成したSH7125のタイマー割込機能を試します。

ファイルはとりあえず
 汎用IO設定ソース:io_setup.c
 汎用IO設定ヘッダ:io_setup.h
 CMT設定ソース:intCMT.c
 CMT設定ヘッダ:intCMT.h
の4つを使います。

※初期化関数名をInit_CMT0からinit_CMT0へ変更しました。

プロジェクトの準備~ビルド

方法はPWMの時と一緒です。
ってかこの説明文もPWM機能を試すのコピペです。
とりあえず付属CDのコンパイル編に従ってプロジェクトを作ります。
説明画像は「sh7125_PWM_test」を作成する際のものを流用しています。
今回は「sh7125_CMT_test」を作成するので、図中の「sh7125_PWM_test」を「sh7125_CMT_test」と読み替えてください。

1)HEWを起動・新規プロジェクトワークスペースの作成


ワークスペース名:sh7125_CMT_test(任意で構いません。ワークスペース名に半角カッコ()を使うと動かない事があります。
プロジェクト名:sh7125_CMT_test(ワークスペース名と同じでOK)
ディレクトリ:標準設定では「C:\WorkSpace」内に作成されます。
CPU種別、ツールチェイン:SuperHって名前が入っている方。多分標準で選択されているはず。
この項はこれでOKです。

次のページ CPU:使用するCPUとC言語を機械語に変換する機能(ツールチェイン)を選択します。

ツールチェインバージョン:標準選択で構いません。インストールしたHEWのバージョンで多少違います。
CPUシリーズ:SH-2
CPUタイプ:SH7125
以降は標準選択を使用するので完了ボタンでもOKです

オプション:よく分かりません。標準選択で構いません。
生成ファイル:よく分かりません。標準選択で構いません。
標準ライブラリ:多分使用したいライブラリの選択です。標準選択で構いません。
スタック領域:多分メモリ関係の設定です。標準選択で構いません。
ベクタテーブル:よく分かりません。標準選択で構いません。
デバッガ:シミュレータデバッガ関連の様ですがよく分かりません。標準選択で構いません。
生成ファイル名:自動生成されるファイル一覧が表示されます。とくに選択する要素はありません。

2)ファイルの追加

一旦HEWは置いておいてプロジェクトを作成したフォルダを開きます。
今回の設定では C:\WorkSpace\sh7125_CMT_test です。
sh7125_CMT_testフォルダの中にsh7125_CMT_testフォルダがあるので開きます。
ここにダウンロードしたファイル4つを入れます。

3)ファイルの登録

HEWに戻って操作します。
メニューよりプロジェクト→ファイルの追加


作成(ダウンロード)したファイル4つを登録します。
画像では「intMTU」になっていますが、今回は「intCMT」を使用します。

1つづつ登録しても、4つまとめて登録してもどちらでも構いません。

4)ファイルの編集1:割り込み機能の有効化

ファイルが追加できたところで、割り込み関数を登録します。
左側の一覧の「C source file」よりresetprg.cを開いて編集します。
36行目付近
#define SR_Init    0x000000F0

#define SR_Init    0x00000000
へ変更します。

5)ファイルの編集2:割り込み関数の登録

ファイルが追加できたところで、割り込み関数を登録します。
左側の一覧の「C source file」よりintprg.cを開いて編集します。
379行目付近
void INT_CMT0_CMI0(void){/* sleep(); */}

void INT_CMT0_CMI0(void){CMT0_INT_CMI();}
へ変更します。

387行目付近
void INT_CMT1_CMI1(void){/* sleep(); */}

void INT_CMT1_CMI1(void){CMT1_INT_CMI();}
へ変更しておきます。

6)ファイルの編集3:メインファイルの編集

続いてメインファイルを編集します。
sh7125_CMT_test.cを開いて中身をまるごと書き換えます。
<設定>
#include "io_setup.h"    //汎用IO機能の読込
#include "intCMT.h"    //PWM機能の読込

void main(void){
    hardware_setup();    //汎用IOの初期化
    init_CMT0( );      //タイマ機能の初期化(1ms)
    set_LED_R( 0 );    //LED赤 消灯
    set_LED_G( 0 );    //LED緑 消灯
   
    while(1){
        if((getsystime()/1000)%2){    //システム時刻取得
            set_LED_R( 0 );    //LED赤 消灯
            set_LED_G( 1 );    //LED緑 点灯
        }else{
            set_LED_R( 1 );    //LED赤 点灯
            set_LED_G( 0 );    //LED緑 消灯
        } // end if
    } // end while
}

<解説>
無限ループの中でシステム時刻をベースにLEDの点灯切り替えを行っています。
1ms単位のシステム時刻を1000で割って1秒単位にしています。
更にこれを2で割った余り(%演算子)をif文の判定に使用します。
これでタイマー割込を使用する準備ができました。
ビルドしてエラーが出なければ成功です。

書き込み~動作確認。

書き込んで実行します。
書き込んで実行してください。
1秒おきに赤と緑のLEDが交互に点灯すれば成功です。


応用編

LEDのONディレイ機能を作ってみます。
スイッチの変化をトリガーにして、スイッチが切り替わって1秒後にLEDを点灯させます。
sh7125_CMT_test.cを開いて中身をまるごと書き換えます。

<設定>
#include "io_setup.h"    //汎用IO機能の読込
#include "intCMT.h"    //PWM機能の読込

void main(void){

    int sw=0,sw_old=0; //スイッチ用変数
    unsigned long led_timer=0; //LED点灯予定時刻変数

    hardware_setup();    //汎用IOの初期化
    init_CMT0( 1 );            //タイマ機能の初期化
    set_LED_R( 0 );    //LED赤 消灯
    set_LED_G( 0 );    //LED緑 消灯

    //変数の初期化
    led_timer=getsystime();  //現在時刻で初期化
    sw_old=get_sw1();  //現在のスイッチの状態で初期化
   
    while(1){
        sw=get_sw1();  //スイッチの状態取得
        if(sw_old!=sw){  //スイッチに変化があった
            led_timer=getsystime()+1000; //点灯予定時刻=現在時刻+1000msを指定
        } // end if sw
        sw_old=sw;   //現在のスイッチの状態を保存して次周期で使う

        set_LED_G(sw);  //スイッチでLED緑を制御

        if(getsystime()>led_timer){ //現在時刻が点灯予定時刻を超えた
            set_LED_R( 1 );    //LED赤 点灯
        }else{
            set_LED_R( 0 );    //LED赤 消灯
        } // end if led_timer

    } // end while
}

<解説>
get_sw1()で現在のスイッチの状態を取得します。
前周期のスイッチの状態を比較して一致していなかったらスイッチに変化があったと判定します。
スイッチに変化があったときLEDの点灯予定時刻を設定します。
LEDの点灯予定時刻は現時刻+1000msとしました。

LED緑は純粋にスイッチで切り替わります。
LED赤はLEDの点灯予定時刻を越えるまで消灯しておき、現在時刻が点灯予定時刻を越えたら点灯させます。


ループ周期の安定化

私が所属するグループで使用しているプログラム構成の一つです。
<設定>
#include "io_setup.h"    //汎用IO機能の読込
#include "intCMT.h"    //PWM機能の読込

#define SAMPLE_TIME 50 //実行周期

void main(void){
    unsigned long loop_timer=0;
    hardware_setup();    //汎用IOの初期化
    init_CMT0( 1 );    //タイマ機能の初期化

    //変数の初期化
    loop_timer=getsystime();
   
    while(1){
        if(getsystime()>loop_timer){
            loop_timer=getsystime()+SAMPLE_TIME;
            /*ここに一定周期で実行する処理を記述*/
           
           
        } // end if loop_timer
       
        /*ここに受信などの高速で連続実行する処理を記述*/
       
    } // end while
}
<解説>
50ms周期で処理を実行するプログラムのベースです。
タイマ割込の実行周期を50msに設定をすることもできますが、使用可能なタイマーの数は限られます。タイマー割込はシステム時刻の設定に使用しシステム時刻を使いながら、ループ時間を安定させます。
PID制御など速度の計算が必要な処理等に使用しています。
一定周期で実行する箇所でセンサー値を読み取り、1周期前のセンサー値と比較する事でセンサー値の変化速度を測定します。
周期毎にセンサー値を取得して処理するため、1周期を「1サンプル」と呼び、1周期前のことを「1サンプル前」等と言います。

関連:当ブログで扱うSH7125の特殊機能一覧
PR

コメント

プロフィール

HN:
ぼんどF博士
性別:
男性
自己紹介:

最新コメント