各構成部品で計測した値を受信し、燃費などの演算を行います。そして演算結果の液晶への表示を制御します。
演算結果は液晶に表示する以外にも、外部に接続されたパソコンへ送信したり、搭載するメモリへ保存することも可能です。
コンパイラは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; } }