中央処理回路

各構成部品で計測した値を受信し、燃費などの演算を行います。そして演算結果の液晶への表示を制御します。

演算結果は液晶に表示する以外にも、外部に接続されたパソコンへ送信したり、搭載するメモリへ保存することも可能です。

プログラム

コンパイラはCCS Cを使用しています。

#include <16f876.h>
#include "FsID.h"

#fuses HS, NOWDT, NOPROTECT, PUT, NOBROWNOUT, NOLVP

#device ADC=8 *=16                // 16bitポインタ指定
#use delay( Clock = 20000000 )    // クロック周波数指定

#use rs232( BAUD = 9600, XMIT=PIN_C6, RCV=PIN_C7 )            // USART
#use i2c( master, SDA=PIN_C4, SCL=PIN_C3, FAST, FORCE_HW )    // I2C

#use fast_io( A )
#use fast_io( B )
#use fast_io( C )

// マクロ定義 **************************************************************
#define PIN_SWITCH_SELECT   PIN_A4
#define PIN_SWITCH_RESET    PIN_B1
#define PIN_LED             PIN_C5

#define PIN_BEEP            PIN_A5    // BEEP音
#define PIN_DISCHARGE       PIN_A0    // 放電開始出力
#define ADD_DATAROM         0xA0      // EEPROM 使用開始アドレス

#define NOW    0    // 今回の記録分のデータ
#define REC    1    // 過去の記録分

// プロトタイプ宣言 ********************************************************
long FuelCost( int32 Injection );
long FuelEff( int32 Distance, int32 Injection );
long SpdAvr( int32 Distance, int32 Timer );
long Slowness( int32 Distance, int32 Timer );
float FuelInjections( int32 Injection );

void ReceiveMeasured();
void i2c_Receive( int, long *lptr, int );

void USART_Send();
void USART_SendFromEEPROM();

void ReadDataFromEEPROM();
void write_eeprom32( int address, int32 Data );
int32 read_eeprom32( int address );

void RecordEEPROM( long );

void SelectDisp();
void ResetData();

void Melodious( int );
void Beep();
void Clock();

// グローバル変数宣言 ******************************************************
short Flag_WriteEeprom = FALSE;  // 外付EEPROM記録フラグ
short Flag_SendUSART = FALSE;    // 内部データ連続転送フラグ
short Flag_Beep = FALSE;         // BEEP音発生フラグ

int SelectedDisp = 0;    // 液晶 表示モード選択
int MelodiousWait = 0;   // 効果音発生器のウエイト

long Speed;              // 車速[x0.1km/h]
long Revolution;         // エンジン回転数[rpm]
int32 Distance[ 2 ];     // 走行距離[m]
signed long Accel;       // 加速度[mG]

signed long WaterTemp;   // 冷却水温度[]
long Volt;               // 電源電圧[x100V]

long Fuel;               // 燃料残量[x10L]
long InjOnce;            // 瞬間燃料噴射量[x100uL]
int32 Injection[ 2 ];    // 総燃料噴射量[x10uL]

int32 TestInjection[ 2 ];
int32 TestInjCount[ 2 ];

int32 Timer[ 2 ];        // 走行時間[sec]

struct
{
    signed long RoomTemp;  // 内気温[x10℃]
    signed long AirTemp;   // 外気温[x10℃]
    long Humidity;         // 湿度[x10%]
} Env;

const int FuelPrice = 110; // 燃料単価[Yen/L]


// -------------------------------------------------
#include "lcd_lib.h"        // 液晶表示ライブラリ
#include "FsLcd.h"          // LCD表示
#include "FsExtEeprom.h"    // 外付けEEPROM
#include "i2c.h"            // I2C


// =====================================================================
// USART受信 割込み処理
#int_rda
void isr_rcv()
{
    switch( getc() )
    {
        // EEPROMデータ転送
        case 'D':
            USART_SendFromEEPROM();
            break;

        // 記録データ リアルタイム転送
        case 'R':
            Flag_SendUSART = TRUE;
            break;

        default:
            break;
    }
}

// =====================================================================
// タイマ1 割込み処理
#int_timer1
void isr1()
{
    // タイマ再設定(100msec)
    set_timer1( 0x0BDC );

    // 時間計測
    Clock();

    // スレーブからデータ受信
    ReceiveMeasured();

    if( Flag_WriteEeprom )
    {
        // 外付EEPROMへ記録
        RecordEEPROM( Volt );
    }

    if( Flag_SendUSART )
    {
        // USARTでデータ送信
        USART_Send();
    }

    if( Flag_Beep )
    {
        // BEEP音発生
        Beep();
    }

//    MelodiousWait++;
}

// =====================================================================
// 外部INT 割り込み << 電源断メモリ >>
#int_ext
void ext_isr()
{
    int address = ADD_DATAROM;

//    output_a(0x00);    // 消費電力を抑えるため
//    output_b(0x00);    // すべての出力をLowレベルとする
//    output_c(0x00);

    // 内蔵EEPROM書き込み処理
    //  256バイトまでは保存可能(実験結果より)
    write_eeprom32( address, Timer[ NOW ] + Timer[ REC ] );
    address += 4;

    write_eeprom32( address, Distance[ NOW ] + Distance[ REC ] );
    address += 4;

    write_eeprom32( address, Injection[ NOW ] + Injection[ REC ] );
    address += 4;

    write_eeprom32( address, TestInjection[ NOW ] );
    address += 4;

    write_eeprom32( address, TestInjCount[ NOW ] );
    address += 4;


    output_high( PIN_LED );

    // 放電開始
    output_high( PIN_DISCHARGE );

    // 3秒待機
    delay_ms( 3000 );

    // --------------------------------------------------
    // 電源が切断されなかったなら復帰する

    output_low( PIN_LED );

    // 放電停止
    output_low( PIN_DISCHARGE );
}

/* =====================================================================
    メイン関数
===================================================================== */
void main()
{
    /* ------------------------------------------------------
        A0:放電開始信号(out)
        A4:Switch(in)
        A5:Beep

        B0:電源断信号(Vdd_in)
        B1:Switch(in)
        B2-B7:LCD(out)

        C3:I2C_SCL(in)
        C4:I2C_SDA(in)
        C5:LED(out)
        C6:USART(out)
        C7:USART(in)
    -------------------------------------------------------*/
    set_tris_a( 0b00010000 );
    set_tris_b( 0b00000011 );
    set_tris_c( 0b10011000 );

    output_a( 0x00 );
    output_b( 0x00 );
    output_c( 0x00 );

    setup_adc_ports( NO_ANALOGS );    // AD_Converter - OFF
    setup_adc( ADC_OFF );
    // ------------------------------------------------------

    setup_timer_1( T1_INTERNAL | T1_DIV_BY_8 );    // タイマ1初期設定
    ext_int_edge( H_TO_L );                        // 外部INT(立ち下りエッジ)

    enable_interrupts( INT_TIMER1 );    // タイマ1
    enable_interrupts( INT_EXT );       // 外部INT
    enable_interrupts( INT_RDA );       // USART

    lcd_init();
    printf( lcd_data, "Waiting..." );

    // 入力信号が安定するまで待つ -----
    output_high( PIN_LED );
    delay_ms( 1000 );
    output_low( PIN_LED );
    // --------------------------------

    delay_ms( 50 );          // 他機器との競合を防止するための時間調整
//    Melodious( 4 );        // 音源デバイスに起音
    ReadDataFromEEPROM();    // EEPROMよりデータ読みみ

    Timer[ NOW ] = 0;             // 走行時間リセット
    set_timer1( 0x0BDC );         // タイマ1 初期値設定(100msec)
    enable_interrupts( GLOBAL );  // グローバル割り込み許可

    while( 1 )
    {
        DisplayLCD( SelectedDisp );

        // スイッチ入力処理
        if( !input( PIN_SWITCH_RESET ) )
        {
            ResetData();
        }

        if( !input( PIN_SWITCH_SELECT ) )
        {
            SelectDisp();
        }

        // オーバーヒート警告
        if( ( WaterTemp > 100 ) && ( InjOnce != 0 ) )
        {
            Flag_Beep = TRUE;
        }

//        if( Speed > 1200 )
//        {
//            // 車速オーバー警告音
//            Melodious( 2 );
//        }

        delay_ms( 100 );
    }
}

// =====================================================================
// スイッチ処理

void SelectDisp()
{
//    Flag_WriteEeprom = TRUE;    // EEPROM への書き込み開始

    SelectedDisp = ( SelectedDisp < 4 )? ++SelectedDisp : 0;

    lcd_clear();

    while( !input( PIN_SWITCH_SELECT ) )
    {
    }
}

void ResetData()
{
    Timer[ REC ] = 0;
    Distance[ REC ] = 0;
    Injection[ REC ] = 0;

    TestInjection[ REC ] = TestInjCount[ REC ] = 0;
}

// =====================================================================
// 効果音発生処理
void Melodious( int Select )
{
    if( MelodiousWait > 4 )    // Timer x 100msecごとに発生処理に移る
    {
        I2cMasterSend8( ADD_MELODIOUS, Select );
        MelodiousWait = 0;
    }
}

// =====================================================================
// BEEP音
void Beep()
{
    static int Count;

    switch( Count )
    {
        case 0:
            output_high( PIN_BEEP );
            break;

        case 1:
            output_low( PIN_BEEP );
            break;

        case 5:
            Flag_Beep = FALSE;
            Count = 0;
            return;

        default:
    }

    Count++;
}

// =====================================================================
// 時間計測
void Clock()
{
    static int Counter;

    // 誤差を補正するため 0.9sec -> 1.0sec とする
    if( ++Counter >= 9 )
    {
        Timer[ NOW ]++;
        Counter = 0;
    }
}

// =====================================================================
// 各種 計算処理関数群

// -----------------------------------------------------------------
// ガソリン代[Yen] =
//  単価[Yen/L] x 燃料消費量[x10L] / 10
long FuelCost( int32 Injection )
{
    return FuelPrice * FuelInjections( Injection ) / 10;
}

// -----------------------------------------------------------------
// 平均燃費[x100km/L] =
//  距離[m] / 燃料消費量[x10L]
long FuelEff( int32 Distance, int32 Injection )
{
    return ( float )Distance / FuelInjections( Injection );
}

// -----------------------------------------------------------------
// 平均速度[x10km/h] =
//  (距離[m] / 時間[s]) x 36[m/s -> x10km/h]
long SpdAvr( int32 Distance, int32 Timer )
{
    // Distanceは 1/1000 されたものを受信するので
    // *36 してもオーバーフローすることはない
    return Distance * 36 / Timer;
}

// -----------------------------------------------------------------
// スローネス[x100min/km] =
//  (1 / 速度[x10km/h]) x 60[h -> min] x 1000
long Slowness( int32 Distance, int32 Timer )
{
    return 60000 / SpdAvr( Distance, Timer );
}

// -----------------------------------------------------------------
// 燃料噴射量 単位変換 [x10uL] -> [x10L]
float FuelInjections( int32 Injection )
{
    return ( float )Injection / 1000000;
}

// =====================================================================
// 他機器からのデータ受信処理
void ReceiveMeasured()
{
    long ReceiveBuffer[ 10 ];

    // Fs_SpeedPulse
    i2c_Receive( ADD_SPEED, &ReceiveBuffer[ 0 ], 5 );

    Speed = ReceiveBuffer[ 0 ];
    Revolution = ReceiveBuffer[ 1 ];

    Distance[ NOW ] = ReceiveBuffer[ 2 ];
    Distance[ NOW ] = Distance[ NOW ] << 16 | ReceiveBuffer[ 3 ];

    Accel = ReceiveBuffer[ 4 ];

    // Fs_Fuel-Temp
    i2c_Receive( ADD_FUEL, &ReceiveBuffer[ 0 ], 10 );

    Fuel = ReceiveBuffer[ 0 ];
    WaterTemp = ReceiveBuffer[ 1 ];
    Volt = ReceiveBuffer[ 2 ];

    InjOnce = ReceiveBuffer[ 3 ];

    Injection[ NOW ]= ReceiveBuffer[ 4 ];
    Injection[ NOW ]= Injection[ NOW ] << 16 | ReceiveBuffer[ 5 ];

    TestInjection[ NOW ] = ReceiveBuffer[ 6 ];
    TestInjection[ NOW ] = TestInjection[ NOW ] << 16 | ReceiveBuffer[ 7 ];

    TestInjCount[ NOW ] = ReceiveBuffer[ 8 ];
    TestInjCount[ NOW ] = TestInjCount[ NOW ] << 16 | ReceiveBuffer[ 9 ];

    // Fs_environment
    i2c_Receive( ADD_ENVIRON, &ReceiveBuffer[ 0 ], 3 );

    Env.AirTemp    = ReceiveBuffer[ 0 ];
    Env.RoomTemp = ReceiveBuffer[ 1 ];
    Env.Humidity = ReceiveBuffer[ 2 ];

    // 記録データと加算 ------------------------
    TestInjection[ NOW ] += TestInjection[ REC ];
    TestInjCount[ NOW ] += TestInjCount[ REC ];
}

// -----------------------------------------------------------
// I2C受信処理(16bit 連続受信)
void i2c_Receive( int address, long *lptr, int size )
{
    int i;

    i2c_start();

    // アドレス指定(受信処理のため+1)
    i2c_write( address | 0x01 );

    for( i = 0; i < size - 1; i++, lptr++ )
    {
        *lptr = i2c_read();
        *lptr = *lptr << 8 | i2c_read();
    }

    *lptr = i2c_read( );

    // Get data with no ACK
    *lptr = *lptr << 8 | i2c_read( 0 );

    i2c_stop();
}

// =====================================================================
// USART 送信処理
void USART_Send()
{
     printf( "%4LX%4LX%4LX%4LX%4LX%4LX\r",
        Speed, Revolution, InjOnce, Fuel, WaterTemp, Volt );
}

// EEPROMから送信
void USART_SendFromEEPROM()
{
    long address;
    int i;

    for( i = 0, address = 0x0000; i < 32; i++, address++ )
    {
        printf( "%4LX", ReadExtEeprom( add_Eeprom, address ) );

        // PCの処理速度に合わせるためウエイトを置く
        delay_us( 10 );
    }
}

// =====================================================================
// 内蔵EEPROM 処理

void ReadDataFromEEPROM()
{
    int address = ADD_DATAROM;

    Timer[ REC ] = read_eeprom32( address );
    address += 4;

    Distance[ REC ] = read_eeprom32( address );
    address += 4;

    Injection[ REC ] = read_eeprom32( address );
    address += 4;

    TestInjection[ REC ] = read_eeprom32( address );
    address += 4;

    TestInjCoun[ REC ] = read_eeprom32( address );
    address += 4;
}

// 書き込み(4Byte)
void write_eeprom32( int address, int32 Data )
{
    write_eeprom( address++, ( int )(Data >> 24 ) );
    write_eeprom( address++, ( int )(Data >> 16 ) );
    write_eeprom( address++, ( int )(Data >> 8 ) );
    write_eeprom( address, ( int )Data );
}

// 読み込み(4Byte)
int32 read_eeprom32( int address )
{
    int32 Data;

    Data = read_eeprom( address++ );
    Data = Data << 8 | read_eeprom( address++ );
    Data = Data << 8 | read_eeprom( address++ );
    Data = Data << 8 | read_eeprom( address );

    return Data;
}

// =====================================================================
// 外付けEEPROMデータ転送 関数
void RecordEEPROM( long Data )
{
    static long address, MemoryBuffer[ 32 ];
    static int Count;

    // I2Cを通信にも使用しているため
    // バッファさせなければ、EEPROMへ書き込みできない
    MemoryBuffer[ Count++ ] = Data;

    // バッファオーバーならば、メモリ記録へ
    if( Count >= 32 )
    {
        WriteExtEeprom( add_Eeprom, address, &MemoryBuffer[ 0 ] );
        address += 64;
        Count = 0;
    }
}

central.c