LCDKEYSHILEDと40X4LCDパネル使ったSPI MONITORを作った。
LCDKEYSHIELDを利用して、そのパネルについているKEYとLCDを使って操作できるようにした。これなら、いままで表示するだけのLCDパネルからWEB経由しないでECUの初期設定やHWの自己診断の選択ができるようになった。また、併せて、20文字X4行から40文字X4行も使えるようになったので、WEB版で出していたものも追加した。
もちろん、LCD KEY SHIEILDで操作できるようになっても、WEB版も同様に操作できる。
LCD KEY SHIELDの操作感はこんな感じ
LCD KEY SHILDは、LCDはパラレルインタフェースで、KEY操作は、1チャンネルのアナログ入力になっている。このキーのアナログ入力が曲者で、5Vを基準に各キーで違った電圧を生成してA/Dで読み取っているけど、5Vが揺れると、下記キーの閾値のずれてくる。特にSELECTキーの抵抗値の設定が良くなくて、ころころ読む値が変わってきてしまう。うちの開発環境が、USBの複合ポートからUSBハブでESPに接続しているので、5Vの電圧の揺れが大きいようで、A/D入力の閾値を決めるキャリブレーションを頻繁に行わないと使い物にならない。もしくは、5V->3.3Vの生成に抵抗でやっているけど、ツェーナーで生成するなどを考えないと使いものにならないと思った。今回のESP32のGPIOの割付けは下記の通りとなっている。合わせれば動作します。
------------------------------------------ GPIO Info: ------------------------------------------ GPIO : BUS_TYPE[bus/unit][chan] ------------------------------------------ 3 : GPIO ;LCD KEY 8 : I2C_MASTER_SCL[0] ;40x4 LCD 9 : I2C_MASTER_SDA[0] ;40x4 LCD 14 : GPIO 15 : UART_RX[2] ;MEMS connect 16 : UART_TX[2] lMEMS connect 19 : GPIO 20 : GPIO 21 : GPIO 43 : UART_TX[0] ;Debug serial 44 : UART_RX[0] ;Debug serial 46 : GPIO ;LCD KEY analog input ------------------------------------------
今回変更した内容は下記の通り
- ESP32-S3の対応
- 40行X4行のLCD対応
- WIFIのAPモードとStationモードの対応。Staitonモードの場合は10秒間で接続できなかったら打ち切るようにした。前のバージョンは無限に待っていたのでロックして起動しないように見えた。
- ロータリーエンコーダーの対応
- KEY LCD SHIELDの対応
各機能は同じソースで対応しており、頭のdefine分をコメントすることで制御できるようにしてある。全部のソースは下記の置いておく。WEB関係のソースはいじっていないので、前の物を転送していれば更新は不要。
SPI MoniotrのソースとHTML,CSSのセット(ZIP FILE)
ソースは折り畳んでいるので、全部のスケッチはクリックして見る
/*
* This code is created by www.misago.com
*
* All original source code in this repository is Copyright (C) 2024 HATI
*
* For more detail (instruction and wiring diagram), visit https://www.misago.com
*/
#define LCD40X4 1
#define ESP32S3 1
#define LCDKEY 1
#define AP_Mode
//#define OLEDESP 1
#include <WiFi.h>
#include <ESPAsyncWebSrv.h>
#include <LittleFS.h>
#include <Wire.h>
#if defined(OLEDESP)
#include <Wire.h> // I2C ライブラリ
#include <Adafruit_GFX.h> // グラフィックのコア・ライブラリ
#include <Adafruit_SH110X.h> // 1.3インチ OLED
#include "AiEsp32RotaryEncoder.h"
#endif
#if defined(LCDKEY)
#include <LiquidCrystal.h>
#endif
#if defined(LCD40X4)
#include <pgmspace.h>
#include <LiquidCrystal_I2C_4004.h>
#define xpos 20
#define ypos 1
#else
#include <LCD_I2C.h>
#define xpos 0
#define ypos 0
#endif
#define ModelNum 5
#define COMMAND80 29
#define COMMAND7D 33
#define COMMANDD0 5
#define NOTEST 0
#define STEPPINGFINISHNG 1
#define STEPPINGFINISHOK 2
#define FUELPUMPFINISHNG 3
#define FUELPUMPFINISHOK 4
#define ACRELAYFINISHNG 5
#define ACRELAYFINISHOK 6
#define O2HEATERFINISHNG 7
#define O2HEATERFINISHOK 8
#define PTCRELAYFINISHNG 9
#define PTCRELAYFINISHOK 10
#define PURGEVALVEFINISHNG 11
#define PURGEVALVEFINISHOK 12
#define STEPPINGNUM 20
#define FUELPUMPNUM 21
#define ACRELAYNUM 22
#define O2HEATERNUM 23
#define PTCRELAYNUM 24
#define PURGEVALVENUM 25
#if defined(OLEDESP)
#define I2CSDA 21
#define I2CSCL 22
#define UARTTX 17 //ESP32
#define UARTRX 16 //ESP32
/*
connecting Rotary encoder
Rotary encoder side MICROCONTROLLER side
------------------- ---------------------------------------------------------------------
CLK (A pin) any microcontroler intput pin with interrupt -> in this example pin 16
DT (B pin) any microcontroler intput pin with interrupt -> in this example pin 14
SW (button pin) any microcontroler intput pin with interrupt -> in this example pin 13
GND - to microcontroler GND
VCC microcontroler VCC (then set ROTARY_ENCODER_VCC_PIN -1)
***OR in case VCC pin is not free you can cheat and connect:***
VCC any microcontroler output pin - but set also ROTARY_ENCODER_VCC_PIN 25
in this example pin 25
*/
#define ROTARY_ENCODER_A_PIN 27
#define ROTARY_ENCODER_B_PIN 26
#define ROTARY_ENCODER_BUTTON_PIN 25
#define ROTARY_ENCODER_BACK_BUTTON_PIN 33
#define ROTARY_ENCODER_COMFIRM_BUTTON_PIN 32
#define ROTARY_ENCODER_VCC_PIN -1 /* 27 put -1 of Rotary encoder Vcc is connected directly to 3,3V; else you can use declared output pin for powering rotary encoder */
//depending on your encoder - try 1,2 or 4 to get expected behaviour
//#define ROTARY_ENCODER_STEPS 1
//#define ROTARY_ENCODER_STEPS 2
#define ROTARY_ENCODER_STEPS 4
#define OLED_I2C_ADRS 0x3C // I2C address of OLED
#define Wire1_SDA 13
#define Wire1_SCL 14
struct Button {
const uint8_t PIN;
bool pressed;
uint32_t lastMillis;
};
Button button1 ={ ROTARY_ENCODER_BACK_BUTTON_PIN,false,0};
Button button2 ={ ROTARY_ENCODER_COMFIRM_BUTTON_PIN,false,0};
#else
#if defined(ESP32S3)
#define I2CSDA 9
#define I2CSCL 8
#define UARTTX 16 //ESP32-S3
#define UARTRX 15 //ESP32-S3
#else
#define I2CSDA 21
#define I2CSCL 22
#define UARTTX 15 //ESP32
#define UARTRX 17 //ESP32
#endif
#endif
#if defined(LCDKEY)||defined(OLEDESP)
#define KEYRIGHT 0
#define KEYUP 1
#define KEYDOWN 2
#define KEYLEFT 3
#define KEYSELECT 4
#define KEYNONE 5
#define KEYERR 6
#endif
#if defined(LCDKEY)
#define KEY_AD 2 // analog input oprt
// A/D input Threshold
#define THRIGHT 159
#define THUP 700
#define THDOWN 1100
#define THLEFT 1600
#define THSELECT 2100
#define THNONE 2300
#if defined(ESP32S3)
/* LCD Assign ESP32-S3 UNO */
#define LCD_RS 21
// #define LCD_RW // GND
#define LCD_EN 46
#define LCD_D4 19
#define LCD_D5 20
#define LCD_D6 3
#define LCD_D7 14
#else
/* LCD Assign ESP32 */
#define LCD_RS 19
// #define LCD_RW // GND
#define LCD_EN 14
#define LCD_D4 18
#define LCD_D5 5
#define LCD_D6 17
#define LCD_D7 16
#endif
#endif
AsyncWebServer server(80);
// AP mode
#ifdef AP_Mode
const IPAddress ip(192, 168, 5, 10); // *** set any addr ***
const IPAddress subnet(255, 255, 255, 0);
const char* ssid = "MEMS";
const char* password = "MiniDeto";
//WIFI station mode
#else
const char *ssid = "XXXXXXXX";
const char *password = "XXXXXXXXXXXX";
#endif
#if defined(LCDKEY)
/*********************/
/* Keypad 入力処理 */
/*********************/
int lastTimekey=KEYNONE;
int firstitem=0;
int seconditem=0;
int position=0;
const char firstitems[][17] = {"Faultcode reset " , "HW TEST " , "Adjust TRIM " , "Adjust IdelSpeed" , "Adjust ignition " };
const char hwtestitems[][17]= {"Stepping Motor " , "Fuelpump TEST " , "AC Relay TEST " , "O2Heater TEST " , "PTC Relay TEST ","PurgeValve TEST" };
const struct {
short dat; // A/D入力閾値
int ret; // 戻り値
} t_key[5] = {
{ THRIGHT , KEYRIGHT },
{ THUP , KEYUP },
{ THDOWN , KEYDOWN },
{ THLEFT , KEYLEFT },
{ THSELECT,KEYSELECT }
};
#endif
#if defined(OLEDESP)
/*********************/
/* Keypad 入力処理 */
/*********************/
int lastTimekey=KEYNONE;
int firstitem=0;
int seconditem=0;
int position=0;
const char firstitems[][17] = {"Faultcode reset " , "HW TEST " , "Adjust TRIM " , "Adjust IdelSpeed" , "Adjust ignition " };
const char hwtestitems[][17]= {"Stepping Motor " , "Fuelpump TEST " , "AC Relay TEST " , "O2Heater TEST " , "PTC Relay TEST ","PurgeValve TEST" };
struct {
int lastcount; // A/D入力閾値
int key; // 戻り値
} t_key = { 500,KEYNONE };
#endif
long webcount = 0;
float webcount2=0.0;
#if defined(LCD40X4)
LiquidCrystal_I2C lcd(0x27, 40, 4); // I2C address 0x27, 40 column and 4 rows
LiquidCrystal_I2C lcd2(0x26, 40, 4); // I2C address 0x26, 40 column and 4 rows
#else
LCD_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 column and 4 rows
LCD_I2C lcd2(0x26, 20, 4); // I2C address 0x26, 20 column and 4 rows
#endif
#if defined(LCDKEY)
LiquidCrystal lcd3(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
#endif
#if defined(OLEDESP)
Adafruit_SH1106G OLED1(128, 64, &Wire1, -1);
// 引数 WIDTH, HEIGHT, &Wire, OLED_RESET
// 4つ目の引数はRESETピン -1はArduinoのRESETピンと共有
int rolayvalue=0;
int keystatus=false;
//instead of changing here, rather change numbers above
AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, ROTARY_ENCODER_VCC_PIN, ROTARY_ENCODER_STEPS);
#endif
uint8_t databuf[80];
int receive_byte;
int memsconnect;
int testruning;
int testitem;
int runtestitem;
const char MEMSModel[][11] = { "MNE10089 ", "MNE10078 ", "MNE101070 ", "MNE101170 ", "MNE101060 " };
const char MEMScode[][4] = { 0x98, 0x00, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x14, 0x99, 0x00, 0x02, 0x03, 0x99, 0x00, 0x03, 0x03, 0x9a, 0x00, 0x01, 0x02 };
// Dataframe command(0x80)の構造体
struct command80 {
uint8_t commnad;
uint8_t framesize; //including this byte. This should be 0x1C (28 bytes) for the frame described here.
uint8_t enginespeed1; // RPM (16 bits)
uint8_t enginespeed2; // RPM (16 bits)
uint8_t coolanttemperature; //degrees C with +55 offset and 8-bit wrap
uint8_t ambienttemperature; // degrees C with +55 offset and 8-bit wrap
uint8_t intakeairtemperature; //degrees C with +55 offset and 8-bit wrap
uint8_t fueltemperature; //degrees C with +55 offset and 8-bit wrap. This is not supported on the Mini SPi, and always appears as 0xFF.
uint8_t mapsensorvalue; //kilopascals
uint8_t batteryvoltage; //0.1V per LSB (e.g. 0x7B == 12.3V)
uint8_t throttlepotvoltage; //0.02V per LSB. WOT should probably be close to 0xFA or 5.0V.
uint8_t idleswitch; //Bit 4 will be set if the throttle is closed, and it will be clear otherwise.
uint8_t Unknown1; //Probably a bitfield. Observed as 0x24 with engine off, and 0x20 with engine running. A single sample during a fifteen minute test drive showed a value of 0x30.
uint8_t parkneutralswitch; //Zero is closed, nonzero is open.
uint8_t faultcodes1; //On the Mini SPi, only two bits in this location are checked:
// Bit 0: Coolant temp sensor fault (Code 1)
// Bit 1: Inlet air temp sensor fault (Code 2)
uint8_t faultcodes2; //On the Mini SPi, only two bits in this location are checked:
// Bit 1: Fuel pump circuit fault (Code 10)
// Bit 7: Throttle pot circuit fault (Code 16)
uint8_t Unknown2;
uint8_t Unknown3;
uint8_t Unknown4;
uint8_t idleaircontrolmotorposition; //On the Mini SPi's A-series engine, 0 is closed, and 180 is wide open.
uint8_t idlespeed1; //deviation (MSB 16 bits)
uint8_t idlespeed2; //deviation (LSB 16 bits)
uint8_t Unknown5;
uint8_t ignitionadvance; //0.5 degrees per LSB with range of -24 deg (0x00) to 103.5 deg (0xFF)
uint8_t coiltime1; //0.002 milliseconds per LSB (16 bits)
uint8_t coiltime2; //0.002 milliseconds per LSB (16 bits)
uint8_t Unknown6;
uint8_t Unknown7;
uint8_t Unknown8;
};
// Dataframe command(0x7d)の構造体
struct command7d {
uint8_t commnad;
uint8_t framesize; // including this byte (0x1f)
uint8_t Unknown1;
uint8_t throttleangle;
uint8_t Unknown2;
uint8_t airfuelratio; // but often observed to never change from 0xFF
uint8_t Unknown3;
uint8_t lambdasensorvoltage; // 5mV per LSB
uint8_t lambdasensorfrequency; //
uint8_t lambdasensordutycycle; //
uint8_t lambdasensorstatus; // 0x01 for good, any other value for no good
uint8_t loopindicator; //0 for open loop and nonzero for closed loop
uint8_t longtermtrim;
uint8_t shorttermtrim; //1% per LSB
uint8_t carboncanisterpurgevalvedutycycle;
uint8_t Unknown4;
uint8_t idlebaseposition;
uint8_t Unknown5;
uint8_t Unknown6;
uint8_t Unknown7;
uint8_t Unknown8;
uint8_t idleerror;
uint8_t Unknown9;
uint8_t UnknownA;
uint8_t UnknownB;
uint8_t UnknownC;
uint8_t UnknownD;
uint8_t UnknownE;
uint8_t UnknownF;
uint8_t Unknown10;
uint8_t Unknown11;
uint8_t Unknown12;
uint8_t jackcount;
};
//Errorの取り出し
struct bits1 {
uint8_t coolanttempsensor : 1;
uint8_t inletairtempsensor : 1;
uint8_t b3 : 1;
uint8_t b4 : 1;
uint8_t b5 : 1;
uint8_t b6 : 1;
uint8_t b7 : 1;
uint8_t b8 : 1;
};
struct bits2 {
uint8_t b1 : 1;
uint8_t fuelpumpcircuit : 1;
uint8_t b3 : 1;
uint8_t b4 : 1;
uint8_t b5 : 1;
uint8_t mapsensor : 1;
uint8_t b7 : 1;
uint8_t throttlepotcircuit : 1;
};
union body {
uint8_t frame80[COMMAND80+1];
command80 frame;
} data;
union body2 {
uint8_t frame7d[COMMAND7D+1];
command7d frame;
} data2;
union body3 {
uint8_t faultcode1;
struct bits1 b;
} error1;
union body4 {
uint8_t faultcode2;
struct bits2 bb;
} error2;
#if defined(OLEDESP)
void IRAM_ATTR readEncoderISR()
{
rotaryEncoder.readEncoder_ISR();
}
void IRAM_ATTR isr()
{
if( millis() -button1.lastMillis >500){
button1.pressed =true;
}
button1.lastMillis=millis();
}
void IRAM_ATTR isr2()
{
if( millis() -button2.lastMillis >500){
button2.pressed =true;
}
button2.lastMillis=millis();
}
#endif
//Stepping moterのテスト
int steppingtest(void){
int steppingdata1,steppingdata2,originalposition,result=false;
unsigned long start_time = 0 ; // タイムアウト監視開始時間
//iNIT CODE FB
Serial2.write(0xfb); // 現在のSteppingの位置の取得
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() <2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) { //データがかえってこなかった。
return (false);
}
//Serial2に受信データの結果読み出し(0xCC00)
steppingdata1= Serial2.read();
originalposition= Serial2.read();
Serial.print(steppingdata1);
Serial.print(originalposition);
if (steppingdata1 != 0xfb ) {
return (false);
}else{
if( originalposition==0){
return (false);
}else{
do{
//iNIT CODE FE
Serial2.write(0xfe); // 現在のSteppingのモーターをクローズ側へ移動
delay(50);
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) { //データがかえってこなかった。
return (false);
}
//Serial2に受信データの結果読み出し(0xCC00)
steppingdata1= Serial2.read();
steppingdata2= Serial2.read();
}while(steppingdata2 != 0 );
do{
//iNIT CODE FD
Serial2.write(0xfd); // 現在のSteppingのモーターをopen側へ移動
delay(50);
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) { //データがかえってこなかった。
return (false);
}
//Serial2に受信データの結果読み出し(0xCC00)
steppingdata1= Serial2.read();
steppingdata2= Serial2.read();
}while(steppingdata2 != 0xb4 );
do{
//iNIT CODE FE
Serial2.write(0xfe); // 現在のSteppingのモーターをクローズ側へ移動
delay(50);
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) { //データがかえってこなかった。
return (false);
}
//Serial2に受信データの結果読み出し(0xCC00)
steppingdata1= Serial2.read();
steppingdata2= Serial2.read();
}while(steppingdata2 != originalposition );
}
}
return(true);
}
//リレー関連のテスト
int relaytest(int relayon , int relayoff){
int i,relaydata1,relaydata2,result=false;
unsigned long start_time = 0 ; // タイムアウト監視開始時間
for( i=0 ; i<11 ; i++ ){ //ACR4は11回ループしていた
// Relay ON
Serial2.write(relayon); // 現在のrelay Onのコマンドを送る
delay(300);
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) { //データがかえってこなかった。
return (false);
}
//Serial2に受信データの結果読み出し
relaydata1= Serial2.read();
relaydata2= Serial2.read();
//Realy off
Serial2.write(relayoff); // 現在のrealy offコマンドを送信
delay(30);
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) { //データがかえってこなかった。
return (false);
}
//Serial2に受信データの結果読み出し
relaydata1= Serial2.read();
relaydata2= Serial2.read();
}
//ダメ押しのOFF
Serial2.write(relayoff); // 現在のRealyのOFFをさらに送信
delay(300);
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) { //データがかえってこなかった。
return (false);
}
//Serial2に受信データの結果読み出し
relaydata1= Serial2.read();
relaydata2= Serial2.read();
return(true);
}
// 内部変数でhtmlファイル内のSTATEの文字を変える
String processor(const String& var) {
char buf[80];
uint8_t readdata1,readdata2;
int receive,count=0;
unsigned long start_time = 0 ; // タイムアウト監視開始時間
// Serial.println(var);
if (var == "RPM") {
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
return String(webcount);
} else if (var == "Twater") {
webcount=(int)data.frame.coolanttemperature - 55;
return String(webcount);
} else if (var == "Tintake") {
webcount=(int)data.frame.intakeairtemperature - 55;
return String(webcount);
} else if (var == "Tambient"){
webcount=(int)data.frame.ambienttemperature - 55;
return String(webcount);
} else if (var == "DATA00"){
webcount=(int)data2.frame.Unknown1;
return String(webcount);
} else if (var =="tangule"){
webcount2=(float)(data2.frame.throttleangle) /2;
return dtostrf(webcount2,5,1,buf);
} else if (var == "AF"){
webcount2=(float)data2.frame.airfuelratio / 10;
return dtostrf(webcount2,6,1,buf);
} else if (var == "DATA03"){
webcount=(int)data2.frame.Unknown2;
return String(webcount);
} else if (var == "Ftemp"){
webcount=(int)data.frame.fueltemperature - 55;
return String(webcount);
} else if (var == "MAPsensor"){
webcount=(int)data.frame.mapsensorvalue;
return String(webcount);
} else if (var == "Bvoltage"){
webcount2=0.1 * (float)data.frame.batteryvoltage;
return dtostrf(webcount2,5,1,buf);
} else if (var == "Tvoltage"){
webcount2=0.02 * (float)data.frame.throttlepotvoltage;
return dtostrf(webcount2,6,2,buf);
} else if (var == "idelSW"){
webcount=(int)data.frame.idleswitch;
return String(webcount);
} else if (var == "Unknown1"){
webcount=(int)data.frame.Unknown1;
return String(webcount,BIN);
} else if (var == "parksw"){
webcount=(int)data.frame.parkneutralswitch;
return String(webcount);
} else if (var == "faultcodes1"){
webcount=(int)data.frame.faultcodes1;
return String(webcount , BIN );
} else if (var == "faultcodes2"){
webcount=(int)data.frame.faultcodes2;
return String(webcount , BIN );
} else if (var == "unknow2"){
webcount2=6.1 * (float)data.frame.Unknown2;
return dtostrf(webcount2,6,1,buf);
} else if (var == "unknow3"){
webcount=(int)data.frame.Unknown3;
return String(webcount);
} else if (var == "unknow4"){
webcount=(int)data.frame.Unknown4;
return String(webcount);
} else if (var == "idleaircontrolmotorposition"){
webcount=(int)data.frame.idleaircontrolmotorposition;
return String(webcount);
} else if (var == "idlespeed"){
webcount=(int)data.frame.idlespeed1 * 256 + (int)data.frame.idlespeed2;
return String(webcount);
} else if (var == "idleaircontrolmotorposition"){
webcount=(int)data.frame.idleaircontrolmotorposition;
return String(webcount);
} else if (var == "Unknown5"){
webcount2=0.5 * (float)data.frame.Unknown5;
return dtostrf(webcount2,6,1,buf);
} else if (var == "ignitionadvance"){
webcount2=-24.0 + 0.5 * (float)data.frame.ignitionadvance;
return dtostrf(webcount2,6,1,buf);
} else if (var == "coiltime"){
webcount2=0.002 * ((float)data.frame.coiltime1*256 + (float)data.frame.coiltime2);
return dtostrf(webcount2,8,3,buf);
} else if (var == "unknown6"){
webcount=(int)data.frame.Unknown6;
return String(webcount);
} else if (var == "unknown7"){
webcount=(int)data.frame.Unknown7;
return String(webcount);
} else if (var == "unknown8"){
webcount=(int)data.frame.Unknown8;
return String(webcount);
} else if (var == "Unknown2B"){
webcount=(int)data2.frame.Unknown3;
return String(webcount,BIN );
} else if (var == "lambdasensorvoltage"){
webcount=5 * (int)data2.frame.lambdasensorvoltage;
return String(webcount);
} else if (var == "lambdasensorfrequency"){
webcount=(int)data2.frame.lambdasensorfrequency;
return String(webcount);
} else if (var == "lambdasensordutycycle"){
webcount=(int)data2.frame.lambdasensordutycycle;
return String(webcount);
} else if (var == "lambdasensorstatus"){
webcount=(int)data2.frame.lambdasensorstatus;
return String(webcount);
} else if (var == "loopindicator"){
webcount=(int)data2.frame.loopindicator;
return String(webcount);
} else if (var == "longtermtrim"){
webcount=(int)data2.frame.longtermtrim-128;
return String(webcount);
} else if (var == "shorttermtrim"){
webcount=(int)data2.frame.shorttermtrim;
return String(webcount);
} else if (var == "purgevalvedutycycle"){
webcount=(int)data2.frame.carboncanisterpurgevalvedutycycle;
return String(webcount);
} else if (var == "Unknown4B"){
webcount=(int)data2.frame.Unknown4;
return String(webcount,BIN);
} else if (var == "idlebaseposition"){
webcount=(int)data2.frame.idlebaseposition;
return String(webcount);
} else if (var == "Unknown5B"){
webcount=(int)data2.frame.Unknown5;
return String(webcount,HEX);
} else if (var == "Unknown6B"){
webcount=(int)data2.frame.Unknown6;
return String(webcount,BIN);
} else if (var == "Unknown7B"){
webcount=(int)data2.frame.Unknown7-48;
return String(webcount);
} else if (var == "Unknown8B"){
webcount=(int)data2.frame.Unknown8;
return String(webcount);
} else if (var == "idleerror"){
webcount=(int)data2.frame.idleerror;
return String(webcount);
} else if (var == "Unknown9B"){
webcount=(int)data2.frame.Unknown9;
return String(webcount,HEX);
} else if (var == "UnknownA"){
webcount=(int)data2.frame.UnknownA;
return String(webcount,BIN);
} else if (var == "UnknownB"){
webcount=(int)data2.frame.UnknownB;
return String(webcount,HEX);
} else if (var == "UnknownC"){
webcount=(int)data2.frame.UnknownC;
return String(webcount,HEX);
} else if (var == "UnknownD"){
webcount=(int)data2.frame.UnknownD;
return String(webcount,HEX);
} else if (var == "UnknownE"){
webcount=(int)data2.frame.UnknownE;
return String(webcount,HEX);
} else if (var == "UnknownF"){
webcount=(int)data2.frame.UnknownF;
return String(webcount,HEX);
} else if (var == "Unknown10"){
webcount=(int)data2.frame.Unknown10;
return String(webcount,HEX);
} else if (var == "Unknown11"){
webcount=(int)data2.frame.Unknown11;
return String(webcount,HEX);
} else if (var == "Unknown12"){
webcount=(int)data2.frame.Unknown12;
return String(webcount,HEX);
} else if (var == "jackcount"){
webcount=(int)data2.frame.jackcount;
return String(webcount);
} else if (var == "HWRESETRESULTS"){
if( memsconnect == false){
return"MEMSに接続されていません";
}else{
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0){
return"エンジンを止めてください";
}else{
//シリアルのBUFFERのから読み
while(Serial2.available() !=0 )Serial2.read();
//iNIT CODE CC
Serial2.write(0xCC); // f4=Fault code reset
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) {
return ("エラーコードが返ってこない");
}
//Serial2に受信データの結果読み出し(0xCC00)
readdata1= Serial2.read();
readdata2= Serial2.read();
if (readdata1 == 0xCC && readdata2 == 0x00) {
return ("初期化に成功しました");
}
return ("初期化に失敗しました");
}
}
} else if (var == "STEPPINGRESULTS"){
if(testruning==true){
return"テスト実行中";
}else{
if( memsconnect == false){
return"MEMSに接続されていません";
}else{
switch(testitem){
case STEPPINGFINISHNG:
testitem=NOTEST;
return"MEMSの帰り値が不正でした";
case STEPPINGFINISHOK:
testitem=NOTEST;
return"Stepping Motorテストが完了しました";
}
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0 ){
return"エンジンを止めてください";
}else{
runtestitem=STEPPINGNUM;
testruning=true;
return("Stepping Motorのテストの実行を始めました");
}
}
}
} else if (var == "FUELPUMPRESULTS"){
if(testruning==true){
return"テスト実行中";
}else{
if( memsconnect == false){
return"MEMSに接続されていません";
}else{
switch(testitem){
case FUELPUMPFINISHNG:
testitem=NOTEST;
return"MEMSの帰り値が不正でした";
case FUELPUMPFINISHOK:
testitem=NOTEST;
return"燃料ポンプリレーのテストが完了しました";
}
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0 ){
return"エンジンを止めてください";
}else{
runtestitem=FUELPUMPNUM;
testruning=true;
return("燃料ポンプリレーのテストの実行を始めました");
}
}
}
} else if (var == "ACRELAYRESULTS"){
if(testruning==true){
return"テスト実行中";
}else{
if( memsconnect == false){
return"MEMSに接続されていません";
}else{
switch(testitem){
case ACRELAYFINISHNG:
testitem=NOTEST;
return"MEMSの帰り値が不正でした";
case ACRELAYFINISHOK:
testitem=NOTEST;
return"エアコン リレーのテストが完了しました";
}
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0 ){
return"エンジンを止めてください";
}else{
runtestitem=ACRELAYNUM;
testruning=true;
return("エアコンリレーのテストの実行を始めました");
}
}
}
} else if (var == "O2HEATERRESULTS"){
if(testruning==true){
return"テスト実行中";
}else{
if( memsconnect == false){
return"MEMSに接続されていません";
}else{
switch(testitem){
case O2HEATERFINISHNG:
testitem=NOTEST;
return"MEMSの帰り値が不正でした";
case O2HEATERFINISHOK:
testitem=NOTEST;
return"O2センサーのリレーのテストが完了しました";
}
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0 ){
return"エンジンを止めてください";
}else{
runtestitem=O2HEATERNUM;
testruning=true;
return("O2センサーリレーのテストの実行を始めました");
}
}
}
} else if (var == "PTCRELAYRESULTS"){
if(testruning==true){
return"テスト実行中";
}else{
if( memsconnect == false){
return"MEMSに接続されていません";
}else{
switch(testitem){
case PTCRELAYFINISHNG:
testitem=NOTEST;
return"MEMSの帰り値が不正でした";
case PTCRELAYFINISHOK:
testitem=NOTEST;
return"PTCリレーのテストが完了しました";
}
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0 ){
return"エンジンを止めてください";
}else{
runtestitem=PTCRELAYNUM;
testruning=true;
return("PTCリレーのテストの実行を始めました");
}
}
}
} else if (var == "PURGEVALVERESULTS"){
if(testruning==true){
return"テスト実行中";
}else{
if( memsconnect == false){
return"MEMSに接続されていません";
}else{
switch(testitem){
case PURGEVALVEFINISHNG:
testitem=NOTEST;
return"MEMSの帰り値が不正でした";
case PURGEVALVEFINISHOK:
testitem=NOTEST;
return"Purgeバルブリレーのテストが完了しました";
}
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0 ){
return"エンジンを止めてください";
}else{
runtestitem=PURGEVALVENUM;
testruning=true;
return("Purgeバルブリレーのテストの実行を始めました");
}
}
}
}else
return String();
}
int Readbyte_MEMS(int *result) {
int Initerror = false, count = 0;
while (!Serial2.available()) {
count = count + 1;
;
if (count > 10000) {
Initerror = true;
return (Initerror);
}
}
//Serial2に受信データがあるか
*result = Serial2.read(); //Serial2データを読み出し
return (Initerror);
}
int Readmulti_MEMS(void) {
uint8_t readdata;
int i, Initerror = false, count;
// String str;
count = 0;
receive_byte = 0;
do {
receive_byte = Serial2.available();
count = count + 1;
if (count > 10000) {
break;
}
} while (receive_byte < 33);
if (receive_byte == 0) {
Initerror = true;
return (Initerror);
}
//Serial2に受信データがあるか
// Serial.printf("receive byte=%02d\n", receive_byte);
for (i = 0; i < receive_byte; i++) {
readdata= (uint8_t)Serial2.read();
databuf[i] = readdata;
// Serial.printf("data~%02X databuf=%02X\n", readdata,databuf[i]);
}
databuf[receive_byte] = 0;
}
void StrtoHEX(void) {
int i;
for (i = 0; i < receive_byte; i++) {
Serial.printf("%02X", databuf[i]);
}
}
int InitMEMS(void) {
int i, j, data, count = 0, result, retry = 0,readdata[COMMANDD0];
memsconnect=false;
testitem=NOTEST;
runtestitem=NOTEST;
// ゴミデータの読みだし
while (Serial2.available() != 0) {
Serial2.read();
}
//iNIT CODE 00
Serial2.write(0);
Readbyte_MEMS(&data);
// Serial.println(data);
//iNIT CODE F9
Serial2.write(0xF9);
Readbyte_MEMS(&data);
// Serial.println(data);
//iNIT CODE CA
Serial2.write(0xCA);
Readbyte_MEMS(&data);
// Serial.println(data);
//iNIT CODE 75
Serial2.write(0x75);
Readbyte_MEMS(&data);
// Serial.println(data);
//iNIT CODE D0
Serial2.write(0xd0);
delay(100);
//Read Model
result = false;
count = 0;
while(Serial2.available()!=COMMANDD0){
count++;
if(count >10000){
return(result);
}
};
if(count == COMMANDD0){
return(result);
}
for(i=0;i<COMMANDD0;i++){
readdata[i]= Serial2.read();
}
//Medel表示
for (j = 0; j < ModelNum; j++) {
count = 0;
for (i = 0; i < COMMANDD0 ; i++) {
if (i == 0) continue;
if (MEMScode[j][i - 1] == readdata[i] ) {
count++;
if (count == (COMMANDD0-1) ) {
lcd.setCursor(0+xpos, 1-ypos);
lcd.printf("%s", MEMSModel[j]);
// Serial.printf("I=%d j=%d data=%s \n",i,j,MEMSModel[j]);
result = true;
break;
} else {
// Serial.printf("I=%d j=%d\n",i,j);
continue;
}
}
}
if (result == true) {
break;
}
}
//Medelが見つからなかったときは、コード表示
if (j == ModelNum) {
lcd.setCursor(0+xpos, 1-ypos);
for (i = 0; i < COMMANDD0; i++) lcd.printf("%02X", readdata[i]);
}
memsconnect=true;
return(true);
}
void setup() {
// シリアル初期化
Serial.begin(115200);
while (!Serial);
// Serial2.begin(9600, SERIAL_8N1, 17, 16); //ピンを指定して使用する場合
Serial2.begin(9600, SERIAL_8N1, UARTRX, UARTTX); //ピンを指定して使用する場合
while (!Serial2);
#if defined(ESP32S3)
Wire.begin(I2CSDA , I2CSCL);
lcd.begin(false); // initialize the lcd
lcd.backlight();
lcd2.begin(false); // initialize the lcd
lcd2.backlight();
#else
lcd.begin(); // initialize the lcd
lcd.backlight();
lcd2.begin(); // initialize the lcd
lcd2.backlight();
#endif
#if defined(LCDKEY)
lcd3.begin(16, 2); //LCD KEY SHIELDの初期化
delay(100);
lcd3.clear();
#endif
#if defined(OLEDESP)
// OLED Setuo
Wire1.begin(Wire1_SDA, Wire1_SCL);
//we must initialize rotary encoder
rotaryEncoder.begin();
rotaryEncoder.setup(readEncoderISR);
delay(250); // wait for the OLED to power up
if(!OLED1.begin(OLED_I2C_ADRS, true)) {
Serial.println(F("SH1106 OLED allocation failed"));
for(;;); // Don't proceed, loop forever
}
// OLEDに初期表示バッファの内容を表示する
// ライブラリはこれをAdafruitスプラッシュ画面で初期化する
OLED1.display();
delay(2000); // 2秒待つ
OLED1.clearDisplay();
OLED1.display();
OLED1.setTextSize(1); // フォントサイズを1~で指定
OLED1.setTextColor(SH110X_WHITE); // フォント色
//set boundaries and if values should cycle or not
//in this example we will set possible values between 0 and 1000;
rotaryEncoder.setAcceleration(250); //or set the value - larger number = more accelearation; 0 or 1 means disabled acceleration
// rotaryEncoder.correctionOffset=8; //try with zero or ROTARY_ENCODER_STEPS/8
// rotaryEncoder.isButtonPulldown = false;
// rotaryEncoder.areEncoderPinsPulldownforEsp32 = true;
bool circleValues = false;
rotaryEncoder.setBoundaries(0, 1000, circleValues); //minValue, maxValue, circleValues true|false (when max go to min and vice versa)
rotaryEncoder.setEncoderValue(500);
/*Rotary acceleration introduced 25.2.2021.
* in case range to select is huge, for example - select a value between 0 and 1000 and we want 785
* without accelerateion you need long time to get to that number
* Using acceleration, faster you turn, faster will the value raise.
* For fine tuning slow down.
*/
//rotaryEncoder.disableAcceleration(); //acceleration is now enabled by default - disable if you dont need it
//KEY Setuo
t_key.lastcount=500;
button1.lastMillis=millis();
button2.lastMillis=millis();
button1.pressed=false;
button2.pressed=false;
pinMode(button1.PIN,INPUT_PULLUP);
pinMode(button2.PIN,INPUT_PULLUP);
attachInterrupt(button1.PIN, isr,FALLING);
attachInterrupt(button2.PIN, isr2,FALLING);
#endif
// LittleFSのセットアップ
if (!LittleFS.begin(true)) {
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
#ifdef AP_Mode
WiFi.mode(WIFI_MODE_AP); // or WIFI_MODE_APSTA
WiFi.softAP(ssid, password);
delay(100);
WiFi.softAPConfig(ip, ip, subnet);
IPAddress myIP = WiFi.softAPIP();
Serial.print("SSID= ");
Serial.println(ssid);
Serial.print("Fixed IP addr= ");
Serial.println(myIP);
Serial.println("Server starting!");
#else
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
//WIDI 接続を10秒待つ
unsigned long ftm = millis() + 10 * 1000;
while ((WiFi.status() != WL_CONNECTED) & (millis() < ftm)) {
Serial.print('*');
delay(500);
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
#endif
lcd.setCursor(0, 0); // move cursor the first row
lcd.print("www.misago.com"); // print message the fourth row
// lcd2.setCursor(0, 0); // move cursor the first row AT Second LCDS
// lcd2.print("Hello!!"); // print message the fourth row
Serial.println("Init Start");
InitMEMS();
testruning=false;
lcd.setCursor(17+xpos, 1-ypos);
lcd.print("Dis");
// GETリクエストに対するハンドラーを登録
// rootにアクセスされた時のレスポンス
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/index.html", String(), false, processor);
});
// style.cssにアクセスされた時のレスポンス
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/style.css", "text/css");
});
// 画像にアクセスされた時のレスポンス
server.on("/deto", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/deto.jpg", "image/jpeg");
});
// リロードボタンにアクセスされた時のレスポンス
server.on("/RELOAD", HTTP_GET, [](AsyncWebServerRequest * request) {
request->redirect("/");
});
// Viewリロードボタンにアクセスされた時のレスポンス
server.on("/RELOAD2", HTTP_GET, [](AsyncWebServerRequest * request) {
request->redirect("/VIEW");
});
// クリアボタンにアクセスされた時のレスポンス
server.on("/BUTTON", HTTP_GET, [](AsyncWebServerRequest * request) {
request->redirect("/");
});
// viewにアクセスされた時のレスポンス
server.on("/VIEW", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/view.html", String(), false, processor);
});
// HWWRESETにアクセスされた時のレスポンス
server.on("/HWRESET", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/memsclear.html", String(), false, processor);
});
// HWtestにアクセスされた時のレスポンス
server.on("/HWTEST", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/memstest.html" );
});
// STEPPINGにアクセスされた時のレスポンス
server.on("/STEPPING", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/stepping.html", String(), false, processor);
});
// Fuel Pumpにアクセスされた時のレスポンス
server.on("/FUELPUMP", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/fuelpump.html", String(), false, processor);
});
// AC RELAYにアクセスされた時のレスポンス
server.on("/ACRELAY", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/acrelay.html", String(), false, processor);
});
// O2 Heaterにアクセスされた時のレスポンス
server.on("/O2HEATER", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/o2heater.html", String(), false, processor);
});
// PTCにアクセスされた時のレスポンス
server.on("/PTCRELAY", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/ptcrelay.html", String(), false, processor);
});
// PURGEにアクセスされた時のレスポンス
server.on("/PURGEVALVE", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/purgevalve.html", String(), false, processor);
});
// IDAVDにアクセスされた時のレスポンス
server.on("/IGADV", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/igadv.html", String(), false, processor);
});
// TRIMにアクセスされた時のレスポンス
server.on("/TRIM", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/trim.html", String(), false, processor);
});
// IDELにアクセスされた時のレスポンス
server.on("/IDEL", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(LittleFS, "/idel.html", String(), false, processor);
});
// ESP32_WebServer start
server.begin();
Serial.println("ESP32_WebServer start!");
#if defined(LCDKEY)
lcd3.setCursor(0,0); //カーソルの移動
lcd3.print(firstitems[firstitem]);
#endif
Serial.println("Init end");
#if defined(OLEDESP)
OLED1.setCursor(0,1);
OLED1.clearDisplay();
OLED1.println("Please select item");
OLED1.println(firstitems[0]);
OLED1.display();
#endif
delay(1000);
}
#if defined(OLEDESP)
/*
#define KEYRIGHT 0
#define KEYUP 1
#define KEYDOWN 2
#define KEYLEFT 3
#define KEYSELECT 4
#define KEYNONE 5
#define KEYERR 6
*/
int read_encoder(void)
{
//dont print anything unless value changed
if (rotaryEncoder.encoderChanged())
{
rolayvalue=rotaryEncoder.readEncoder();
if ( (t_key.lastcount -rolayvalue) > 3 ){
t_key.lastcount = rolayvalue;
t_key.key = KEYRIGHT;
return(KEYRIGHT);
}
if ( (t_key.lastcount -rolayvalue) < -3 ){
t_key.lastcount = rolayvalue;
t_key.key = KEYLEFT;
return(KEYLEFT);
}
}
// if (rotaryEncoder.isEncoderButtonClicked())
// {
// rotary_onButtonClick();
// }
// PUSH BACK
if ( button1.pressed ==true ){
button1.pressed =false;
t_key.key = KEYUP;
return(KEYUP);
}
// PUSH COMFIRM
if ( button2.pressed ==true ){
t_key.key = KEYSELECT;
button2.pressed =false;
return(KEYSELECT);
}
// t_key.key = KEYNONE;
return(KEYNONE);
}
#endif
int CheckConnect(void) {
int result = false,count=0,readdata1,readdata2,receive=0;
//iNIT CODE F4
Serial2.write(0xF4); // f4=nop
delay(50);
do {
receive= Serial2.available();
count = count + 1;
if (count > 50000) {
break;
}
} while (receive< 2);
// Serial.printf("F4 readnum=%d\n",receive);
if (receive != 2 ) {
return (result);
}
//Serial2に受信データの結果読み出し(0xf400)
readdata1= Serial2.read();
readdata2= Serial2.read();
if (readdata1 == 0xF4 && readdata2 == 0x00) {
result = true;
}
return (result);
}
void CheckFaultcode(void) {
lcd.setCursor(8+xpos, 3-ypos*2);
lcd.printf("Fcode:");
//Fault codeの確認
if ((int)data.frame.faultcodes1 == 0 && (int)data.frame.faultcodes2 == 0) {
lcd.setCursor(15+xpos, 3-ypos*2);
lcd.printf("NoErr");
return;
}
error1.faultcode1 = data.frame.faultcodes1;
if (error1.b.coolanttempsensor != 0) {
lcd.setCursor(15+xpos, 3-ypos*2);
lcd.printf("C ");
}
if (error1.b.inletairtempsensor != 0) {
lcd.setCursor(16+xpos, 3-ypos*2);
lcd.printf("I ");
}
error2.faultcode2 = data.frame.faultcodes2;
if (error2.bb.fuelpumpcircuit != 0) {
lcd.setCursor(17+xpos, 3-2*ypos);
lcd.printf("F ");
}
if (error2.bb.throttlepotcircuit != 0) {
lcd.setCursor(18+xpos, 3-2*ypos);
lcd.printf("T ");
}
if (error2.bb.mapsensor != 0) {
lcd.setCursor(19+xpos, 3-2*ypos);
lcd.printf("M");
}
}
/*********************/
/* keypad入力処理 */
/*********************/
#if defined(LCDKEY)
int red_key()
{
int i;
int r;
int key;
r = KEYERR;
key = analogRead(KEY_AD);
// lcd3.setCursor(0,0); //カーソルの移動
// lcd3.print(key);
if( key > THNONE ) r = KEYNONE;
else {
for( i = 0; i < 5; i++ ) {
if( key < t_key[i].dat ) {
r = t_key[i].ret;
break;
}
}
}
return( r );
}
/*********************/
/* 入力Key表示 */
/*********************/
void prn_key(int key)
{
lcd3.setCursor(0,1); //カーソルの移動
switch (key) {
case KEYRIGHT:
lcd3.print("RIGHT ");
break;
case KEYLEFT:
lcd3.print("LEFT ");
break;
case KEYUP:
lcd3.print("UP ");
break;
case KEYDOWN:
lcd3.print("DOWN ");
break;
case KEYSELECT:
lcd3.print("SELECT ");
break;
case KEYNONE:
lcd3.print("NONE ");
break;
case KEYERR:
lcd3.print("ERROR ");
break;
default:
break;
}
}
#endif
void loop() {
int i;
unsigned long start_time = 0 ; // タイムアウト監視開始時間
#if defined(LCDKEY)||defined(OLEDESP)
int key1,changekey, readdata1, readdata2;
#endif
// MEMSとの接続確認
if (testruning == true ){
testitem=NOTEST;
switch(runtestitem){ //HW診断の実行
case STEPPINGNUM:
if(steppingtest() ==false){
testitem=STEPPINGFINISHNG;
}else{
testitem=STEPPINGFINISHOK;
}
testruning = false;
runtestitem = NOTEST;
return;
case FUELPUMPNUM:
if(relaytest( 0x11 ,0x01 ) == false ){ // FUEL PUMP test
testitem=FUELPUMPFINISHNG;
}else{
testitem=FUELPUMPFINISHOK;
}
testruning = false;
runtestitem =NOTEST;
return;
case ACRELAYNUM:
if(relaytest( 0x13 ,0x03 ) == false ){ // AC RELAY test
testitem=ACRELAYFINISHNG;
}else{
testitem=ACRELAYFINISHOK;
}
testruning = false;
runtestitem =NOTEST;
return;
case O2HEATERNUM:
if(relaytest( 0x19 ,0x09 ) == false ){ // O2HEATER RELAY test
testitem=O2HEATERFINISHNG;
}else{
testitem=O2HEATERFINISHOK;
}
testruning = false;
runtestitem =NOTEST;
return;
case PTCRELAYNUM:
if(relaytest( 0x12 ,0x02 ) == false ){ // PTC RELAY test
testitem=PTCRELAYFINISHNG;
}else{
testitem=PTCRELAYFINISHOK;
}
testruning = false;
runtestitem =NOTEST;
return;
case PURGEVALVENUM:
if(relaytest( 0x18 ,0x08 ) == false ){ // VERGEVALVE RELAY test
testitem=PURGEVALVEFINISHNG;
}else{
testitem=PURGEVALVEFINISHOK;
}
testruning = false;
runtestitem =NOTEST;
return;
}
}
if (CheckConnect() == true) {
lcd.setCursor(17+xpos, 1-ypos);
lcd.printf("Con");
//データーフレーム(0x80)の読み出し
Serial2.write(0x80);
start_time = millis();
// 開始前の時刻を取得
while(Serial2.available() < COMMAND80){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
// Serial.printf("receivenum=%d \",Serial2.available());
}
// Serial.printf("receive finalnum=%d \n",Serial2.available());
for(i=0;i<COMMAND80;i++){
data.frame80[i] =(uint8_t)Serial2.read();
}
//MEMSの電圧表示
lcd.setCursor(0, 2-ypos);
lcd.printf("%4.1fV", 0.1 * (float)data.frame.batteryvoltage);
//MEMSの環境温度
lcd.setCursor(6, 2-ypos);
lcd.printf("W:%3d", (int)data.frame.intakeairtemperature - 55);
lcd.setCursor(11, 2-ypos);
lcd.write(0xdf);
lcd.write('C');
//MEMSの水温
lcd.setCursor(14, 2-ypos);
lcd.printf("A:%2d", (int)data.frame.coolanttemperature - 55);
lcd.setCursor(18, 2-ypos);
lcd.write(0xdf);
lcd.write('C');
//MEMSが管理しているエンジン回転数
lcd.setCursor(0+xpos, 3-2*ypos);
lcd.printf("%04dRPM", (int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2);
CheckFaultcode();
#if defined(LCD40X4)
lcd.setCursor(0, 2);
lcd.printf("Coil%6.3fmV", 0.002*((float)(data.frame.coiltime1 * 256) + (float)data.frame.coiltime2));
lcd.setCursor(13, 2);
lcd.printf("AF:%4.1f", (float)data2.frame.airfuelratio / 10);
lcd.setCursor(21, 2);
lcd.printf("Jackcount:%3d", (int)data2.frame.jackcount);
#endif
//Idel position
lcd2.setCursor(0, 0);
lcd2.printf("Ipos:%03d", (int)data.frame.idleaircontrolmotorposition);
//Idel speed
lcd2.setCursor(9, 0);
lcd2.printf("IdelEr%05d", (int)data.frame.idlespeed1 * 256 + (int)data.frame.idlespeed2);
//スロットル開度
lcd2.setCursor(0+xpos, 1-ypos);
lcd2.printf("Tp:%5.1f", (float)(data.frame.throttlepotvoltage) / 250 * 100); //Throttle pot voltage, 0.02V per LSB. WOT should probably be close to 0xFA or 5.0V.
lcd2.write('%');
//進角
lcd2.setCursor(10+xpos, 1-ypos);
lcd2.printf("IgAd:%05.1f", -24.0 + 0.5 * (float)data.frame.ignitionadvance); //Ignition 0.5 degrees per LSB with range of -24 deg (0x00) to 103.5 deg (0xFF)
//Coil time
// lcd2.setCursor(0, 2);
// lcd2.printf("Ctime:%4.1f",0,002*((float)data.frame.coiltime1*256+ (float)data.frame.coiltime2)); //Ignition 0.5 degrees per LSB with range of -24 deg (0x00) to 103.5 deg (0xFF)
//データーフレーム(0x7D)の読み出し
Serial2.write(0x7d);
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < COMMAND7D){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
// Serial.printf("7D num=%d \n",Serial2.available());
}
// Serial.printf("7D finalnum=%d \n",Serial2.available());
}
for(i=0;i<COMMAND7D;i++){
data2.frame7d[i] =(uint8_t)Serial2.read();
}
//Map sensoe
lcd2.setCursor(0, 2-ypos);
lcd2.printf("Map:%03d", (int)data.frame.mapsensorvalue);
// lambda_voltage(mV)
lcd2.setCursor(8, 2-ypos);
lcd2.printf("Lamda:%4dmV", 5 * (int)data2.frame.lambdasensorvoltage); // 5mV per LSB
//Closeloop:0 for open loop and nonzero for closed loop
lcd2.setCursor(0+xpos, 3-2*ypos);
lcd2.printf("Cloop:");
if (data2.frame.loopindicator == 0) {
lcd2.setCursor(6+xpos, 3-2*ypos);
lcd2.printf("Open ");
} else {
lcd2.setCursor(6+xpos, 3-2*ypos);
lcd2.printf("Close");
}
//Short_trim
lcd2.setCursor(11+xpos, 3-2*ypos);
lcd2.printf("Trim:%3d%", data2.frame.shorttermtrim); //1% per LSB
} else {
lcd.setCursor(0, 0); // move cursor the first row
lcd.print("www.misago.com"); // print message the fourth row
lcd.setCursor(17+xpos, 1-ypos);
lcd.print("Dis");
#if defined(LCD40X4)
for (i = 1; i < 4; i++) {
lcd.setCursor(0, i);
lcd.print(" ");
lcd.setCursor(20, i);
lcd.print(" ");
}
for (i = 0; i < 4; i++) {
lcd2.setCursor(0, i);
lcd2.print(" ");
lcd2.setCursor(20, i);
lcd2.print(" ");
}
#else
for (i = 2; i < 4; i++) {
lcd.setCursor(0, i);
lcd.print(" ");
}
for (i = 0; i < 4; i++) {
lcd2.setCursor(0, i);
lcd2.print(" ");
}
#endif
InitMEMS();
}
#if defined(LCDKEY)
key1 = red_key();
if( lastTimekey != key1){ // 入力に変化あり
changekey = key1;
start_time = millis();
do{ //チャタリング対策
key1 = red_key();
if ( (millis()- start_time > 200 ) && (changekey == key1) )break;
}while( true );
// prn_key( key1 );
lastTimekey = key1;
}
switch (lastTimekey) {
case KEYRIGHT:
if(position ==0 ){
if(firstitem < 4){
firstitem++;
lcd3.setCursor(0,0); //カーソルの移動
lcd3.print(firstitems[firstitem]);
}
}else if(position == 1) {
if( seconditem < 5 ) {
seconditem++;
lcd3.setCursor(0,0); //カーソルの移動
lcd3.print(hwtestitems[seconditem]);
}
}
break;
case KEYUP:
if(position != 0) {
position--;
}
testitem=NOTEST;
lcd3.setCursor(0,0); //カーソルの移動
if (position == 1 )lcd3.print(hwtestitems[seconditem]);
if (position == 0 )lcd3.print(firstitems[firstitem]);
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print(" ");
break;
case KEYDOWN:
break;
case KEYLEFT:
if(position == 0) {
if( firstitem !=0) {
firstitem--;
lcd3.setCursor(0,0); //カーソルの移動
lcd3.print(firstitems[firstitem]);
}
}else if(position == 1) {
if( seconditem !=0) {
seconditem--;
lcd3.setCursor(0,0); //カーソルの移動
lcd3.print(hwtestitems[seconditem]);
}
}
break;
case KEYSELECT:
if(position == 0) {
position++;
if( firstitem ==1) {
lcd3.setCursor(0,0); //カーソルの移動
lcd3.print(hwtestitems[seconditem]);
}else{
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Execution ?(S)");
}
break;
}else if(position == 1){
if( firstitem ==1) {
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Execution ?(S)");
position++;
}else{
switch( firstitem ){
case 0:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Execute Reset ");
if( memsconnect == false){
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Not connect MEMS");
return;
}else{
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0){
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Running Engine ");
}else{
//シリアルのBUFFERのから読み
while(Serial2.available() !=0 )Serial2.read();
//iNIT CODE CC
Serial2.write(0xCC); // f4=Fault code reset
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) {
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("No response0xCC");
return;
}
//Serial2に受信データの結果読み出し(0xCC00)
readdata1= Serial2.read();
readdata2= Serial2.read();
if (readdata1 == 0xCC && readdata2 == 0x00) {
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("HW RESET OK ");
}else{
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("HW RESET NG ");
}
}
}
break;
case 2:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Execute TRIM ");
break;
case 3:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Execute Idel SP");
break;
case 4:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Execute Ig Adv ");
}
}
}else if(position == 2){
if( memsconnect == false){
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Notconnect MEMS");
break;
}else{
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0){
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Running engine ");
break;
}
}
testitem=NOTEST;
testruning = true;
switch( seconditem ){
case 0:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Exec Stepping ");
runtestitem=STEPPINGNUM;
break;
case 1:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Exec Fuelpump ");
runtestitem=FUELPUMPNUM;
break;
case 2:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Exec AC Relay ");
runtestitem=ACRELAYNUM;
break;
case 3:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Exec O2Heater ");
runtestitem=O2HEATERNUM;
break;
case 4:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Exec PTC Relay ");
runtestitem=PTCRELAYNUM;
break;
case 5:
lcd3.setCursor(0,1); //カーソルの移動
lcd3.print("Exec PurgeValve");
runtestitem=PURGEVALVENUM;
break;
}
}
// case THNONE:
default:
if(position != 2)break;
lcd3.setCursor(0,1);
switch (testitem){
case STEPPINGFINISHNG:
lcd3.print("Stepping Error ");
break;
case STEPPINGFINISHOK:
lcd3.print("Stepping OK ");
break;
case FUELPUMPFINISHNG:
lcd3.print("FUELPUMP Error ");
break;
case FUELPUMPFINISHOK:
lcd3.print("FUELPUMP Ok ");
break;
case ACRELAYFINISHNG:
lcd3.print("AC Relay Error ");
break;
case ACRELAYFINISHOK:
lcd3.print("AC Relay Ok ");
break;
case O2HEATERFINISHNG:
lcd3.print("O2 Heater Error");
break;
case O2HEATERFINISHOK:
lcd3.print("O2 Heater Ok ");
break;
case PTCRELAYFINISHNG:
lcd3.print("PTC RELAY Error");
break;
case PTCRELAYFINISHOK:
lcd3.print("PTC RELAY Ok ");
break;
case PURGEVALVEFINISHNG:
lcd3.print("PurgeValveError");
break;
case PURGEVALVEFINISHOK:
lcd3.print("PurgeValve Ok ");
}
}
#endif
#if defined(OLEDESP)
lastTimekey=read_encoder();
OLED1.clearDisplay();
/*debug OLED1.setCursor(0,3*8+1);
OLED1.println(lastTimekey);
OLED1.println(firstitem);
OLED1.println(position);
*/
OLED1.setCursor(0,1);
// OLED1.clearDisplay();
OLED1.println("Please select item");
switch (lastTimekey) {
case KEYRIGHT:
if(position ==0 ){
if(firstitem < 4){
firstitem++;
}
OLED1.print(firstitems[firstitem]);
}else if(position == 1) {
if( seconditem < 5 ) {
seconditem++;
}
OLED1.print(hwtestitems[seconditem]);
}
break;
case KEYUP:
rotaryEncoder.setEncoderValue(500);
t_key.lastcount=500;
if(position != 0) {
position--;
}
testitem=NOTEST;
if (position == 1 )OLED1.print(hwtestitems[seconditem]);
if (position == 0 )OLED1.print(firstitems[firstitem]);
break;
case KEYLEFT:
if(position == 0) {
if( firstitem > 0) {
firstitem--;
}
OLED1.print(firstitems[firstitem]);
}else if(position == 1) {
if( seconditem > 0) {
seconditem--;
}
OLED1.print(hwtestitems[seconditem]);
}
break;
case KEYSELECT:
rotaryEncoder.setEncoderValue(500);
t_key.lastcount=500;
if(position == 0) {
position++;
if( firstitem ==1) {
OLED1.print(hwtestitems[seconditem]);
}else{
OLED1.println(firstitems[firstitem]);
OLED1.print("Execution ?(S)");
}
break;
}else if(position == 1){
if( firstitem ==1) {
OLED1.println(firstitems[firstitem]);
OLED1.print("Execution ?(C)");
position++;
}else{
switch( firstitem ){
case 0:
OLED1.println(firstitems[firstitem]);
OLED1.println("Execute Reset ");
if( memsconnect == false){
OLED1.print("Not connect MEMS");
return;
}else{
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0){
OLED1.print("Running Engine ");
}else{
//シリアルのBUFFERのから読み
while(Serial2.available() !=0 )Serial2.read();
//iNIT CODE CC
Serial2.write(0xCC); // f4=Fault code reset
start_time = millis(); // 開始前の時刻を取得
while(Serial2.available() < 2 ){
if ( (millis() - start_time) > 2000 ) {
break ; // 2000 mS 受信がなければループを抜ける
}
}
if (Serial2.available() != 2 ) {
OLED1.print("No response0xCC");
return;
}
//Serial2に受信データの結果読み出し(0xCC00)
readdata1= Serial2.read();
readdata2= Serial2.read();
if (readdata1 == 0xCC && readdata2 == 0x00) {
OLED1.print("HW RESET OK ");
}else{
OLED1.print("HW RESET NG ");
}
OLED1.display();
delay(2000);
}
}
break;
case 2:
OLED1.print("Execute TRIM ");
break;
case 3:
OLED1.print("Execute Idel SP");
break;
case 4:
OLED1.print("Execute Ig Adv ");
}
break;
}
}else if(position == 2){
if( memsconnect == false){
OLED1.print("Notconnect MEMS");
break;
}else{
webcount=(int)(data.frame.enginespeed1 * 256) + (int)data.frame.enginespeed2;
if( webcount !=0){
OLED1.print("Running engine ");
break;
}
}
testitem=NOTEST;
testruning = true;
switch( seconditem ){
case 0:
OLED1.print("Exec Stepping ");
runtestitem=STEPPINGNUM;
break;
case 1:
OLED1.print("Exec Fuelpump ");
runtestitem=FUELPUMPNUM;
break;
case 2:
OLED1.print("Exec AC Relay ");
runtestitem=ACRELAYNUM;
break;
case 3:
OLED1.print("Exec O2Heater ");
runtestitem=O2HEATERNUM;
break;
case 4:
OLED1.print("Exec PTC Relay ");
runtestitem=PTCRELAYNUM;
break;
case 5:
OLED1.print("Exec PurgeValve");
runtestitem=PURGEVALVENUM;
break;
}
}
// case THNONE:
default:
if (position == 1 ){
if (firstitem == 1 ){
OLED1.println(hwtestitems[seconditem]);
}else{
OLED1.println(firstitems[firstitem]);
OLED1.print("Execution ?(C)");
}
}
if (position == 0 )OLED1.println(firstitems[firstitem]);
if(position != 2)break;
if(testitem == NOTEST && testruning == false && firstitem ==1 ){
OLED1.clearDisplay();
OLED1.setCursor(0,1);
OLED1.println("Please select item");
OLED1.println(firstitems[firstitem]);
OLED1.println(hwtestitems[seconditem]);
OLED1.print("Execution ?(C)");
}
switch (testitem){
case STEPPINGFINISHNG:
OLED1.print("Stepping Error ");
break;
case STEPPINGFINISHOK:
OLED1.print("Stepping OK ");
break;
case FUELPUMPFINISHNG:
OLED1.print("FUELPUMP Error ");
break;
case FUELPUMPFINISHOK:
OLED1.print("FUELPUMP Ok ");
break;
case ACRELAYFINISHNG:
OLED1.print("AC Relay Error ");
break;
case ACRELAYFINISHOK:
OLED1.print("AC Relay Ok ");
break;
case O2HEATERFINISHNG:
OLED1.print("O2 Heater Error");
break;
case O2HEATERFINISHOK:
OLED1.print("O2 Heater Ok ");
break;
case PTCRELAYFINISHNG:
OLED1.print("PTC RELAY Error");
break;
case PTCRELAYFINISHOK:
OLED1.print("PTC RELAY Ok ");
break;
case PURGEVALVEFINISHNG:
OLED1.print("PurgeValveError");
break;
case PURGEVALVEFINISHOK:
OLED1.print("PurgeValve Ok ");
}
}
OLED1.display();
#endif
delay(400);
}
最近のコメント