LEDフリーラン点滅

タイマ割り込み(Static Timer Drivers Library)を使った場合
                          (→プロジェクトファイル(Harmony Ver.2.04版 ) ダウンロード


   LEDのフリーラン点滅を タイマ割り込み(Static Timer Drivers Library)を使って行う場合の例を以下に説明します。
   
<仕様>
 ・ PIC32MZを使用する
 ・ LEDは1sec ON、1sec OFFを繰り返す
 ・ 動作クロックは外部に24MHzの水晶発振器を接続しこれを使用する
 ・ 時間制御は割り込みを使い、Harmonyのスタティックタイマドライバー ライブラリをつかうこと。
 
<回路図>(→回路図のPDFファイル


 


<外観>
<動作結果>
(画像をクリックすると プログラム動作中の動画がYouTubeで再生します)

     
ディスクリートキバン

(PIC32MZ QFPモジュール組立キット → 購入方法
(QFPモジュール用ユニバーサルキバン → 購入方法

 
PIC32MZ評価ボード(MZ100-A001)

( → 購入方法 )
動作結果の
   動画再生
    




<解説> 
   

 右の表は、MHCでスタティックタイマドライバーライブラリー(以下、スタティックタイマと云う)を選択した場合に生成されるファイルの抜粋です。

 ソースコードの黒字の部分はMHCが自動生成する部分です。緑色文字部分がLEDフリーラン(LED 1秒点灯、1秒消灯の繰り返し)として追加記入した部分です。


@system_interrupt.cの中にあるタイマ1割り込みベクトル関数__ISR(_TIMER_1_VECTOR, ipl1AUTO) IntHandlerDrvTmrInstance0(void)が、割り込みが発生すると呼ばれますのでこの中に 割り込み検出フラグTriggerを設定します。


Aapp.cの中にあるAPP_Tasks ( )のAPP_STATE_SERVICE_TASKSステートはmain.cの繰り返し呼び出し関数SYS_Tasks( )から繰り返し呼び出されます。 このステートにタイマ1の割り込みが発生したらLED点滅を実行するソースコードを書き込みます。


BAPP_STATE_SERVICE_TASKSステートの内容は以下のようになっています。
 ・割り込みフラグがたったら、フラグをクリアしてLED点滅動作を実行する。
 ・LEDが点灯していたら消灯し、消灯している時間を周期レジスタに書き込む。  またLEDが消灯していたら点灯し、点灯時間を周期レジスタに書き込む。


Cデフォルトでは、タイマの入力クロックは100MHzです。従ってプリスケール1/256の16ビットタイマの最大カウント時間は 167.7696 msec( = 10nsec x 256 x 65535 = 167769600 nsec)です。 所要の1secより短いのでタイマの入力クロックの ペリフェラルクロック(PBCLK3)を10MHzに変更します。 system_init.cの中にあるSYS_Initialize ( )の青字部分により実行されます。


Dapp.cの中にあるAPP_Initialize ( )で周期レジスタにPICが立ち上がって最初の割り込み発生までの時間を周期レジスタに書き込みます。デフォルトでは"0"が入っているので書き込まないとLEDの点滅は始まりません。


Eapp.cの中にあるAPP_Tasks ( )のAPP_STATE_INITステートにDRV_TMR0_Start()を書き込むとタイマ1の割り込みが許可され、タイマ1がイネーブルになります。




  
 
 ファイル名  ファイルの内容抜粋
 main.c
.....
.....

int main ( void )
{
    
   SYS_Initialize ( NULL ); //システム初期化

    while ( true )
    {
        SYS_Tasks ( );      //繰り返し実行
    } 
    return ( EXIT_FAILURE );
}
 
system_tasks.c   
void SYS_Tasks ( void )
{
    .....
    .....

    APP_Tasks();            //アプリケーション繰り返し実行
}
app.c   

extern bool Trigger;
bool LED;
....
....

void APP_Initialize ( void ) //アプリケーション初期化
{
   
    appData.state = APP_STATE_INIT;
    PLIB_TMR_Period16BitSet(TMR_ID_1,39063); 
                    //50 nsec x2  x 39063 x 256 = 1000012.8μsec = 1000.0128msec
}

void APP_Tasks ( void )      //アプリケーション繰り返し実行
{
    switch ( appData.state )
    {
        case APP_STATE_INIT:    //実行ステート初期化
        {
           DRV_TMR0_Start();   //タイマ割り込み許可、タイマ1イネーブル
            appData.state = APP_STATE_SERVICE_TASKS;
            break;
        }

        case APP_STATE_SERVICE_TASKS: //実行ステート
        {
            if(Trigger == true)
            {
                Trigger = false;
                
                if(LED == false)
                {
                    LED = true;
                    PLIB_PORTS_PinSet( PORTS_ID_0, PORT_CHANNEL_G, 15 ); //RG15:LED点灯                    
                    PLIB_TMR_Period16BitSet(TMR_ID_1,39063);
                     //100 nsec x 39063 x 256 = 1000.0128msec = 1000msec  //LEDのON時間設定
                     // at タイマ用のPBCLK3ペリフェラルクロック:10MHz
                }
                else
                {
                    LED = false;
                    PLIB_PORTS_PinClear( PORTS_ID_0, PORT_CHANNEL_G, 15 ); //RG15:LED消灯
                    PLIB_TMR_Period16BitSet(TMR_ID_1,39063);
                     //100 nsec x 39063 x 256 = 1000.0128msec = 1000msec  //LEDのON時間設定
                     // at タイマ用のPBCLK3ペリフェラルクロック:10MHz
  
                }
            }
            break;
        }

        default:
        {
            break;
        }
    }
}
 
 system_init.c  
....
....

void SYS_Initialize ( void* data ) //システム初期化
{
 ....
 ....
 
// PBCLK3ペリフェラルクロック変更    
    SYS_DEVCON_SystemUnlock();
    PB3DIVbits.PBDIV = 0x13; 
//19: PBCLK3(Timer,OC等ペリフェラルクロック):1/20(デフォルトの1/10) //10MHz(= 200MHz/20)     
    SYS_DEVCON_SystemLock();
  
    DRV_TMR0_Initialize();  //スタティックタイマ初期化

    SYS_INT_Initialize();   //割り込み初期化
  
    SYS_INT_Enable();       //グローバル割り込み許可   

    APP_Initialize();       //アプリケーション初期化
}

 

 system_interrupt.c  

bool Trigger;

void __ISR(_TIMER_1_VECTOR, ipl1AUTO) IntHandlerDrvTmrInstance0(void)
                                                       //タイマ1割り込みベクトル関数
{
    PLIB_INT_SourceFlagClear(INT_ID_0,INT_SOURCE_TIMER_1);//タイマ1割り込みフラグクリア
    
Trigger = true;  //割り込み発生検出>

}

 

 drv_tmr_static.c  
....
....

void DRV_TMR0_Initialize(void) //タイマ1初期化
{   
    PLIB_TMR_Stop(TMR_ID_1); //タイマ1ディセーブル  //T1CONbits.ON = 0;
    PLIB_TMR_ClockSourceSelect(TMR_ID_1, DRV_TMR_CLKSOURCE_INTERNAL); //クロックソース:内部
    PLIB_TMR_PrescaleSelect(TMR_ID_1, TMR_PRESCALE_VALUE_256); //プリスケーラ: 1/256
    PLIB_TMR_Mode16BitEnable(TMR_ID_1); //16ビットモード
    PLIB_TMR_Counter16BitClear(TMR_ID_1); //16ビットカウンタークリア
    PLIB_TMR_Period16BitSet(TMR_ID_1, 0); //周期レジスタPR1に0をセット
    PLIB_INT_VectorPrioritySet(INT_ID_0, INT_VECTOR_T1, INT_PRIORITY_LEVEL1);
                                                                       //主割り込みレベル:1
    PLIB_INT_VectorSubPrioritySet(INT_ID_0, INT_VECTOR_T1, INT_SUBPRIORITY_LEVEL0);
                                                                       //副割り込みレベル:0
}

static void _DRV_TMR0_Resume(bool resume)
{
    if (resume)
    {
        PLIB_INT_SourceFlagClear(INT_ID_0, INT_SOURCE_TIMER_1);//タイマ1割り込みフラグクリア
                                                               //IFS0bits.T1IF= 0;
        PLIB_INT_SourceEnable(INT_ID_0, INT_SOURCE_TIMER_1);//タイマ1割り込み許可   
        PLIB_TMR_Start(TMR_ID_1); //タイマ1イネーブル  //T1CONbits.ON = 1;
    }
}

bool DRV_TMR0_Start(void) //タイマ1スタート
{
    _DRV_TMR0_Resume(true);
    DRV_TMR0_Running = true;
    
    return true;
}

....
....



 <プロジェクト作成手順>(スタティックタイマ割り込みを使った場合)
  はじめてHarmonyの プロジェクトをつくる方も対象に、プロジェクト作成要領について説明します。
   以下は、Harmony v1.08、MPLABX v.3.35 をもとに作成してあります。 (10)のPin Settinsのポート設定の画面がHarmony v.2以降大幅に
  変わりましたのでポート設定画面は v2.04のものに変更してあります。 Harmony v.2.04の時点では、他の部分の変更はありません。
  (最新の Harmony や MPLABX とは、若干異なるところがある可能性がありますので注意してください。)
  (1) Harmony プロジェクト選択
    MPLABXのメニューバーで[File]→[New Project]とすると 下図の[New Project]ダイアログが開きます。[Categories]の[Microchip Embedded]を選んだあと [Projects]の[32bit−MPLAB Harmony Project]を選択して[Next]をクリックします。
     
  (2)  プロジェクトフォルダの作成
  C:\microchip\harmony\v1_08_01\appsフォルダに下にプロジェクトフォルダをつくります。 これ以外のところにプロジェクトフォルダをつくるとコンパイルできなくなることがあります。 今回だけでなく後々他にもたくさんHarmonyのプロジェクトをつくことになるのでここではC:\microchip\harmony\v1_08\apps\_myWork\Test\Basicフォルダの下にプロジェクトフォルダをつくります。
     
  (3)  プロジェクト名、デバイス名 
    ここではプロジェクト名を"02 Led FreeRun Static tmrINT"として、Project Nameに記入します。使用するデバイス名としてPIC32MZ2048EFH100を選択して [Finish]をクリックします。
     
   (4) プロジェクト画面の表示 
    プロジェクト全体の画面があらわれます。 
   
  (5)  プロジェクトのプロパティ設定
    プロジェクトを右クリックしてドロップダウンリストの中から[Properties]を選択します。
   
  (6)  コンパイラの設定
    Project Propertiesのダイアログが開きます。特に理由がなければXC32の最新のコンパイラを選択します。
     
  (7)  シフトJIS選択 
    Categoriesボックスの[General]を選択して、 Encodiongのコンボボックスから[Shift-JIS]を選択します。
   
  (8)   MHCの表示
    右のボックスにMHC(MPLAB Harmony Configurator)の画面が表示されていない場合は、 メニューバーから[Tools] → [Embedded] → [MPLAB Harmony Configurator]をクリックするとMHCの画面が現れます。 
 尚、MHC画面を表示するには左側のプロジェクトWinodowでMHCを開きたいプロジェクトをドロップダウンリストで main project に設定しておく必要があります。
   
  (9)  クロックの設定
    [Clock Diagram]のタブをクリックしてクロック設定の画面を開きます。
 PIC32MZのOSC1ピンに 24MHzの外付け水晶発振器を取り付け、システムクロックが200MHzとなるクロックモジュールの設定を行います。プリプロセッサコマンドで記述すると以下のようになります。

 #pragma config FNOSC = SPLL
 #pragma config POSCMOD = EC
 #pragma config FPLLICLK = PLL_POSC
 #pragma config FPLLIDIV = DIV_3
 #pragma config FPLLMULT = MUL_50
 #pragma config FPLLODIV = DIV_2

 この設定を実現すべくクロックモジュール設定画面で  FNOSC、 POSCMOD、 FPLLICLK、 FPLLIDIV、FPLLMULT、FPLLODIVの各項目のコンボボックスからそれぞれ SPLL、 EC、 PLL_POSC、 DIV_3、 MUL_50、 DIV_2を選択します。
 (下記画面は 画像をクリックすると画像が拡大します)
     
     
    <追記>
 クロックの設定は以下の MHCのDevice & Project Configuration画面でも設定できます。

  (10)   ポートの設定
    ポートの設定(下記のPin Settingsの画面は Harmony v2.04のものです)
    [Pin Settings]のタブを開きます。 Pinの RG15で Function欄を GPIO_OUT に変更します。

  (11)  スタティックタイマ選択(Static Timer Drivers Librayを選択 )
    MHCの[Option]タブを選択して、ツリーからHarmony Framework Configuration→Driver→Timerを選択します。そして"Use Timer Driver ?"のチェックに入れ、Driver Implementationで "STATIC"を選択します。 更に、"Interrupt Mode"、"TMR Driver Instance 0" のチェックをいれます。後は、デフォルト(タイマ1選択、割り込み優先度1、内部タイマクロック、プリスケーラ1/256など)のままにしておきます。
 
     
  (12)  プロジェクト コードの生成
    (Generate Code)ボタンをクリックして、*.hや*.cなどのプロジェクトに関連するファイルを一括で作成します。 MHCを保存するかどうかきいてきますので、特に理由がない場合は SaveボタンをクリックしてMHCを保存します。
   

Generateボタンをクリックしてプロジェクトファイルを一式生成します。

  (13)  割り込みフラグをたてる 
     プロジェクトファイルが一式できあがりました。クリーンビルドしてここまで問題なくプロジェクトファイルができあがっていることを確認します。

 アプリケーションのコーディングに最初として、まずsystem_interrupt.cを修正します。system_interrupt.cのタイマ1割り込みベクター関数 __ISR(_TIMER_1_VECTOR, ipl1AUTO) IntHandlerDrvTmrInstance0(void)の中に割り込みが発生したら グローバル変数にフラグが立つようにします。 ここでは変数名をTriggert とし、 Trigger = true;を書き込みます。 Trigger は、グローバル変数として プリプロセッサで bool Trigger;を 定義しておきます。
     
  (14)  app.cファイル修正
    app.cを以下の要領で修正します。 
   
@ system_interrupt.cで割り込み発生検出用として設定したグローバル変数Triggerをapp.cでも使えるように   
  使えるように定義します。また、LEDのON/OFF状態のフラグ変数も追加します。
 
extern bool Trigger;
bool LED;

 


A デフォルトでは周期レジスタの値は0なので、void APP_Initialize ( )の中に
  PLIB_TMR_Period16BitSet(TMR_ID_1,39063); を追加して 1sec相当の値を周期レジスタに設定します。
   尚、ここで PLIB_TMR_Period16BitSet(TMR_ID_1,39063); を記載しないで MHCの中で Timer Period 欄に
  39063と記載して設定しても同じ動作となります。(→ URL )

void APP_Initialize ( void )
{
    appData.state = APP_STATE_INIT;

    PLIB_TMR_Period16BitSet(TMR_ID_1,39063); 
                   
}


B APP_Tasks ( )のcase APP_STATE_INIT:の中にDRV_TMR0_Start();を追加して タイマ1の割り込みを許可して
  タイマ1をイネーブルにします。

         case APP_STATE_INIT:
        {
            bool appInitialized = true;
            if (appInitialized)
            { 
                DRV_TMR0_Start();   
                appData.state = APP_STATE_SERVICE_TASKS;
            }
            break;
        }


C つづいてcase APP_STATE_SERVICE_TASKS:の中に、タイマ1割り込み検出のフラグをクリアして、LEDが点灯して
  いたら消灯させ消灯していたら点灯させます。 

        case APP_STATE_SERVICE_TASKS:
        {
            if(Trigger == true)
            {
                Trigger = false;
                if(LED == false)
                {
                    LED = true;
                    PLIB_PORTS_PinSet( PORTS_ID_0, PORT_CHANNEL_G, 15 );
                }
                else
                {
                    LED = false;
                    PLIB_PORTS_PinClear( PORTS_ID_0, PORT_CHANNEL_G, 15 );
                }
            }
            break;
        }




 
  (15)   タイマ入力周波数変更
   
 デフォルトでは、タイマの入力クロックは100MHzです。従ってプリスケール1/256の16ビットタイマの最大カウント時間は
167.7696 msec( = 10nsec x 256 x 65535 = 167769600 nsec)です。 所要の1secより短いのでタイマの入力クロックの
ペリフェラルクロック(PBCLK3)を10MHzに変更します。PB3DIVレジスタを変更することによってペリフェラルクロック
(PBCLK3)の周波数を変えることができます。 PBCLK3レジスタを変更するには、事前にシステムロックを実施し、
変更後にシステムロックを解除する必要があります

    SYS_DEVCON_SystemUnlock();
    PB3DIVbits.PBDIV = 0x13;
    SYS_DEVCON_SystemLock(); 

  (16)  プロジェクトのクリーンビルド
    プロジェクトのクリーンとビルドを行う。
   
   
実行ファイルをデバイスに書き込む