ケントエンジンの自作ECU化
sub_task(気筒に関係ないエンジンの全体的な処理を行うタスク)のステート0、8、16,24でMTUから回転数を入力します。ステート12ではスロットル用のADコンバータの変換を開始、ステート17で変換結果を得ています。周期割込ハンドラでシリアルコンソールに回転数とスロットル開度を出力します。エンジンエミュレータの擬似パルスの周波数とスロットル用のボリュームを変化させて動作をテストします。
以下、sub_taskの抜粋です。
・
・
// state 0
//
回転数入力
rev0 =
sil_reh_mem (TGR4A);
・
・
// state 8
// 回転数入力
rev8
= sil_reh_mem (TGR4A);
・
・
// state 12
// AD0
A:スロットル変換開始
sil_wrb_mem(ADCSR0,0x39);
・
・
//
state 16
// 回転数入力
rev16 =
sil_reh_mem (TGR4A);
・
・
// state
17
// スロットル開度の加速度計算のため前の値を覚えておく
thr_old = thr_new;
//thr_new = sil_reh_mem(ADDRA0);
// ADは右に6BITシフトする
thr_new =
((sil_reh_mem(ADDRA0) >> 6) & 0x03ff);
・
・
// state
24
// 回転数入力
rev24 =
sil_reh_mem (TGR4A);
//
rev[0,8,16,24]はクランク軸1回に換算で16分割のうちの
//
4つのサンプルである。
//
MTU4のクロック周期はT=28.64MHz/16=558.6nSEC
//
rpm=1/(rev*16*T*4)*60
//
これを回転数に変換するのは26852846/revの4つの加算
rev =
26852846/(rev0 + rev8 + rev16 + rev24);
以下、シリアルコンソールの出力結果です。回転数は200〜8500rpmくらい、スロットル開度は1〜1023までアナログ値として変換できています。
REV=8568 THR=1
REV=8612
THR=134
REV=8617
THR=320
REV=8620
THR=518
REV=8620
THR=733
REV=8617
THR=910
REV=8617
THR=1023
REV=8651
THR=1023
REV=8329
THR=1023
REV=3974
THR=1023
REV=1820
THR=1023
REV=1309
THR=1023
REV=920
THR=1023
REV=807
THR=1023
REV=669
THR=1023
REV=496
THR=1023
1月21日
マップの4点補完について考察します。燃料の噴射量と進角値はマップから基本値を得ますが通常は回転数、スロットル開度ともマップの格子点から外れています。この時は近傍の4点から補完をする必要があります。下図でa、b、c、dをマップの格子点とし、例としてスロットル開度が7%、回転数1700回転の時のe点の値を補完して計算してみます。
簡単にするため回転数は1000、1500、2000、2500のみ、スロットル開度は0、3、5、10%のみの噴射量の4x4のマップを作ります。
// 噴射量マップ#include
<stdio.h>
/*
噴射量マップ
*/
/*
1000,
1500, 2000, 2500
回転数 */
/*
index
0 1
2
3 index */
int
inj_val[4][4]={{ 10, 20, 30,
40}, /* 0% 0 */
{ 20,
30, 40, 50}, /* 3%
1 */
{ 35, 45,
55, 65}, /* 5% 2
*/
{
40, 50, 60, 70}};/* 10%
3 */
/********************************************/
/*
回転数、スロットル開度から4点補完をする */
/*
*/
/*
get_ave:
*/
/********************************************/
int
get_ave(int rev, int thr)
{
int
rev_index;
int
rev_diff,
rev_l_diff, rev_h_diff;
int
thr_index;
int
thr_diff, thr_l_diff,
thr_h_diff;
int a, b,
c, d;
int e, f, g;
/* 入力回転数からインデックスと差分を計算します */
if ((rev >= 1000) && (rev <
1500)) {
rev_index =
0;
rev_diff = 1500 -
1000;
rev_l_diff = rev -
1000;
rev_h_diff= 1500 -
rev;
}
else if ((rev >= 1500) && (rev
< 2000)) {
rev_index =
1;
rev_diff = 2000 -
1500;
rev_l_diff = rev -
1500;
rev_h_diff = 2000 -
rev;
}
else if ((rev >= 2000) && (rev
<= 2500)) {
rev_index = 2;
rev_diff = 2500 - 2000;
rev_l_diff = rev - 2000;
rev_h_diff = 2500 - rev;
}
/* 入力スロットル開度からインデックスと差分を計算します */
if ((thr >= 0) && (thr < 3))
{
thr_index = 0;
thr_diff = 3 - 0;
thr_l_diff = thr - 0;
thr_h_diff = 3 - thr;
}
else if ((thr >= 3) && (thr < 5)) {
thr_index = 1;
thr_diff = 5 - 3;
thr_l_diff = thr - 3;
thr_h_diff = 5 - thr;
}
else if ((thr >= 5) && (thr <= 10)) {
thr_index = 2;
thr_diff = 10 - 5;
thr_l_diff = thr - 5;
thr_h_diff = 10 - thr;
}
/* 得られた低高インデックスより4点の格子点の噴射量を得ます */
a = inj_val[thr_index + 1][rev_index ];
b = inj_val[thr_index + 1][rev_index + 1];
c = inj_val[thr_index ][rev_index ];
d =
inj_val[thr_index ][rev_index +
1];
/* ab間の回転数の補完値fを得ます */
f = (rev_h_diff*a + rev_l_diff*b)/rev_diff;
/* cd間の回転数の補完値gを得ます */
g =
(rev_h_diff*c + rev_l_diff*d)/rev_diff;
/* 上記のfとgからスロットル開度の補完値eを計算します */
e = (thr_l_diff*f +
thr_h_diff*g)/thr_diff;
return e;
}
void
main(void )
{
int rev,
thr;
rev = 1700;
thr = 7;
printf("ave = %d\n", get_ave(rev, thr));
rev = 1000;
thr = 5;
printf("ave = %d\n", get_ave(rev, thr));
rev = 1000;
thr = 0;
printf("ave = %d\n", get_ave(rev, thr));
rev = 2500;
thr = 10;
printf("ave = %d\n", get_ave(rev, thr));
}
以下、実行結果です。正しく動作しています。
# cc -o get_ave
get_ave.c
# ./get_ave
ave = 51
ave = 35
ave = 10
ave = 70
_sw:
mov.l r14,@-r15
add #-8,r15
mov r15,r14
mov.l r4,@r14
mov.l @r14,r1
mov #0,r2
mov #3,r3
sub r2,r1
cmp/hi r3,r1
bt .L3
mova .L8,r0
add r1,r1
mov.w @(r0,r1),r1
add r0,r1
jmp @r1 <-レジスタの間接ジャンプ命令になって、直接処理へ飛んでいる
nop
.align 2
.align 2
.L8:
.word .L4-.L8
.word .L5-.L8
.word .L6-.L8
.word .L7-.L8
.align 2
.L4:
mov #0,r1 <-case 0の部分
mov.l r1,@(4,r14)
bra .L3
nop
.align 2
.L5:
mov #10,r1 <-case 1の部分
mov.l r1,@(4,r14)
bra .L3
nop
・
・