PICの初期設定
CCS-Cのおまじない
FUSEのセットです。内部クロックはH4で4逓倍させます。(10MHZX4=40MHz)だからといって、20MHZ取り付けて80MHZでは動きません。内部最大は40MHZですので・・・
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/__/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_
//
// SPEED COUNTER
/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/__/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_
#include <18f8720.h>
#fuses H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#device ADC=10//A/D変換10ビットモード
#USE DELAY(CLOCK=40MHZ, CRYSTAL=10MHZ)
#use RS232(BAUD=230400, XMIT=PIN_C6,RCV=PIN_C7)
//割り込み優先設定//
#PRIORITY CCP4,CCP5,CCP3,CCP2,CCP1,TIMER1
インジェクターパルスとは
エンジンへ燃料噴射を行うインジェクター駆動電圧信号を計測します。車種によっては、パルス制御、電流制御、電圧デューティ制御、ECUとは別ユニットにてドライバー制御(D4)等あるみたいです。ここに記載した計測方法は一般的なアクティブローにて燃料噴射を行う車種のみに適用できる方法を記載します。
下記に示すオシログラフが実際の制御電圧を観察したものです。かなり高電圧の誘導起電力が見られます。
インジェクターは制御信号に従って0Vの間の時間だけ燃料が噴射されます。この時間はデューティ制御となっているためパルス立下りと立ち上がりの時間の計測が必要になります。
尚、全てのインジェクターを計測する必要がなく、1気筒のみで燃費計算は出来ますが、気筒休止とかするエンジンでは誤差が大きくなります。

回路
シュミットトリガ2段でもとの極性に変換してます。(別に2段通さなくてもいいんですが)
オペアンプとかコンパレータ使ってもいいんですが、基板のサイズに制約あるのと部品安くするため、こんな回路としました。1N4004は誘導起電力防止のために入れます。極性を逆にすると最悪ECUを壊します。

下記のオシログラフがECU信号にシュミットトリガを通して波形成型した例です。

カウントエラー対策とノイズ対策
車両からのパルスをオシロスコープで観察すると、波形がまともな矩形波ではなく、さらにノイズが混入する場合があります。ハードで対策するには限界があるし、コストがかかってしまうので、ソフト処理でなんとかならないかなと、2年も(笑)試行錯誤してしまいました。実証試験からわかったことは、※タイマーカウンタ割込みによる表示をしなくても、100HZ以上の信号がたまに抜けることがある。
※ノイズが入力されるとミスカウントをしてしまう。
※インジェクション、ATソレノイド等の誘導負荷があるため、ノイズが避けられない
※#device HIGH_INTS=TRUEを宣言して高位割込みを使用するとプログラムメモリ大となる
※各計測パルスの割込み周期が偶発的に一致する。
※移動平均を使用しないほうがよい。
回転数−>高回転で波形が低くなる
インジェクション−>デューティー制御のためあまり使用しないほうがよいかな
※ABS動作、トラクションコントール、冬場のコールドスタート時にノイズが入ってくる場合が ある<BR>
※ABS動作の時の速度波形をパルス抜けとしないようにする必要がある。
※凹凸路面走行での波形処理を考慮する必要がある
※急ブレーキの減速比率を考慮する必要がある。(パルス抜けと処理されないように)
※シフトアップ、シフトダウン時の増減率を考慮する必要がある(パルス抜けと処理されない
ように)<BR>
※速度と回転数はPICの内部クロックを引き上げると低速・低回転でオーバーフローする
別の方法あるんですが、BootLoaderからめるとフリーズするので・・・・<BR>
※CCP UPエッジトリガとDPWNエッジトリガどちらか一方のみで使用できるのは速度と回転数
※インジェクシヨンはCCP UPエッジトリガとDPWNエッジトリガを使用する必要がある。
(デューティー制御のため)
※タイマーカウンタ割込みによる回転数計測は不安定
※エアコン動作するとノイズが混入する場合がある。
※パーキング停止状態でノイズ入ったら、ノイズと判断する(ATの状態監視)
※パルスとりこぼしは全てオリジナルパルス波形時間の2倍前後となる
※パルス時間を比較するよりも、表示対象に変換してから比較したほうがよい
インジェクション:パルス時間小=負荷小とは限らない(開弁率の関係より)
※回転数を基準として考える必要がある
インジェクションのパルス異常監視は開弁率から判別します。つまり開弁率100%を超えた場合は異常値と判断します。
エンジンは2行程であることから、エンジン1回転の時間内で噴射された時間の割合が開弁率となります。つまり噴射されていないはずの時間にインジェクタが噴射していれば、異常値であると判断できるからです。
この方法だけでは全てのミスカウントを検出できません。なぜなら、立下りと立ち上がりのパルスが抜けてしまう場合があるからです。下記にその対策方法をまとめてみました。


下記の図は低負荷時のオシロ波形です。高負荷時よりも短いサイクルで噴射されています。低負荷時が最もミスカウントを引き起こしやすいことが分かります。

プログラムソース(ccs-c用)
mainルーティン設定はこのようにします。//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_main_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_
main()
{
setup_ccp1(CCP_CAPTURE_RE); //CCP1動作条件設定 立上りはRE 立下りはFE
cp1edge=0;//fall=1 rise=0
setup_ccp2(CCP_CAPTURE_RE);
setup_ccp3(CCP_CAPTURE_FE);
setup_ccp4(CCP_CAPTURE_FE); //CCP2動作条件設定 立下り
setup_ccp5(CCP_CAPTURE_RE); //CCP2動作条件設定 立下り
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_8);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
setup_timer_3(T3_INTERNAL | T3_DIV_BY_8|T3_CCP1_TO_5);
set_timer1(3035);
enable_interrupts(INT_TIMER1); //タイマ1割込み許可
enable_interrupts(INT_TIMER0); //タイマ0割込み許可
enable_interrupts(INT_CCP1); //CCP2側のみ割込み許可
enable_interrupts(INT_CCP2); //CCP2側のみ割込み許可
enable_interrupts(INT_CCP3); //CCP2側のみ割込み許可
rpm_rise=1;
enable_interrupts(INT_CCP4); //CCP2側のみ割込み許可
enable_interrupts(INT_CCP5); //CCP2側のみ割込み許可
enable_interrupts(GLOBAL); //グローバル割込み許可
・
・
・
・
・
}
割込みにて計測しますのでソースはこのようになります。
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_割り込みCCP4_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_
#int_ccp4 // HIGH
void ccp4_isr()
{
bairitu=0;
if(injfall_f==1)//CCP5 miss count
{
injectionhantei=(old_inj*0.001*0.001*0.1*8);//sec積算//
injectiontime=old_inj*0.1*0.001*8-mukoujikan;//*8*0.001でmsの実時間//
mukou_count=mukou_count+(mukoujikan*0.001);
inj_time=inj_time+(injectionhantei);
injerr=injerr+1;
if(injpulse_n<10000)
injpulse_n=injpulse_n+1;
if(injpulse_n==10000)//9999->10000
{
injpulse_milion=injpulse_milion+1;
injpulse_n=0;
}
}
injfall_f=1;
}
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_割り込みCCP4_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_
#int_ccp5 //HIGH
void ccp5_isr()
{
bairitu=0;
rise =CCP_4; //立上りの時間
fall =CCP_5; //立下りの時間
if (fall > rise)
{
pulse = (fall - rise); //パルス幅=時間差
}
else
{
pulse =( (0xffff - rise ) + fall);
}
inj_count=0;//gasカット判断 700rpm=1min 700 1s=11:
dpulse=(float)pulse;
if((dpulse+100)/(dpulse_rpm*4)>1.0&&dpulse/old_inj>=2&&injfall_f==1)//fall&rise
miss count
{
injerr=injerr+1;
mul2_f=1;
dpulse=old_inj;
}
else if(injfall_f==0)//ccp4 miss count
{
injerr=injerr+1;
mul2_f=1;
dpulse=old_inj;
}
else
{
old_inj=dpulse;
mul2_f=0;
}
injreset=injreset+1;
if(injreset>5)
injreset=10;
if(speed==0)
{
nenpi_odo=0;
}
kaiben=(dpulse/(dpulse_rpm*4))*100;
if(kaiben>100)
kaiben=100;
inj_mul=2;
if(dpulse>0)
{
if(mul2_f==0)//&&mul3_f==0)
{
injectionhantei=(dpulse*0.001*0.001*0.1*8);//(mukoujikan*0.001);//sec積算//
injectiontime=dpulse*0.1*0.001*8-mukoujikan;//*8*0.001でmsの実時間//
mukou_count=mukou_count+(mukoujikan*0.001);
inj_time=inj_time+(injectionhantei);//-mukou_count);
injpulse_n=injpulse_n+1;//無効時間算出計算用の噴射時間積算
}
else if(mul2_f==1)
{
injectionhantei=(dpulse*inj_mul*0.001*0.001*0.1*8);
injectiontime=dpulse*0.1*0.001*8-mukoujikan;//*8*0.001でmsの実時間//
mukou_count=mukou_count+(mukoujikan*0.001)*inj_mul;
inj_time=inj_time+(injectionhantei);//-mukou_count);
injpulse_n=injpulse_n+inj_mul;//無効時間算出計算用の噴射時間積算
}
}
intercept=0;
if(injpulse_n==10000)//無効時間算出計算用の噴射時間積算
{
injpulse_milion=injpulse_milion+1;
injpulse_n=0;
}
else if(injpulse_n>=10001)//無効時間算出計算用の噴射時間積算
{
injpulse_milion=injpulse_milion+1;
injpulse_n=1;
}
if(injectionhantei>0&&injectionhantei<1)
{
totalinjecton+=injectionhantei;
if(speed==0)
idol_gas+=(injectionhantei*gas*gas_hosei);
}
if(totalinjecton<0)
{
totalinjecton=old_totalinjecton;
}
old_totalinjecton=totalinjecton;
injfall_f=0;
}