PIC24FJで4足ロボットの製作(その8) [PIC]
今回はリモート制御のための赤外線コントロールについて書いてみます。
ハードウェアを簡略化するために 赤外線でのコントロール実験 の記事で紹介した安価な家電用赤外線受信ユニット(PL-IRM0208-A538)を使用します。通信方式は通信速度を極力高速化(家電方式の約20倍)した独自方式です。
概要を 赤外線コントロールの実験 (←上記とは違うWebページ)にまとめていますので参考にしてください。
上記の記事では受信側を PIC16F88 を使ってエッジ(信号状態変化)割込みとタイマー割り込みを使って実現しましたが、受信処理内容を改めて見てみると割込み処理内での処理時間まで考慮した結構複雑な処理を行っています。
今回は PIC24FJ を32MHzで使うので割込み処理内の時間は考慮しなくても大丈夫と思います。また、上記 URL では受信処理内容について細かく記載していませんでしたので再度整理しました。
[TOP] [ 前へ ] 連載記事 [ 次へ ]
ハードウェアを簡略化するために 赤外線でのコントロール実験 の記事で紹介した安価な家電用赤外線受信ユニット(PL-IRM0208-A538)を使用します。通信方式は通信速度を極力高速化(家電方式の約20倍)した独自方式です。
概要を 赤外線コントロールの実験 (←上記とは違うWebページ)にまとめていますので参考にしてください。
上記の記事では受信側を PIC16F88 を使ってエッジ(信号状態変化)割込みとタイマー割り込みを使って実現しましたが、受信処理内容を改めて見てみると割込み処理内での処理時間まで考慮した結構複雑な処理を行っています。
今回は PIC24FJ を32MHzで使うので割込み処理内の時間は考慮しなくても大丈夫と思います。また、上記 URL では受信処理内容について細かく記載していませんでしたので再度整理しました。
- 制御信号
制御信号は上記URLのページにも書いてありますが下記のようになります。
- PCM信号はLSB側から出力する。
- ビット1は変調信号送信(オン)、ビット0は変調信号オフとする。
- 1ビット分の送信で
- ビット1:38KHzの変調波を6サイクル(156us)送信
- ビット0:6サイクルの時間38KHz信号をオフ。但し直前の送信ビットが1の場合、12サイクルの時間オフにする。
- 制御信号のフォーマット
[1+ID(4)+01] + [0ff-ffff] + [1ss-ssss] + [0tt-tttt] + [1oo-oooo] + [0cc-cccc]
f,s,t,oはそれぞれ1~4chの値で6ビット長なので64段階の制御可能
cは制御信号のチェックサム値で誤り検出用
構成としては 7bit x 6 でエッジ同期でディコードするのでエッジなし最長時間を保証するため、各データの最上位に同期用のビットを付加し、この同期用ビットは交互に反転しています。
- 制御信号例
制御信号の波形例(コントロール信号の値は 0x4d, 0x00, 0x40, 0x20, 0x40)を下図に示します。黄色が赤外線受信ユニットの出力波形で紫色がタイマー割込み毎にトグルで変化させた波形(ディバッグのために一時的に出力させたモニタ信号)です。
制御信号例
- タイマー割込みのタイマー値
赤外線受信ユニットの出力は赤外線有の時のパルス幅(Low出力)が実際の赤外線出力時間よりも長くなり、逆に赤外線なしの場合のパルス幅(High出力)は赤外線がない時間よりも短くなります。
このため、ディコード処理が少々面倒で、エッジ割込みとタイマー割込みを使って処理しています。
タイマー割込みのタイマー値は条件に応じて変更する必要があり、条件分けとしてはエッジ割込み時のタイマー設定とタイマー割込み時のタイマー設定のそれぞれについて赤外線受信ユニット信号の値(0または1)で場合分け(2x2=4通り)する必要があります。
それぞれの条件でのタイマー設定値は下記のようになります。
尚、下表でのタイマー値設定欄で記載している記号の意味は次の通りです。
- Tb : 1bit長(156 us)
- Ta : 赤外線有時の赤外線受信ユニットの出力パルス幅の増加分
- Tm : エッジ変化可能性ありの時刻に加算するタイマー値(= Tb / 2 )
No 割込み処理 赤外線有無 タイマー設定値 下図対応個所 1 エッジ割込み 有 Tb + Ta + Tm ① 2 エッジ割込み 無 2 * Tb - Ta + Tm ③ 3 タイマー割込み 有 Tb ② 4 タイマー割込み 無 Tb ④
タイマー割込み設定値のサンプルケース
- Ta の値について
赤外線受信ユニットの出力での赤外線有の時のパルス幅(Low出力)の増加時間について再度確認してみました。
コントロール信号が 0x4d, 0x18. 0x4e, 0x20, 0x40, 0x3b の波形を用いてシンクロで赤外線ユニットの出力信号幅を実測し、赤外線の出力時間との差異を確認しました。
結果が下表で差異を平均すると 44.7 us という結果になりました。この結果から前項での Ta の値を 50 us にしたところ、赤外線受信処理でのディコードが安定するようになりました。
赤外線受信ユニットの0/1パルス幅の非対称性
- 割込み処理及び初期化
フローチャート化等すればベターなのでしょうが、上記の赤外線受信処理のエッセンスから実装可能と思います。
参考に初期化と割込み処理のソースを付けておきます。
尚、赤外線受信ユニットの出力信号は _RA1 で読み込んでいます(下記ソースでは IR_BIT )
/* * First IR control receiver * for PIC24FJ64GA * Ver 0.01 by skyriver 2016/08/21 */ #include "io.h" #include "IrRcv.h" /* timing parameter definition */ #define TM4_LENGTH 4 // timer4 clock [uSec] #define TM_1BIT_LEN 156 // one bit length[uSec] #define TM_1_ADD 50 // 1(low) bit additional time [us] #define TM_MARGIN (TM_1BIT_LEN / 2 ) // time up timing #define TM_UNSENCE 10000 // unsense timer(wait next signal) [us] #define TM_SET(x) PR4 = ( (x) / TM4_LENGTH ) IRDAT_TYP IrDat; #define RcvCmpBit IrDat.RcvFlg.bits.b0 // receive data exist #define RcvRcvingBit IrDat.RcvFlg.bits.b2 // receiving flag #define RcvPreBit IrDat.RcvFlg.bits.b3 // receive privious bit #define RcvNoRcvBit IrDat.RcvFlg.bits.b4 // no receive bit uint8_t *RcvBufPnt; BYTE_BIT RcvData; // received control data #define RcvDataMSB RcvData.bits.b7 uint8_t RcvBitCnt; // receive data bit counter uint8_t RcvByteCnt; // receive data byte counter uint8_t RcvChkSum; // receive data check sum uint8_t RcvID; // receive ID No #define ENABLE_TMR4 T4CONbits.TON = 1 #define DISABLE_TMR4 T4CONbits.TON = 0 void CheckEnd( void ); void __attribute__((interrupt, no_auto_psv)) _CNInterrupt( void ) { CN_MON ^= 1; // ___ for debug if( RcvNoRcvBit == 0 ) { // if can receive if( RcvCmpBit == 0 ) { // if receive data doesn't exist if( RcvRcvingBit == 0 ) { // if not receiving if( IR_BIT == IR_BIT1VAL ) { // if IR signal is active TMR4 = 0; TM_SET( TM_1BIT_LEN + TM_1_ADD + TM_MARGIN ); ENABLE_TMR4; RcvRcvingBit = 1; RcvPreBit = 1; RcvByteCnt = RCVDATALEN; // set receive byte counter RcvBitCnt = RCVDATABLEN; // set bit counter RcvBufPnt = &IrDat.RcvDataBuf[ 0 ]; RcvData.byte = 0; RcvChkSum = 0; } } else { TMR4 = 0; if( IR_BIT == IR_BIT0VAL ) { TM_SET( 2 * TM_1BIT_LEN - TM_1_ADD + TM_MARGIN ); } else { TM_SET( TM_1BIT_LEN + TM_1_ADD + TM_MARGIN ); } RcvDataMSB = RcvPreBit; RcvData.byte >>= 1; RcvPreBit ^= 1; CheckEnd(); // check byte end } } } _CNIF = 0; } void __attribute__((interrupt, no_auto_psv)) _T4Interrupt( void ) { TM0_MON ^= 1; // ___ for debug if( RcvNoRcvBit == 0) { // if not inhibit to receive(=receiving) TMR4 = 0; TM_SET( TM_1BIT_LEN ); RcvDataMSB = RcvPreBit; // receive same as previous data RcvData.byte >>= 1; CheckEnd(); // check byte end } else { RcvNoRcvBit = 0; DISABLE_TMR4; _CNIE = 1; // enable CN int } _T4IF = 0; } /* check byte end */ void CheckEnd( void ) { if( --RcvBitCnt == 0 ) { // if byte data receive completely RcvBitCnt = RCVDATABLEN; *RcvBufPnt++ = RcvData.byte; RcvChkSum ^= RcvData.byte; if( --RcvByteCnt == 0 ) { RcvRcvingBit = 0; if( RcvChkSum == RCVDATMSB ) { // if check sum is ok RcvCmpBit = 1; // set receive complate flag RcvNoconBit = 0; } } else { if( RcvByteCnt == ( RCVDATALEN - 1 ) ) { // if first byte if( RcvData.byte != RcvID ) { // if not my ID RcvRcvingBit = 0; } } else if( RcvByteCnt & 1 ) { // if first, third or fifth byte if( RcvData.bits.b6 == 0 ) { // if format error RcvRcvingBit = 0; } } else if( RcvData.bits.b6 == 1 ) { // if format error RcvRcvingBit = 0; } } RcvData.byte = 0; if( RcvRcvingBit == 0 ) { // if receive proc end RcvNoRcvBit = 1; TMR4 = 0; TM_SET( TM_UNSENCE ); _CNIE = 0; // disable CN int } } } // IR receive initial setting void IrRcvIni( void ) { CNPU1 = 0x0008; // set IRbit PullUp(CN3:RA1) CNEN1 = 0x0008; // enable IRbit(CN3:RA1) change interrupt _CNIF = 0; // clear CN int flag _CNIE = 1; // enable CN interrupt T4CON = 0x2020; // TON:OFF TSIDL 1/64(4us clock) _T4IE = 1; // enable time4 interrupt IrDat.RcvFlg.byte = 0; RcvID = (DEFAULT_CH << 2) | 0x41; }
[TOP] [ 前へ ] 連載記事 [ 次へ ]
コメント 0