燃料の残量、冷却水の温度、バッテリー電圧、および燃料の噴射量を計測します。
燃料の噴射量はECUから信号を検出し算出しています。
コンパイラはCCS Cを使用しています。
#include <16f876.h> #include "FsID.h" #fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP #device ADC=10, *=16 // A/D変換 10ビットモード, 16bitポインタ指定 #use delay( Clock = 20000000 ) // クロック周波数指定 #use i2c( slave, SDA=PIN_C4, SCL=PIN_C3, ADDRESS=ADD_FUEL, FAST, FORCE_HW ) #use fast_io( A ) #use fast_io( B ) #use fast_io( C ) // マクロ定義 ************************************************************** #define CH_FUEL 0 // 燃料残量 入力チャンネル #define CH_WATERTEMP 1 // 水温 〃 #define CH_VOLT 4 // 電圧 〃 #define SWCH01 PIN_B1 #define SWCH02 PIN_B2 #define LED_BLUE PIN_B6 // LED - Blue #define LED_RED PIN_B7 // LED - Red // プロトタイプ宣言 ******************************************************** long FuelGauge(); long Thermomeeter(); long Voltmeter(); long AD_avr( int ); // グローバル変数宣言 ****************************************************** long Fuel; // 燃料残量[x10L] long Volt; // 電源電圧[x100V] signed long WaterTemp; // 冷却水温度[] long InjOnce; // 瞬間燃料噴射時間[x1.6usec] int32 Injection; // 総燃料噴射時間[x1.6usec] // ------------------- int32 TestInjection; int32 TestInjCount; // ------------------- int InjUpp; const float InjCon = 0.3512900; // 単位時間[1.6usec]の燃料噴射量[x10uL] // (無効噴射 1.00msec) // ------------------------------------------------- #include "i2c.h" // I2C送受信処理 #include "ad.h" // A/D // ===================================================================== // SSP割り込み処理 #int_ssp void ssp_interupt() { if( i2c_poll() ) { // 受信 int Receive; Receive = i2c_read(); } else { // 送信 int32 Work; I2cSlaveSend16( Fuel ); I2cSlaveSend16( ( long )WaterTemp ); I2cSlaveSend16( Volt ); I2cSlaveSend16( ( long )( InjCon * 10.0 * InjOnce ) ); // [usec] -> [x100uL] Work = ( float )Injection * InjCon; // [usec] -> [x10uL] I2cSlaveSend16( ( long )( Work >> 16 ) ); // 上位16ビット I2cSlaveSend16( ( long )Work ); // 下位16ビット I2cSlaveSend16( ( long )( TestInjection >> 16 ) ); // 上位16ビット I2cSlaveSend16( ( long )TestInjection ); // 下位16ビット I2cSlaveSend16( ( long )( TestInjCount >> 16 ) ); // 上位16ビット I2cSlaveSend16( ( long )TestInjCount ); // 下位16ビット } } // ===================================================================== // タイマ1割り込み処理 【フューエルカット検出】 #int_timer1 void isr1() { if( InjUpp >= 2 ) { InjOnce = 0; InjUpp = 0xFF; } else { InjUpp++; } } // ===================================================================== // CCP1割り込み処理 【燃料噴射開始 確認】 #int_ccp1 void ccp1_isr() { // カウンターをクリア InjUpp = 0; } // ===================================================================== // CCP2割り込み処理 【燃料噴射時間 計測】 #int_ccp2 void ccp_isr() { if( InjUpp != 0xFF ) { // 瞬間噴射時間 (計測範囲 : 0 - 65535[x1.6usec]) InjOnce = ( InjUpp * 0x10000 + CCP_2 ) - CCP_1; // 無効噴射時間を考慮しない噴射時間 TestInjection += InjOnce; // 無効噴射時間を差し引く (1.00[msec] = 1.6[usec] x 625) InjOnce -= 625; // 総噴射時間 (計測範囲 : 0 - 4294.967265[x1.6sec]) Injection += InjOnce; // 噴射回数カウント TestInjCount++; } else { // フューエルカット後、噴射開始を確認せずに // 噴射時間の計測処理に入っている。エラー処理が必要 } } /* ===================================================================== メイン関数 ===================================================================== */ void main() { /* ------------------------------------------------------ A0:'Fuel' (An_in) A1:'WaterTemp' (An_in) A5:'Volt' (An_in) B1:Switch B2:Switch B6:LED_Blue B7:LED_Red C1:'Injection' Pulse Low Input(CCP2) C2:'Injection' Pulse High Input(CCP1) C3:I2C_SCL(in) C4:I2C_SDA(in) -------------------------------------------------------*/ set_tris_a( 0b00100011 ); set_tris_b( 0b00000110 ); set_tris_c( 0b00011110 ); output_a( 0x00 ); output_b( 0x00 ); output_c( 0x00 ); setup_adc_ports( A_ANALOG ); // Setup A/D Converter setup_adc( adc_clock_div_32 ); // Fosc/32 最高速度 // ------------------------------------------------------ setup_ccp1( CCP_CAPTURE_FE ); // CCP1設定(立ち下がりキャプチャ) setup_ccp2( CCP_CAPTURE_RE ); // CCP2設定(立ち上がり ) setup_timer_1( T1_INTERNAL | T1_DIV_BY_8 ); // タイマ1設定(1.6usec) enable_interrupts( INT_CCP1 ); // CCP1 enable_interrupts( INT_CCP2 ); // CCP2 enable_interrupts( INT_TIMER1 ); // タイマ1 enable_interrupts( GLOBAL ); // グローバル割り込み許可 // 入力信号が安定するまで待つ ----- output_high( LED_RED ); output_high( LED_BLUE ); delay_ms( 1000 ); output_low( LED_RED ); output_low( LED_BLUE ); // -------------------------------- Injection = 0; TestInjection = TestInjCount = 0; // SSP割り込み許可。外部との通信を開始する enable_interrupts( INT_SSP ); while( 1 ) { // 電圧(水温の補正のため 先に測定する) Volt = Voltmeter(); // 燃料残量 Fuel = FuelGauge(); // 水温 WaterTemp = Thermomeeter(); delay_ms( 90 ); } } // ===================================================================== // 燃料残量 測定 long FuelGauge() { long Result, Data; Data = AD_avr(CH_FUEL); if( Data == 0xFFFF ) { // エラー(コード:0x0001) return 0x0001; } // 燃料残量[x10L] = 450[x10L] - (AD / 2.5744 + 53.970) Result = 396 - ( long )( Data / 2.574 ); if( Result > 350 ) { // 残油35L 以上は'満タン'と判定 return 0xFFFF; } return Result; } // ===================================================================== // 水温 測定 signed long Thermomeeter() { const float Correction = 1370.0; // 電圧化による補正係数(平均電圧) const signed long TempAver = -425; // 水温平均値 補正値 const signed long TempCold = -250; // 低温警告値 signed long Result; long Data; Data = AD_avr(CH_WATERTEMP); if( Data == 0xFFFF ) { // エラー(コード:0x7FFF) return 0x7FFF; } Data ^= 0x03FF; // 測定値反転(0 <-> 0x03FF) // 水温[] = AD * (電圧[V] / 平均電圧[V]) Result = Data * ( Volt / Correction ); // 水温平均値を0に補正 Result += TempAver; // 低温警告 if( Result < TempCold ) { output_high( LED_BLUE ); } else { output_low( LED_BLUE ); } return Result; } // ===================================================================== // 電圧 測定 long Voltmeter() { long Data; Data = AD_avr( CH_VOLT ); if( Data == 0xFFFF ) { // エラー(コード:0x0001) return 0x0001; } // 電圧[x100V] = AD x 1.5 return Data * 1.5; } // ===================================================================== // アナログ入力 (平均値 出力) long AD_avr( int Channel ) { int i; long Data; long Result = 0; // 64回の平均値を測定値とする for( i = 0; i < 64; i++ ) { Data = ADConv10( Channel ); // アナログ入力値オーバー if( Data == 0x03FF ) { output_high( LED_RED ); // エラー(コード:0xFFFF) return 0xFFFF; } Result += Data; } return Result / 64; }