新しくタコメーターを作ることに。
とはいってもタコメーターなんてパルスとって表示すりゃいいだけなのでそんなに難しくはない・・・はず。
F1風にバーで4500RPMから10000RPMくらいまで出して、9000RPMくらいから点滅させりゃいいやとおとといくらいに
言われたので適当に考えてみた。ついでにバッテリーの電圧見れるようにとのことなのでそれも踏まえて取りあえず回路を描いてみる
とりあえず家にあったdsPIC30F4013を使うことに、あと同じく家にあった基板実装型のスイッチと、レギュレーターとトランジスタアレイx2を使って
LEDバーと7セグメントで光らせりゃいいやという単純仕様。
ということで近くのマルツに行ってさっそく高輝度LEDと7セグメントと、あと適当な水晶発振子を買ってきてみたはいいものの。
なぜか7セグメントはアノードコモンじゃなくてカソードコモンしか売ってなかったという・・・orzなぜだよ。
適当に基盤に実装してMPLABで書いたプログラムがこれ
► スポイラーを表示
//ヘッダファイルをインクルード
#include "p30f4013.h"
#include "timer.h"
#include "adc12.h"
#include "ports.h"
//コンフィギュレーション・ワードの設定
//クロック切り替え機能OFF、周波数は4倍で駆動
_FOSC(CSW_FSCM_OFF & XT_PLL4);
//ウォッチドックタイマをOFF
_FWDT(WDT_OFF);
//パワーオンリセットをONに、パワーオンリセットパルス幅64ms 外部クリア機能ON 2.0VでパワーOFF
_FBORPOR(PBOR_ON & PWRT_64 & MCLR_EN & BORV20 );
//コードプロテクトOFF
_FGS(CODE_PROT_OFF);
//コンフィグ設定を行う関数
void ConfigALL();
//********************************************************************
//タイマー45用設定
//タイマー45ON、ゲートタイマーモードOFF、クロックをシステムクロックの1/256に、内部クロックを使用
const unsigned int T45config = T4_ON & T4_GATE_OFF & T4_PS_1_256 & T4_32BIT_MODE_ON & T4_SOURCE_INT;
//割り込みモードOFF(ReadTimerにて数値を直接取得)
const unsigned int T45config2 = T5_INT_OFF;
//タイマーのカウントからエンジンの回転周期を逆算
const unsigned long MultiValue = 1000L * 64L * 60L;
//********************************************************************
//タイマー3用のコンフィグ // AD変換用
//タイマー3ON、ゲートタイマーモードOFF、クロックをシステムクロックの1/256に、内部クロックを使用
const unsigned int T3config = T3_ON & T3_GATE_OFF & T3_PS_1_256 & T3_SOURCE_INT;
//サンプルタイミング(適当)
const unsigned int SampleTime3 = 201;
//********************************************************************
//AD変換用のコンフィグ
//AD変換機をON、アイドルモードでは停止、12ビット符号なし整数で出力、タイマー3と同期、サンプルを自動化、手動サンプリングOFF
const unsigned int ADconfig1 = ADC_MODULE_ON & ADC_IDLE_STOP & ADC_FORMAT_INTG & ADC_CLK_TMR
& ADC_AUTO_SAMPLING_ON & ADC_SAMP_OFF;
//VDD-VSSを基準電圧に、スキャンをOFFに、割り込み相互間サンプル数1:1、バッファモードOFF、代替入力サンプルモードOFF
const unsigned int ADconfig2 = ADC_VREF_AVDD_AVSS & ADC_SCAN_OFF & ADC_SAMPLES_PER_INT_1
& ADC_ALT_BUF_OFF & ADC_ALT_INPUT_OFF;
//自動サンプル時間ビット1、クロックソースはシステムを流用、変換クロックは8Tcyで
const unsigned int ADconfig3 = ADC_SAMPLE_TIME_1 & ADC_CONV_CLK_SYSTEM & ADC_CONV_CLK_8Tcy;
//AN0をAD変換
const unsigned int ADconfigPORT = ENABLE_AN0_ANA;
//スキャンはしない
const unsigned int ADconfigSCAN = 0;
//正入力と負入力のインプット先(AN0の入力電圧と、NVREFの入力電圧の差を、基準電圧と比較)
#define ADconfigCH0 ADC_CH0_POS_SAMPLEA_AN0 & ADC_CH0_NEG_SAMPLEA_NVREF
static const int ADCFrequency = 4096;
//********************************************************************
//外部割込みピンのコンフィグ
const unsigned int Int1Config = RISING_EDGE_INT & EXT_INT_ENABLE & EXT_INT_PRI_6;
const unsigned int Int2Config = RISING_EDGE_INT & EXT_INT_ENABLE & EXT_INT_PRI_6;
//********************************************************************
int main()
{
ConfigALL();
while(1)
{
}
}
void ConfigALL()
{
//-------------------------------------------------------------------
//ポート初期設定
TRISB = 0x1; //ポートBは1ビット目をAD変換用入力
TRISF = 0x0;
TRISD = 0x300;
//-------------------------------------------------------------------
//AD変換モジュールの初期設定
OpenADC12(ADconfig1,ADconfig2,ADconfig3,ADconfigPORT,ADconfigSCAN);
SetChanADC12(ADconfigCH0); //チャンネル設定
ConfigIntADC12(ADC_INT_ENABLE & ADC_INT_PRI_5); //AD変換機からの割り込みを許可
//===================================================================
//タイマー1の設定 タイマー割り込みを許可しない
OpenTimer45(T45config, 0xFFFF);
ConfigIntTimer1(T45config2);
//-------------------------------------------------------------------
//タイマー3の初期設定
OpenTimer3(T3config,SampleTime3);
//-------------------------------------------------------------------
ConfigINT1(Int1Config);
ConfigINT2(Int2Config);
}
static unsigned int SegmentOn = 0;
static unsigned int LEDBarChan = 0;
void DisplaySegment( unsigned long, unsigned unt );
void HiddenSegment();
unsigned int Segment( unsigned int , int );
static unsigned long SRPM = 0;
static unsigned int RPMReset = 0;
unsigned long ConvertTimerValue( unsigned long );
void ShowLEDBar( unsigned long );
//タイマー3からの割り込みでAD変換後、AD変換終了時に呼ばれる関数。
void __attribute__((__interrupt__,__shadow__,auto_psv)) _ADCInterrupt(void)
{
//割り込みフラグクリア
IFS0bits.ADIF = 0;
unsigned int value = ReadADC12(0);
static unsigned int segmentChan = 0;
if( RPMReset == 1000 )
{
SRPM = 0;
}
if( SegmentOn > 0 )
{
--SegmentOn;
DisplaySegment( value, segmentChan );
}
else
{
HiddenSegment();
}
++segmentChan;
++RPMReset;
segmentChan %= 3;
LEDBarChan = 1-LEDBarChan;
static unsigned int wait9000 = 0;
++wait9000;
if( SRPM > 8500 && wait9000 > 35 )
ShowLEDBar(0);
else
ShowLEDBar( SRPM );
if( wait9000 == 70 )
wait9000 = 0;
}
//割り込みピン1RPMインプットが入るたびに呼ばれる関数
void __attribute__((interrupt,auto_psv)) _INT1Interrupt(void)
{
//割り込みフラグクリア
IFS1bits.INT1IF=0;
RPMReset = 0;
unsigned long TimerValue = ReadTimer45();
WriteTimer45( 0L );
SRPM = ConvertTimerValue( TimerValue );
}
//割り込みピン2電圧表示スイッチのONタイミングで呼ばれる関数
void __attribute__((interrupt,auto_psv)) _INT2Interrupt(void)
{
//割り込みフラグクリア
IFS1bits.INT2IF=0;
SegmentOn = 1000;
}
unsigned long ConvertTimerValue( unsigned long TimerValue )
{
return MultiValue / TimerValue;
}
void ShowLEDBar( unsigned long RPM )
{
unsigned int d = PORTD;
if( RPM > 4500 )
RPM -= 4500;
else
RPM = 0;
if( LEDBarChan == 1 )
{
if( RPM > 2500 )
RPM -= 2500;
else
RPM = 0;
d &= ~(0x2);
d |= 0x1;
}
else
{
d &= ~(0x1);
d |= 0x2;
}
PORTD = d;
unsigned int f = 0;
if( RPM > 0 ) f |= 0x1;
if( RPM > 500 ) f |= 0x2;
if( RPM > 1000 ) f |= 0x10;
if( RPM > 1500 ) f |= 0x20;
if( RPM > 2000 ) f |= 0x4;
if( RPM > 2500 ) f |= 0x8;
PORTF = f;
}
void DisplaySegment( unsigned long value , unsigned int chan )
{
value = value * 160 / ADCFrequency;
if( chan == 0 )
{
value /= 100;
unsigned int b = PORTB;
b &= 0x1;
b |= 0x800 | Segment( (int)value, 0 );
PORTB = b;
}
else if( chan == 1 )
{
value -= ( value / 100 ) * 100;
value /= 10;
unsigned int b = PORTB;
b &= 0x1;
b |= 0x1000 | Segment( (int)value, 1 );
PORTB = b;
}
else
{
value -= ( value / 10 ) * 10;
unsigned int b = PORTB;
b &= 0x1;
b |= 0x400 | Segment( (int)value, 0 );
PORTB = b;
}
}
void HiddenSegment()
{
unsigned int b = PORTB;
b &= ~(0x1FE);
PORTB = b;
}
static const unsigned int LT = 0x100;
static const unsigned int RT = 0x10;
static const unsigned int TT = 0x80;
static const unsigned int C = 0x40;
static const unsigned int LB = 0x20;
static const unsigned int RB = 0x2;
static const unsigned int BB = 0x4;
static const unsigned int DP = 0x8;
unsigned int Segment( unsigned int value, int dp )
{
unsigned int rvalue = 0;
switch( value )
{
case 0:
rvalue = LT | RT | TT | LB | RB | BB;
break;
case 1:
rvalue = RT | RB;
break;
case 2:
rvalue = RT | TT | LB | BB | C;
break;
case 3:
rvalue = RT | TT | RB | BB | C;
break;
case 4:
rvalue = LT | RT | RB | C;
break;
case 5:
rvalue = LT | TT | RB | BB | C;
break;
case 6:
rvalue = LT | TT | LB | RB | BB | C;
break;
case 7:
rvalue = LT | RT | TT | RB;
break;
case 8:
rvalue = LT | RT | TT | LB | RB | BB | C;
break;
case 9:
rvalue = LT | RT | TT | RB | BB | C;
break;
}
if( dp==1 ) rvalue |= DP;
return rvalue;
}
とりあえずコンパイルして書き込んでMOTECからパルスののテストアウトプットを出す。
・・・うーん光る。拍子抜けなくらいに光る。
バッテリー電圧(12V)を測る為の抵抗の分圧(大体1MΩ:22MΩ)が超適当だったため、電圧計は大して精度が出てなかったものの、それも適当に修正
まぁデバッグも大したことなく動いてよかった。(と思ってたんですよ。このときは・・・)
その辺に転がってたカーボン板を切って削って現物合わせで適当にマウントした状態がこれ
タイラップで止めてるのは取りあえずつけばいいからということで・・・(一応後で何とかします)
そしていよいよエンジンを回す・・・!
・・・
・・・
表示がおかしい。
なぜだ。
考えて考えて5時間。取りあえずいくつか修正したものの、どう考えても回転数がおかしい。
いよいよ意味不明なので先輩に聞いたところ
「あ、2ストローク用のメータの出力にECU設定したから倍パルス出てるわ・・・」
とかいう悪魔の一言が。。。
僕の5時間を返して・・・orz