メインプログラム:IR_TX.c
プロセッサーエキスパート(PE)で設定した結果、下図の様なソースが生成されます。初期設定は全て完了していますのでMAIN関数の含まれているIR_TX.cのみを記述します。メインプログラムはSWが接続されているポートを読み込んでフラッグを設定します。フラッグが立っていればSWが押されたと判断してデータを送信します。送信はNECフォーマットに基づいてパルスを発生させ、リーダーコード・カスタムコード・データコード・ストップビットを送信して戻ります。フラッグが立たない場合は,またSWのチェックを繰り返します。約6万5千回チェックしてもフラッグが立たない場合はSW割込みを許可してウェイトモードに移行して消費電力を抑えます。ウェイトモードからのウェイクアップはSW割込みで通常モードに移行し、直ちにフラッグが立ちますので送信を行います。通常モードからウェートモーで移行までの時間はおよそ2秒です。
メインプログラムは以下の関数から構成されます。
宣言部について
38kHz変調関数
void IR_Pulse(void)
下図に示す38kHzのパルスを発生する関数です。IrLEDはIR_OUTと名付けた2ビットのポートに接続されています。Hi(1)にすると点灯し、Low(0)にすると消灯します。NECフォーマットでは点灯時間 8.77μSですから、IR_OUT_PutVal(3);でポートを二つともHiにして8.77μS待ちます。ポートを”0”に戻して消灯時間は 26.3μSとなっていますので待ちます。この関数は1パルスだけ発生させる関数ですから、必要な時間だけ繰り返します。消灯時間についてはこの関数自身が呼び出されてから点灯するまでの時間も含まれますので考慮しています。
/***************
* 38kHz変調関数 *
***************/
void IR_Pulse(void)
{
IR_OUT_PutVal(3); // 赤外線(IR)LED点灯
i = 0; // 8.77uS待機
while (i)
{
i = i-1;
}
asm
{
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
}
IR_OUT_PutVal(0); // 赤外線(IR)LED消灯
i = 1; // 12.4uS待機(12.4uS+次の点灯までの時間5.125uS=17.53uS)
while (i) // 8.77uS(ON)+17.53uS(OFF)=26.3uS(38kHz)
{
i = i-1;
asm
{ // Wait 17.625uS
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
}
}
asm
{
nop // (1 c: 125 ns) wait for 1 c
nop // (1 c: 125 ns) wait for 1 c
}
}
"0"出力関数
void Send_0(void)
下図に示すDATA=0を発生させる関数です。0.56mSだけ38kHzパルスを発生させ、その後は待機して1.25mS周期の信号を生成します。38kHzを21回繰り返してONの期間0.56mSを生成し、OFFの期間はDelayで0.5mSと微調整として何もしない繰り返しを21回で調整しています。
/*************
* "0"出力関数 *
*************/
void Send_0(void) // Data=0 を出力(1.125mS)
{
for (c=0;c<21;c++) IR_Pulse(); // ON 0.56mS
Cpu_Delay100US(5); // OFF 0.56mS
for (c=0;c<21;c++);
}
"1"出力関数
下図に示すDATA=1を発生させる関数です。ONの期間はDATA=0と同じですがOFFの期間が約3倍になっています。
/*************
* "1"出力関数 *
*************/
void Send_1(void) // Data=1 を出力(2.25mS)
{
for (c=0;c<21;c++) IR_Pulse(); // ON 0.56mS
Cpu_Delay100US(17); // OFF 1.7mS
}
Leader Code出力関数
void LeaderCode(void)
下図に示すリーダーコードを発生する関数です。ONの期間を9mS生成し、OFF期間は4.5mSをDelayで生成します。
/**********************
* Leader Code出力関数 *
**********************/
void LeaderCode(void) // リーダーコードを出力(9mS+4.5mS)
{
for(c=0;c<342;c++) // ON期間は9mS
{
IR_Pulse(); // 変調出力
}
Cpu_Delay100US(45); // OFF期間は4.5mS
}
Repeat Code出力関数
void RepeatCode(void)
下図に示すリピートコードを発生する関数です。リーダーコードに対してOFF期間が半分になっており、最後にストップビットが入ります。
今回はこの関数を使用していません。
/********************
* Repeat Code出力関数 *
*********************/
void RepeatCode(void) // リピートコード出力(11.25mS)未使用
{
for(c=0;c<342;c++) // ON期間は9mS
{
IR_Pulse(); // 変調出力
}
Cpu_Delay100US(22); // OFF期間は4.5mS
for(i=1;i<24;i++){}
Send_0(); // Stop Bit出力
}
赤外線送信関数
void SendIR(void)
1フレーム送信する関数です。1フレームは105mSなので16ビットモジュロカウンタで計測します。
以下の順序で送信します。
1.リーダーコード
2.カスタムコード上位バイト
3.カスタムコード下位バイト
4.データーコード
5.反転したデーターコード
6.ストップビット
16ビットモジュロカウンター待ちで105mS経過後リターンします。
/***************
* 赤外線送信関数 *
****************/
void SendIR(void) // LeaderCode+CustumCode+DataCode+StopBit
{
PTBD_PTBD4 = 1; // 赤外線出力同期信号
Cpu_Delay100US(1); // 1mS待ち
PTBD_PTBD4 = 0;
TPMSC = 0x0F; // 16ビットモジュロカウンタースタート
LeaderCode(); // リーダーコード送信
for (a=0;a<8;a++) // カスタムコード上位バイト送信
{
x = CUSTOM_CODE_H & BitMask[a];
if (x == 0) Send_0(); else Send_1();
}
for (a=0;a<8;a++) // カスタムコード下位バイト送信
{
x = CUSTOM_CODE_L & BitMask[a];
if (x == 0) Send_0(); else Send_1();
}
for (a=0;a<8;a++) // データコード送信
{
x = DATA_CODE & BitMask[a];
if (x == 0) Send_0(); else Send_1();
}
for (a=0;a<8;a++) // 反転データコード送信
{
x = DATA_CODE & BitMask[a];
if (x == 0) Send_1(); else Send_0(); // "0"→1を送信,"1"→0を送信(反転コード)
}
Send_0(); // Stop Bit送信
Rep_DATA = DATA_CODE; // 送信済みデータをリピート比較用レジスタにコピー
while (TPMSC_TOF == 0); // タイマー待ち(105mS)
}
SWチェック関数
void GetSW(void)
スイッチの状態をチェックする関数です。スイッチはプルアップされているので押されていない状態はHiです。ポートA0〜A4を変数SWAに格納します。一つでもSWが押されるとチャタリングか判断するため1mS待機した後、もう一度ポートAを格納して比較し、同じであればフラッグを立てます。SWBも同様です。
/*****************
* SWチェック関数 *
*****************/
void GetSW(void) // POART A0-3,POART B0-3
{
char Temp;
SWA = SWA_GetVal() & 0x0F; // POART A SW読み込み
if (SWA < 0x0F) // SW ONは有るか?
{
Cpu_Delay100US(10); // 1mS待ち
Temp = SWA_GetVal() & 0x0F; // SWAチャタリングチェック
if (SWA == Temp)flag = 1; // SW変化フラグセット
}
SWB = SWB_GetVal() & 0x0F; // POART B SW読み込み
if (SWB < 0x0F) // SW ONは有るか?
{
Cpu_Delay100US(10); // 1mS待ち
Temp = SWB_GetVal() & 0x0F; // SWBチャタリングチェック
if (SWB == Temp)flag = 1; // SW変化フラグセット
}
}
割込み解除処理
void interrupt VectorNumber_Vkeyboard KBI_isr()
ウェイトモードからKBIによってウェークアップすると、この関数が呼び出されます。KBI割込みを禁止して戻ります。
/***** 割込み解除処理 *****/
void interrupt VectorNumber_Vkeyboard KBI_isr()
{
KBISC_KBIE = 0;
}
メイン関数
void main(void)
PEで生成された関数の初期設定まではPEの自動生成です。
カスタムコード設定は16ビットです。筆者が設定したカスタムコードは0x0078です。0x0000から0x00FFまでは自由に使用できるので好きな番号に設定してください。
内臓基準クロック設定はOSBDMでデバッグする時に必要になる設定です。OSBDM以外のツールでは必要ないかもしれません。詳しくは”OSBDMの製作”をご覧ください。
タイマー設定は16ビットモジュロタイマーを使用して105mSのフレーム周期を設定します。
メインループ
ウェイトモードモニター用にポートをセット(通常モード)し、SWをチェック。フラッグが立っていればSWA,SWBのデータに応じてデーターコードをセットして送信します。変数”j”はメインループカウンターで”j”が0xFFFAを超えるとウェイトモードモニター用にポートをクリアし、ウェイトモードに移行します。
/*************
* メイン関数 *
*************/
void main(void)
{
/* Write your local variable definition here */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
/* Write your code here */
/* For example: for(;;) { } */
/***** カスタムコード設定 *****/
CUSTOM_CODE_H = 0x00; // 送信機カスタムコード上位8ビット
CUSTOM_CODE_L = 0x78; // 送信機カスタムコード下位8ビット
/***** 内臓基準クロック設定 *****/
ICSTRM = 0xA4; // 内部基準クロック16MHzのトリム値上位8ビット
ICSSC_FTRIM = 0; // 内部基準クロック16MHzのトリム値下位上位8ビット
/***** タイマー設定 *****/
TPMSC = 0x00; // 16ビットモジュロタイマーディスエーブル
TPMMODH = 0x19; // 16ビットモジュロカウンタ=105mS
TPMMODL = 0xA2;
/***** メインループ *****/
for(;;)
{
PTBD_PTBD5 = 1; // 確認用 Hi= 通常モード
j = j++;
GetSW(); // SWチェック
if (flag==1)
{
flag = 0;
if ((SWA & BitMask[0]) == 0) DATA_CODE = 7; // 未使用
if ((SWA & BitMask[1]) == 0) DATA_CODE = 6; // 未使用
if ((SWA & BitMask[2]) == 0) DATA_CODE = 5; // Right
if ((SWA & BitMask[3]) == 0) DATA_CODE = 4; // Left
if ((SWB & BitMask[0]) == 0) DATA_CODE = 3; // UP
if ((SWB & BitMask[1]) == 0) DATA_CODE = 2; // Down
if ((SWB & BitMask[2]) == 0) DATA_CODE = 1; // Punch
if ((SWB & BitMask[3]) == 0) DATA_CODE = 0; // Kick
SendIR(); // 送信出力
j = 0;
}
KBIPE = 0xFF;
KBISC_KBIE = 1;
if (j > 0xFFFA)
{
PTBD_PTBD5 = 0; // 確認用 Low=WAITモード
_asm(wait); // WAIT MODE SET!
}
}
}