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
回転数SPEEDパルスとは
エンジン一回転で1,2,4,6,8・・・・と0−5Vがパルスとして出力されます。PIC18F8720にはCCP1〜CCP5までキャプチャが可能です。速度、インジェクションで4入力使用するため、回転数はパルス立ち上がりか立下りのどちらかしか利用できません。このため立ち上がり〜立下りまでのパルス時間計測ではなく、パルスの立ち上がりだけを利用してエンジン回転数を算出します。
※700RPM以下はタイマーがオーバーフローするかもしれません
下記の図はECUからデジタルオシロで実際に計測した波形です。ノイズが見られます。


回路
今回はCCP1にてパルスをキャプチャ。2SC1815で受けて波形反転、シュミットトリガで波形を2度反転してますので極性は反転で考えて下さい回路は以下のようにしたとして説明します。
成型後の波形には顕著なノイズは観察されませんでしたが、ブザーを動作させると、0.2vのコモンモードノイズがみられました。PICのエッジトリガ割込みへの影響ですが、74HC14の閾値は
Hレベル:2.7V
Lレベル:1.6V
以上からアナログ入力波形のノイズは問題ないことがわかりました。
ではシュミットトリガからPICへの入力は
Hレベル:0.8V
Lレベル:0.2V
実験では警報ブザーを常に鳴らして、計測しましたが、波形処理が効いているのか?処理波形には異常は見られませんでした。
下のオシロはシュミットトリガ通過後の波形です。ブザーが動作していないときは、問題ないレベルです。

カウントエラー対策とノイズ対策
車両からのパルスをオシロスコープで観察すると、波形がまともな矩形波ではなく、さらにノイズが混入する場合があります。ハードで対策するには限界があるし、コストがかかってしまうので、ソフト処理でなんとかならないかなと、2年も(笑)試行錯誤してしまいました。実証試験からわかったことは、※タイマーカウンタ割込みによる表示をしなくても、100HZ以上の信号がたまに抜けることがある。
※ノイズが入力されるとミスカウントをしてしまう。
※インジェクション、ATソレノイド等の誘導負荷があるため、ノイズが避けられない
※#device HIGH_INTS=TRUEを宣言して高位割込みを使用するとプログラムメモリ大となる
※各計測パルスの割込み周期が偶発的に一致する。
※移動平均を使用しないほうがよい。
回転数−>高回転で波形が低くなる
インジェクション−>デューティー制御のためあまり使用しないほうがよいかな
※ABS動作、トラクションコントール、冬場のコールドスタート時にノイズが入ってくる場合が ある<BR>
※ABS動作の時の速度波形をパルス抜けとしないようにする必要がある。
※凹凸路面走行での波形処理を考慮する必要がある
※急ブレーキの減速比率を考慮する必要がある。(パルス抜けと処理されないように)
※シフトアップ、シフトダウン時の増減率を考慮する必要がある(パルス抜けと処理されない
ように)<BR>
※速度と回転数はPICの内部クロックを引き上げると低速・低回転でオーバーフローする
別の方法あるんですが、BootLoaderからめるとフリーズするので・・・・<BR>
※CCP UPエッジトリガとDPWNエッジトリガどちらか一方のみで使用できるのは速度と回転数
※インジェクシヨンはCCP UPエッジトリガとDPWNエッジトリガを使用する必要がある。
(デューティー制御のため)
※タイマーカウンタ割込みによる回転数計測は不安定
※エアコン動作するとノイズが混入する場合がある。
※パーキング停止状態でノイズ入ったら、ノイズと判断する(ATの状態監視)
※パルスとりこぼしは全てオリジナルパルス波形時間の2倍前後となる
※パルス時間を比較するよりも、表示対象に変換してから比較したほうがよい
インジェクション:パルス時間小=負荷小とは限らない(開弁率の関係より)
※回転数を基準として考える必要がある
プログラムソース(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); //グローバル割込み許可
・
・
・
・
・
}
割込みにて計測しますのでソースはこのようになります。
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_割り込みCCP1_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_
#int_ccp1
void ccp1_isr()
{
rpm_longidle=0;
rpm_ini=rpm_ini+1;
intrup_n1=intrup_n2;
intrup_n2=CCP_1;//get_timer3()は不正確になる;
rise3 = intrup_n1; //立上りの時間
fall3 = intrup_n2; //立下りの時間
if (fall3 > rise3)
pulse_rpm = fall3 - rise3; //パルス幅=時間差
else
pulse_rpm = (0xffff - rise3 ) + fall3;
if(pulse_rpm!=0)
dpulse_rpm=((float)pulse_rpm)/2;
if( rpm_ini>=50)//初期カウントエラー防止のため
{
if(AN_H7>=4)//PARKING OFF
{
if((old_rpm*4)/dpulse_rpm>0.8&&(old_rpm*4)/dpulse_rpm<1.2)
{
dpulse_rpm=dpulse_rpm/4;//エラー対策
}
else if((old_rpm*3)/dpulse_rpm>0.8&&(old_rpm*3)/dpulse_rpm<1.2)
{
dpulse_rpm=dpulse_rpm/3;//エラー対策
}
else if((old_rpm*2)/dpulse_rpm>0.8&&(old_rpm*2)/dpulse_rpm<1.2)
{
dpulse_rpm=dpulse_rpm/2;//エラー対策
}
else
{
dpulse_rpm=dpulse_rpm;
}
}
else//PARKING
{
old_rpm=dpulse_rpm;
gear_rpm=(1000*60)/(dpulse_rpm/8*25/1000);
}
gear_rpm=(1000*60)/((dpulse_rpm)/8*25/1000);
old_rpm=dpulse_rpm;
}
else
{
old_rpm=dpulse_rpm;
gear_rpm=(1000*60)/(dpulse_rpm/8*25/1000);
}
if( rpm_ini>=50)
rpm_ini=200;
}
以上の手法は回転数が600RPMまでは計算できますが、それ以下はタイマーがオーバーフローしてしまい、鬼門となるところではないでしょうか。次に説明する手法はタイマー0を使用して超低回転のみ計測する手法です。
まず、タイマー0を5ms毎に割込みさせます。(10msでは精度がでません)
※内部40MHz動作の場合です
変数は
long rpm_pcount;
と設定します。
またmain()で0に初期化します
rpm_pcount=0;
#int_timer0
void isr0()
{
set_timer0(59285);//5ms
rpm_pcount++;
spd_pcount++;
if(number2!=0)
{
counter04 ++;
}
}
回転数パルスの間隔をタイマー0割込みによる5ms毎のカウンター値より計算します。分解能は5msですが、超低回転100RPMまで計測が可能になります。
#int_ccp1
void ccp1_isr()
{
・
・
・
・
if(rpm_pcount>=10)
gear_rpm=(1/(rpm_pcount*(0.005*2))*60;
rpm_pcount=0;
if( rpm_ini>=50)
rpm_ini=200;
・
・
・
・
}
make32を使用してタイマーオーバーフロー分を入れて速度1パルス分の時間計算もできるのですが、内部処理による時間遅れ等により結構速度がバラツキます。見た目はこちらの手法が安定して表示できます。