C言語

赤外線リモコン受信処理の実装

赤外線リモコン受信処理は、赤外線リモコン受信モジュールからのデータを受信します。
コードが大きいため、最初に関数の概要について解説します。

G_DrRcvCtrl_Init関数

G_DrRcvCtrl_Init関数は、赤外線リモコン受信初期化処理です。
赤外線リモコン受信処理のモジュール内のスタティック変数の初期化を行います。
こちらの関数は、メイン処理を行う前にメイン処理から呼び出されます。

G_DrRcvCtrl_Start関数

G_DrRcvCtrl_Start関数は、赤外線リモコン受信開始処理です。
赤外線リモコン受信を受け取るために、赤外線リモコン受信したときの外部イベントによるHI区間のタイマの割り込み開始と、受信継続の監視タイマの割り込み開始を行います。
また、このとき、赤外線リモコン受信したときの外部イベントによるHI区間のタイマを開始します。
こちらの関数も、メイン処理を行う前にメイン処理から呼び出されます。初期化関数を呼び出した後に呼び出します。

G_DrRcvCtrl_Sleep関数

G_DrRcvCtrl_Sleep関数は、赤外線リモコン受信スリープ処理です。
赤外線リモコン受信が一定時間ない場合、メイン処理にてHALTモードにするのですが、このHALTモードに移行する前にこちらの関数を呼び出します。
ここでは、HALTモードからの復帰を赤外線リモコン受信したときの外部イベントによるHI区間のタイマの割り込みのみとするため、受信継続の監視タイマを停止させます。

U1G_DrRcvCtrl_GetRcvFinFlg関数

U1G_DrRcvCtrl_GetRcvFinFlg関数は、受信完了フラグ取得処理です。
赤外線リモコン受信処理にて、リーダーコードから始まるデータの全受信が完了したときにONするフラグを呼び出し元に返します。
こちらの関数は、メイン処理にて、この受信完了フラグがONの場合、受信データの解析を行うために使用します。

G_DrRcvCtrl_ClrRcvFinFlg関数

G_DrRcvCtrl_ClrRcvFinFlg関数は、受信完了フラグクリア処理です。
受信完了フラグをクリアします。
こちらの関数は、メイン処理にて、この受信完了フラグがONを検知したとき、受信データの解析を行う前にクリアをし、同じ受信データの解析を複数回行うことを防止するためにフラグをクリアさせるために、この関数を呼び出します。

U1G_DrRcvCtrl_GetRcvCntinuFlg関数

U1G_DrRcvCtrl_GetRcvCntinuFlg関数は、受信継続フラグ取得処理です。
赤外線リモコン受信処理にて、リーダーコードから始まる全データの受信が完了したときに受信継続フラグをONする、または、リピートコードを受信したときにONします。
受信継続の監視タイマがタイムアップしたときに、このフラグをOFFすることにより、ボタンが押下し続けているかを判定するために用意したフラグです。
こちらの関数は、メイン処理にて、受信継続フラグがOFFになっていたら、モータを停止するため、この判定に使用します。

G_DrRcvCtrl_GetRcvData関数

G_DrRcvCtrl_GetRcvData関数は、赤外線リモコン受信処理にて受信したリーダーコードから始まる全データの値を引数で指定した配列にセットします。
こちらの関数は、赤外線リモコン受信データ解析処理にて、こちらの関数を経由して受信データを取得するために使用します。

Int_DrRcvCtrl_Main関数

Int_DrRcvCtrl_Main関数は、赤外線リモコン受信処理で、赤外線リモコン受信モジュールのメインとなる処理です。
この関数は、赤外線リモコン受信モジュールに接続されてるポートの立ち下がりを検出したときのタイマ割り込み処理として実行されます。
このタイマは、赤外線リモコン受信モジュールに接続されてるポートの立ち上がりにて、カウントを開始し、立ち下がりまでの時間をカウントしていますので、この割り込み処理で、こちらのカウント値を調べて、HI区間の時間により、データの判別を行います。

受信のHI区間の時間がリーダーコードの範囲内なら、受信データバッファの添字0にリーダーコードの受信IDをセットします。このとき、赤外線リモコン受信監視タイマを開始して、期間内の全データの受信が完了しなかった場合、受信データをクリアし、受信継続フラグをOFFして、受信がなかったものとして扱います。

受信のHI区間の時間がリピートコードの範囲内なら、受信データバッファの添字0にリピートコードの受信IDをセットします。このときも、赤外線リモコン受信監視タイマを開始して、期間内の全データの受信が完了しなかった場合、受信データをクリアし、受信継続フラグをOFFして、受信がなかったものとして扱います。

受信のHI区間が0ビット、1ビットの範囲内なら、受信データバッファに0/1をセットします。

受信データがリーダーコードから始まる全33ビット分受信した場合、受信したデータを他のモジュールに渡すための変数にコピーします。これは、受信データ解析処理にて受信したデータを取得する前に次の受信データで上書きされる可能性があるため、受信が終わった直後に退避させるためにコピーしています。
受信が完了したら、受信完了フラグをONし、メイン処理に通知します。また、受信継続フラグをONにします。受信継続フラグをONすることにより、ボタン押下状態を保持します。受信が完了しても107msの赤外線リモコン受信監視タイマは停止せず、この後、リピートコードが来ない場合は、タイムアップにて、受信継続フラグをOFFしボタンが離されたことを通知します。このため、リピートコード受信から、107ms後にまだリピートコードかリーダーコードを再度受信しなければ、ボタンは離されたと判断します。

関数の概要は以上になります。つぎは、実装について解説します。

赤外線リモコン受信処理の実装

実装内容は次の通りとなります。

#include "iodefine.h"
#include "DrRcvCtrl.h"

#pragma interrupt Int_DrRcvCtrl_Main( vect = INTTM01 )
#pragma interrupt Int_DrRcvCtrl_TimOut( vect = INTTM02 )

#define U2S_DRRCVCTRL_READER_LOWER      ((U2)(4380U))
#define U2S_DRRCVCTRL_READER_UPPER      ((U2)(4620U))
#define U2S_DRRCVCTRL_REPEAT_LOWER      ((U2)(2170U))
#define U2S_DRRCVCTRL_REPEAT_UPPER      ((U2)(2320U))
#define U2S_DRRCVCTRL_0BIT_LOWER        ((U2)(520U))
#define U2S_DRRCVCTRL_0BIT_UPPER        ((U2)(600U))
#define U2S_DRRCVCTRL_1BIT_LOWER        ((U2)(1620U))
#define U2S_DRRCVCTRL_1BIT_UPPER        ((U2)(1750U))
#define U2S_DRRCVCTRL_CHANEL2           ((U2)(0x0004U))
#define U2S_DRRCVCTRL_107MS_TIMECNT     ((U2)(0x687DU))
#define U2S_DRRCVCTRL_40MS_TIMECNT      ((U2)(0x2710U))
#define U1S_DRRCVCTRL_RCV_ID_POS        ((U1)(0U))
#define U1S_DRRCVCTRL_INT_ENABLE        ((U1)(0U))
#define U2S_DRRCVCTRL_CHANEL1           ((U2)(0x0002U))

static U1 u1s_RcvDataBuf[ U1G_DRRCVCTRL_RCVDATA_SIZE ];
static U1 u1s_RcvData[ U1G_DRRCVCTRL_RCVDATA_SIZE ];
static U1 u1s_RcvPos;
static U1 u1s_RcvCntinuFlg;
static U1 u1s_RcvFinFlg;

void G_DrRcvCtrl_Init( void )
{
    U1 u1l_Cnt;

    for( u1l_Cnt = U1_CLR; u1l_Cnt < U1G_DRRCVCTRL_RCVDATA_SIZE; u1l_Cnt++ )
    {
        u1s_RcvDataBuf[ u1l_Cnt ] = U1_CLR;
        u1s_RcvData[ u1l_Cnt ] = U1_CLR;
    }
    u1s_RcvPos = U1_CLR;
    u1s_RcvCntinuFlg = U1_OFF;
    u1s_RcvFinFlg = U1_OFF;
    return;
}

void G_DrRcvCtrl_Start( void )
{
    TMMK01 = U1S_DRRCVCTRL_INT_ENABLE;
    TMMK02 = U1S_DRRCVCTRL_INT_ENABLE;
    TS0 |= U2S_DRRCVCTRL_CHANEL1;
    return;
}

void G_DrRcvCtrl_Sleep( void )
{
    TT0 |= U2S_DRRCVCTRL_CHANEL2;
    return;
}

U1 U1G_DrRcvCtrl_GetRcvFinFlg( void )
{
    return u1s_RcvFinFlg;
}

void G_DrRcvCtrl_ClrRcvFinFlg( void )
{
    u1s_RcvFinFlg = U1_OFF;
    return;
}

U1 U1G_DrRcvCtrl_GetRcvCntinuFlg( void )
{
    return u1s_RcvCntinuFlg;
}

void G_DrRcvCtrl_GetRcvData( U1 *u1l_RcvData )
{
    U1 u1l_Cnt;

    for( u1l_Cnt = U1_CLR; u1l_Cnt < U1G_DRRCVCTRL_RCVDATA_SIZE - 1; u1l_Cnt++ )
    {
        u1l_RcvData[ u1l_Cnt ] = u1s_RcvData[ u1l_Cnt + 1 ];
    }
    return;
}

void Int_DrRcvCtrl_Main( void )
{
    U1 u1l_Cnt;
    U2 u2l_Tdr01;

    u2l_Tdr01 = TDR01;

    if( ( u2l_Tdr01 >= U2S_DRRCVCTRL_READER_LOWER )
     && ( u2l_Tdr01 <= U2S_DRRCVCTRL_READER_UPPER ) )
    {
        TT0 |= U2S_DRRCVCTRL_CHANEL2;

        for( u1l_Cnt = U1_CLR; u1l_Cnt < U1G_DRRCVCTRL_RCVDATA_SIZE; u1l_Cnt++ )
        {
            u1s_RcvDataBuf[ u1l_Cnt ] = U1_CLR;
        }

        u1s_RcvPos = U1_CLR;
        u1s_RcvDataBuf[ u1s_RcvPos ] = U1G_DRRCVCTRL_READER_ID;
        TDR00 = U2S_DRRCVCTRL_107MS_TIMECNT;
        TS0 |= U2S_DRRCVCTRL_CHANEL2;
    }
    else if( ( u2l_Tdr01 >= U2S_DRRCVCTRL_REPEAT_LOWER )
          && ( u2l_Tdr01 <= U2S_DRRCVCTRL_REPEAT_UPPER ) )
    {
        TT0 |= U2S_DRRCVCTRL_CHANEL2;

        for( u1l_Cnt = U1_CLR; u1l_Cnt < U1G_DRRCVCTRL_RCVDATA_SIZE; u1l_Cnt++ )
        {
            u1s_RcvDataBuf[ u1l_Cnt ] = U1_CLR;
        }

        u1s_RcvPos = U1_CLR;
        u1s_RcvDataBuf[ u1s_RcvPos ] = U1G_DRRCVCTRL_REPEAT_ID;
        u1s_RcvCntinuFlg = U1_ON;
        TDR00 = U2S_DRRCVCTRL_40MS_TIMECNT;
        TS0 |= U2S_DRRCVCTRL_CHANEL2;
    }
    else if( ( u2l_Tdr01 >= U2S_DRRCVCTRL_0BIT_LOWER )
        &&   ( u2l_Tdr01 <= U2S_DRRCVCTRL_0BIT_UPPER ) )
    {
        u1s_RcvPos++;

        if( u1s_RcvPos < U1G_DRRCVCTRL_RCVDATA_SIZE )
        {
            u1s_RcvDataBuf[ u1s_RcvPos ] = BIT0;
        }
        else
        {
            u1s_RcvCntinuFlg = U1_OFF;
        }
    }
    else if( ( u2l_Tdr01 >= U2S_DRRCVCTRL_1BIT_LOWER )
          && ( u2l_Tdr01 <= U2S_DRRCVCTRL_1BIT_UPPER ) )
    {
        u1s_RcvPos++;

        if( u1s_RcvPos < U1G_DRRCVCTRL_RCVDATA_SIZE )
        {
            u1s_RcvDataBuf[ u1s_RcvPos ] = BIT1;
        }
        else
        {
            u1s_RcvCntinuFlg = U1_OFF;
        }
    }
    else
    {
        /* 処理なし(不正なデータを受信した場合は無視する) */
    }

    if( ( ( u1s_RcvPos + 1 ) >= U1G_DRRCVCTRL_RCVDATA_SIZE )
     && ( u1s_RcvDataBuf[ U1S_DRRCVCTRL_RCV_ID_POS ] == U1G_DRRCVCTRL_READER_ID ) )
    {
        for( u1l_Cnt = U1_CLR; u1l_Cnt < U1G_DRRCVCTRL_RCVDATA_SIZE; u1l_Cnt++ )
        {
            u1s_RcvData[ u1l_Cnt ] = u1s_RcvDataBuf[ u1l_Cnt ];
        }
        u1s_RcvFinFlg = U1_ON;
        u1s_RcvCntinuFlg = U1_ON;
    }
    return;
}

void Int_DrRcvCtrl_TimOut( void )
{
    TT0 |= U2S_DRRCVCTRL_CHANEL2;
    u1s_RcvCntinuFlg = U1_OFF;
    return;
}

次にヘッダーファイルの実装内容は次のようになります。

#ifndef DRRCVCTRL_H
#define DRRCVCTRL_H

#include "common.h"

#define U1G_DRRCVCTRL_READER_ID         ((U1)(0x01U))
#define U1G_DRRCVCTRL_REPEAT_ID         ((U1)(0x02U))
#define U1G_DRRCVCTRL_RCVDATA_SIZE      ((U1)(33U))

extern void G_DrRcvCtrl_Init( void );
extern void G_DrRcvCtrl_Start( void );
extern void G_DrRcvCtrl_Sleep( void );
extern U1 U1G_DrRcvCtrl_GetRcvFinFlg( void );
extern void G_DrRcvCtrl_ClrRcvFinFlg( void );
extern U1 U1G_DrRcvCtrl_GetRcvCntinuFlg( void );
extern void G_DrRcvCtrl_GetRcvData( U1 *u1l_RcvData );

#endif

ヘッダーファイルは、基本的に関数プロトタイプ宣言のみです。
受信データ解析処理側で使用することを想定し、定数定義していますが、受信IDを知らなくても解析はできるため使用しないかもしれません。

簡単ではありますが、赤外線リモコン受信処理の実装については以上となります。

-C言語