燃料残量、冷却水温度、燃料噴射量などの計測回路

燃料の残量、冷却水の温度、バッテリー電圧、および燃料の噴射量を計測します。

燃料の噴射量は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;
}

fuel-temp.c