
おはようございます。
ケロタン少佐デありま~す・・・(^_^;)ヾ
こんかいは・・・
TREC
や
PIVOT
や
BRITZ
の様なものを
自作にて考えてみまちた。
回路図は・・・
アクセル開度テーブルは・・・
1.ノーマル
2.フラット
3.スポーツ
4.エコ
5.バック
の5種類から・・・
【システム用件】
・運転席足元のアクセルペダル上に設置してある
アクセル開度センサーに割り込み配線
・開度センサーは、ボリューム抵抗によるアナログデータと推測。
・おそらく、0V~5Vのアナログデータである。
・角度検出のデジタルデータであった場合は、再度修正予定
こっちの方がデジタルなので楽かな…(例)舵角センサー
【制御フロー】
・アクセル開度に応じた電圧値のアナログデータを取得
↓
・マイコン内にて、デジタルデータへ変換
↓
・各モードテーブルに沿ったデジタルデータへ変更
↓
・専用IC用にデータをデジタル変換
↓
・専用ICへデータ送信
↓
・デジタルデータをアナログ電圧データに変換
↓
・アクセル開度センサーへ出力
↓
・最初へ戻る(無限ループ)
【プログラム】
/*************************************************************************************************
AVR Studio 4 C言語用 Ver1.1(ATmega88用) 2008.11.28
アクセル開度コントロール プログラム (A・O・C)
Program Name : accel-open-control-ver1.1.c
Version : 1.1
Language : AVR C言語 (WinAVR)
Device : ATmega88
Clock : 1MHz(内蔵RC発振)
Author : ケロタン少佐
**************************************************************************************************
I/O
(PCINT14/RESET) PC6 | 1****28| PC5 (ADC5/SCL/PCINT13)
(PCINT16/RXD) PD0 | 2****27| PC4 (ADC4/SDA/PCINT12)
(PCINT17/TXD) PD1 | 3****26| PC3 (ADC3/PCINT11)
(PCINT18/INT0) PD2 | 4****25| PC2 (ADC2/PCINT10)
(PCINT19/OC2B/INT1) PD3 | 5****24| PC1 (ADC1/PCINT9)
(PCINT20/XCK/T0) PD4 | 6****23| PC0 (ADC0/PCINT8)
VCC | 7****22| GND
GND | 8****21| AREF
(PCINT6/XTAL1/TOSC1) PB6 | 9****20| AVCC
(PCINT7/XTAL2/TOSC2) PB7 |10****19| PB5 (SCK/PCINT5)
(PCINT21/OC0B/T1) PD5 |11****18| PB4 (MISO/PCINT4)
(PCINT22/OC0A/AIN0) PD6 |12****17| PB3 (MOSI/OC2A/PCINT3)
(PCINT23/AIN1) PD7 |13****16| PB2 (SS/OC1B/PCINT2)
(PCINT0/CLKO/ICP1) PB0 |14****15| PB1 (OC1A/PCINT1)
PORTB7 ; 出力 ; H ; def
PORTB6 ; 出力 ; H ; def
PORTB5 ; 出力 ; H ; def
PORTB4 ; 出力 ; H ; def
PORTB3 ; 出力 ; H ; def
PORTB2 ; 出力 ; H ; +信号 ; dat_ch ; データ送信チャンネル
PORTB1 ; 出力 ; H ; +信号 ; cs_ch
PORTB0 ; 出力 ; H ; +信号 ; clk_ch
PORTC6 ; 入力 ; L ; -信号 ; RESET
PORTC5 ; 出力 ; H ; def
PORTC4 ; 出力 ; H ; def
PORTC3 ; 入力 ; L ; -信号 ; menu_sw
PORTC2 ; 入力 ; L ; -信号 ; select_sw
PORTC1 ; 入力 ; L ; -信号 ; back_s
PORTC0 ; 入力 ; ADC0 ; アクセル開度信号入力 ; accel_s
PORTD7 ; 出力 ; H ; seg_a
PORTD6 ; 出力 ; H ; seg_b
PORTD5 ; 出力 ; H ; seg_c
PORTD4 ; 出力 ; H ; seg_d
PORTD3 ; 出力 ; H ; seg_e
PORTD2 ; 出力 ; H ; seg_f
PORTD1 ; 出力 ; H ; seg_g
PORTD0 ; 出力 ; H ; status_LED
**************************************************************************************************
動作仕様
1.アクセル開度データを取得して変換し、モードテーブルを参照して出力する
2.任意変換モードは、ノーマル(N:0)、フラット(F:1)、スポーツ(S:2)、エコ(E:3)の4モードとする
3.後進はバックモードとする
4.設定値は、EEPROMに記憶させる
5.アクセル開度は、7セグにより逐次%表示(10桁のみ)する
6.フローはA/D変換→データ変換→D/A変換とする
7.D/A変換には、専用IC(MCP4822)を使用する
STATUS LEDの動作
点滅1・・・(2Hz)
点滅2・・・(10Hz)
*********************************************************************************************** */
#include (avr/io.h)
#include (avr/eeprom.h)
// PORTB
//#define def 7
//#define def 6
//#define def 5
//#define def 4
//#define def 3
#define dat_ch 2
#define cs_ch 1
#define clk_ch 0
// PORTC
//#define RESET 6
//#define def 5
//#define def 4
//#define menu_sw 3
//#define select_sw 2
//#define back_s 1
//#define accel_s 0
// PORTD
#define seg_a 7
#define seg_b 6
#define seg_c 5
#define seg_d 4
#define seg_e 3
#define seg_f 2
#define seg_g 1
#define status_LED 0
/*************************************************************************************************
******* グローバル宣言 */
uint8_t mode; // 0:Normal,1:Flat,2:Sports,3:Eco,4:Back
uint8_t mode_e __attribute__((section(".eeprom")));
uint8_t menu_stu; // 0:def 1:select 2:EEPROM_write&read
uint8_t adc; // A/D converter
// 7セグ表示用データ
uint8_t seg_dat[] = {
0b11111101, // 0
0b01100001, // 1
0b11011011, // 2
0b11110011, // 3
0b01100111, // 4
0b10110111, // 5
0b10111111, // 6
0b11100101, // 7
0b11111111, // 8
0b11110111, // 9
0b11111101, // 1O:Normal
0b10001111, // 11:Flat
0b10110111, // 12:Sports
0b10011111 // 13:Eco
};
// モード別テーブル
uint8_t kaido_dat[50];
// Normal モード ;0
uint8_t table_n[] __attribute__((section(".eeprom"))) ={
0,2,4,6,8,10,12,14,16,18,
20,22,24,26,28,30,32,34,36,38,
40,42,44,46,48,50,52,54,56,58,
60,62,64,66,68,70,72,74,76,78,
80,82,84,86,88,90,92,94,96,99
};
// Flat モード ;1
uint8_t table_f[] __attribute__((section(".eeprom"))) ={
0,2,4,6,8,10,12,14,16,18,
20,22,24,26,28,30,32,34,36,38,
40,42,44,46,48,50,52,54,56,58,
60,62,64,66,68,70,72,74,76,78,
80,82,84,86,88,90,92,94,96,99
};
// Sports モード;2
uint8_t table_s[] __attribute__((section(".eeprom"))) ={
0,2,4,6,8,10,12,14,16,18,
20,22,24,26,28,30,32,34,36,38,
40,42,44,46,48,50,52,54,56,58,
60,62,64,66,68,70,72,74,76,78,
80,82,84,86,88,90,92,94,96,99
};
// Eco モード;3
uint8_t table_e[] __attribute__((section(".eeprom"))) ={
0,2,4,6,8,10,12,14,16,18,
20,22,24,26,28,30,32,34,36,38,
40,42,44,46,48,50,52,54,56,58,
60,62,64,66,68,70,72,74,76,78,
80,82,84,86,88,90,92,94,96,99
};
// Back モード;4
uint8_t table_b[] ={
0,2,4,6,8,10,12,14,16,18,
20,22,24,26,28,30,32,34,36,38,
40,42,44,46,48,50,52,54,56,58,
60,62,64,66,68,70,72,74,76,78,
80,82,84,86,88,90,92,94,96,99
};
/*************************************************************************************************
******* プロトタイプ宣言 */
void init_io(void);
void init_adc(void);
void init_dat(void);
void wait_100us(uint16_t);
void table_in(void);
void menu(void);
void select(void);
int adc_convert(uint8_t);
void dac_out(uint16_t);
void seg_out(uint8_t);
/*************************************************************************************************
******* メイン */
int main(void){
// 初期化
init_io(); // I/O初期化
init_adc(); // A/Dコンバーター初期化
init_dat(); // データ初期化
PORTD |= _BV(status_LED); // LED点灯
// セッティング記録の読込み
eeprom_busy_wait(); // 読み書き可能になるまで待つ
mode = eeprom_read_byte(&mode_e); // EEPROMよりmodeデータを読出し
eeprom_busy_wait(); // 読み書き可能になるまで待つ
table_in(); // モードテーブルを選択格納
uint8_t i =0;
i = mode +10; // modeに+10の下駄をはかす
seg_out(i); // 選択モード表示
wait_100us(10000); // 1s待ち
wait_100us(10000); // 1s待ち 合計2s待ちオープニング
uint8_t x,x0; // 各SW変化検出用
x0 = PINC & 0b00001110; // 入力信号初期値を代入
// メインループ
while(1) {
// ステータスLED点滅(red)
PORTD ^= _BV(status_LED); // LEDを反転
// セッティング監査
x = PINC & 0b00001110; //
if (x != x0) {
if ((x & 0b00001000) != 0) {
menu();
}
if ((x & 0b00000100) != 0) {
select();
}
if ((x & 0b00000010) != 0) {
for(i=0;i<50;i++)
kaido_dat[i] = table_b[i]; // Back テーブルを格納
} else {
eeprom_busy_wait(); // 読み書き可能になるまで待つ
table_in(); // モードテーブルを選択格納
}
x0 = x; // 前回のスイッチ状況を反映
wait_100us(100); // 10ms待ち チャタリング防止用wait
}
// A/D 変換
adc = adc_convert(10); // ADC10からAD変換 512(例)
// データ変換
uint8_t accel_kaido =0;
accel_kaido = adc / 1023 / 2 * 100; // 50段階へ変換 25
// D/A変換用データ作成
uint8_t dac =0;
dac = kaido_dat[accel_kaido]; // パターン表を参照 50
uint16_t dac_ic_dat =0;
dac_ic_dat = dac * 41; // 2050
// D/A変換器へデータ送信
dac_out(dac_ic_dat); // 2050
// 7セグ表示
if (menu_stu != 0){
i =0;
i = mode + 10; // modeに+10の下駄をはかす
seg_out(i); // 選択モード表示
wait_100us(5000); // 500ms待ち LED点滅変更用wait
} else {
i =0;
i = dac / 10; // 表示用補正
seg_out(i); // アクセル開度表示 50
wait_100us(100); // 10ms待ち LED点滅変更用wait
}
}
}
/*************************************************************************************************
******* init_io I/O 初期化処理 */
void init_io(void){
DDRB = 0b11111111; // 全出力
PORTB = 0b01110000; // 0=all
PORTC = 0b01001110; // 6,3-1プルアップ
DDRC = 0b00110000; // 5-4出力
DDRD = 0b11111111; // 全出力
PORTD = 0b00000000; // 0=all
}
/*************************************************************************************************
******* init_adc A/Dコンバータ 初期化処理 */
void init_adc(void){
ADMUX = (1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
// 外部AVCC基準;データレジスタ右そろえ;ADC0;01 0 0 0000;
// 0<REFS1,1<REFS0,0<ADLAR,0<def,0<MUX3,0<MUX2,0<MUX1,0<MUX0
ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADPS1);
// A/D変換許可;1回目変換開始(調整);分周率1/4;1 1 0 0 0 010;
// 1<ADEN,1<ADSC,0<ADATE,0<ADIF,0<ADIE,0<ADPS2,1<ADPS1,0<ADPS0
ADCSRB = 0;
// 連続変換動作;0 0 000 000;
// 0<def,0<ACME,0<def,0<def,0<def,0<ADTS2,0<ADTS1,0<ADTS0
}
/*************************************************************************************************
******* init_dat 各種データ 初期化処理 */
void init_dat(void){
mode = 0; // Normal 初期値0
menu_stu = 0; //
adc = 0; //
}
/*************************************************************************************************
******* wait関数_100us */
void wait_100us(uint16_t time) { // 100us wait ルーチン。 クロック設定のこと。
// 25MHzでも 260ms までとれる。
time*=1; // 8MHzのとき。timeにF_CPU(MHz)をかける。重要!!
uint8_t lpcnt;
__asm__ __volatile__("\n"
"Entry%=: \n\t"
"ldi %0,24\n" // 計算値は25。24の方が実測値は良い。
"Loop%=: \n\t"
"nop\n\t"
"dec %0\n\t"
"brne Loop%=\n\t"
"sbiw %1,1\n\t"
"brne Entry%=\n\t"
:"=&a"(lpcnt)
:"w"(time)
);
return;
}
/*************************************************************************************************
******* テーブル格納 */
void table_in(void){
uint8_t i;
switch(mode){
case 0:for(i=0;i<50;i++){
eeprom_busy_wait();
kaido_dat[i] = eeprom_read_byte(&table_n[i]); // Normalテーブル格納
};
break;
case 1:for(i=0;i<50;i++){
eeprom_busy_wait();
kaido_dat[i] = eeprom_read_byte(&table_f[i]); // Flatテーブル格納
};
break;
case 2:for(i=0;i<50;i++){
eeprom_busy_wait();
kaido_dat[i] = eeprom_read_byte(&table_s[i]); // Sportsテーブル格納
}
break;
case 3:for(i=0;i<50;i++){
eeprom_busy_wait();
kaido_dat[i] = eeprom_read_byte(&table_e[i]); // Ecoテーブル格納
}
break;
default:mode = 0;
}
}
/*************************************************************************************************
******* menu */
void menu(void){
menu_stu++;
if (2 < menu_stu) {
menu_stu = 0;
}
if (menu_stu == 2){
eeprom_busy_wait(); // 読み書き可能になるまで待つ
eeprom_write_byte (&mode_e, mode); // EEPROMへmodeデータを書込み
menu_stu = 0;
eeprom_busy_wait(); // 読み書き可能になるまで待つ
table_in(); // モードテーブルを選択格納
}
}
/*************************************************************************************************
******* select */
void select(void){
if (menu_stu == 1){
mode++;
if (3 < mode) {
mode = 0;
}
}
}
/*************************************************************************************************
******* ピンを指定してAD変換 戻り値(return) 0-1023 */
int adc_convert(uint8_t pin){
ADMUX = pin; // AD変換入力ピン
ADCSRA &= ~_BV(ADIF); //
ADCSRA |= _BV(ADSC); // 変換開始
loop_until_bit_is_set(ADCSRA,ADIF); // 変換完了まで待つ
adc = ADCL; // 下位8bit取得
return adc += (ADCH<<8); // 上位2bit取得
}
/*************************************************************************************************
******* dac_out D/A変換器へデータ送信 */
void dac_out(uint16_t out) // D/A_out
{
uint8_t i = 0;
// 開始処理
PORTB = _BV(0 << clk_ch); // clock low
PORTB = _BV(0 << cs_ch); // CS on
// 以下4ビットがステータス設定ビット
// bit-1 // チャンネル設定ビット 0:chanel A 1:chanel B
// VoutA に出力
// PORTB = _BV(1 << dat_ch); // data high
PORTB = _BV(0 << dat_ch); // data low
PORTB = _BV(1 << clk_ch); // clock high
PORTB = _BV(0 << clk_ch); // clock low
// bit-2 // dummy;常時 1
PORTB = _BV(1 << dat_ch); // data high
// PORTB = _BV(0 << dat_ch); // data low
PORTB = _BV(1 << clk_ch); // clock high
PORTB = _BV(0 << clk_ch); // clock low
// bit-3 // ゲイン設定ビット 1:G=1, 0:G=2
// G = 2; V = Data/4096 * 2.048*2 [V]
// PORTB = _BV(1 << dat_ch); // data high
PORTB = _BV(0 << dat_ch); // data low
PORTB = _BV(1 << clk_ch); // clock high
PORTB = _BV(0 << clk_ch); // clock low
// bit-4 // シャットダウン設定ビット 1:出力イネイブル, 0:シャットダウン
// output enable
PORTB = _BV(1 << dat_ch); // data high
// PORTB = _BV(0 << dat_ch); // data low
PORTB = _BV(1 << clk_ch); // clock high
PORTB = _BV(0 << clk_ch); // clock low
// ここから、データビット
for(i=0; i<12; i++){ // 送信データをMSBから順次1ビットづつ合計12bit分を出力する
// outの第12bitをチェック 0なら0を1なら1を出力する
if ((out & 0b0000100000000000) != 0){ // 0000 1000 0000 0000;
PORTB = _BV(1 << dat_ch); // 12bit目が1ならdata highを出力
} else {
PORTB = _BV(0 << dat_ch); // 12bit目が0ならdata lowを出力
}
out = (out << 1); // 送信後1bitだけ左にビットシフト
PORTB = _BV(1 << clk_ch); // clock high
PORTB = _BV(0 << clk_ch); // clock low
}
// 終了処理
PORTB = _BV(1 << cs_ch); // CS off
}
/**************************************************************************************************
******* 7セグメント表示 */
void seg_out(uint8_t data) {
uint8_t j,x,y;
x = PORTD; // ポート状態データ取得
PORTD = (x & 0b00000001); // 7seg 表示クリア
x = PORTD; // ポート状態データ再取得
x = (x ^ 0b11111110); // bit0以外を反転マスク
j = data; // データ取得
y = seg_dat[j]; // 7segデータを展開
PORTD = (x & y); // 7segデータをポートへ出力
}
/*************************************************************************************************
******* END */