// nissan200sx
// https://forum.arduino.cc/t/vehicle-immobiliser-with-auto-start-function-a-small-problem/1463704/13
#define SYSTEM METRIC // ENGLISH
#include "secrets.h" // contains pswd and measurement system
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#include <Keypad.h>
int ecuRelay = 4;
int ignitionRelay = 7;
int fuelPumpRelay = 8;
int starterRelay = 12;
int startButton = 5;
int buzzerPin = 3;
int analogPin = A0;
float val, oldval; // analog value
char customKey;
const byte ROWS = 4;
const byte COLS = 3;
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
byte rowPins[ROWS] = {31, 33, 35, 37};
byte colPins[COLS] = {39, 41, 43};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
unsigned long startTimer, startTimeout[] = {200, 800}; // for "PRESS START" blinker
unsigned long signinTimer, signinTimeout[] = {200, 800}; // for "SIGN IN" blinker
bool signed_in = 0; // help indicate when to blink "SIGN IN"
bool toggle; // for text blinkers
bool template_displayed = false, engine_started = false, welcome_displayed = false, tune_played = false;
// button reading
int buttonCount;
bool buttonReadOld, buttonState, start_button_pressed = false;
unsigned long buttonTimer, buttonTimeout = 50;
void setup() {
Serial.begin(115200); // bringing comms into the current century
Serial.println(); // handshake serial comms
lcd.init();
lcd.backlight();
createCustomLCDchars();
pinMode(ecuRelay, OUTPUT);
pinMode(ignitionRelay, OUTPUT);
pinMode(fuelPumpRelay, OUTPUT);
pinMode(starterRelay, OUTPUT);
digitalWrite(starterRelay, LOW);
pinMode(startButton, INPUT_PULLUP); // set pin HIGH using internal PULLUP
pinMode(analogRead, INPUT);
displayCarType();
}
void loop() {
//////////////////////////////////////////////////
// SIGN IN
//////////////////////////////////////////////////
if (signed_in == false) {// when not signed in
displaySignIn(); // blink "SIGN IN"
readKeypad(); // gather keypad presses
if (data_a_count == Password_a_Length - 1)
checkPasswordA();
if (data_b_count == Password_b_Length - 1)
checkPasswordB();
}
if (signed_in == true) { // successful sign in... begin engine start
if (welcome_displayed == false) // if welcome is not displayed
displayWelcome(); // WELCOM
if (template_displayed == false) // if template is not displayed...
displayRelayTemplate(); // RELAY TEMPLATE
if (engine_started == false) // until START button is pressed...
displayPressStart(); // PRESS START
displayECUvdc(); // read ECU input
readStartButton(); // read button
if (start_button_pressed == true)
displayStartingEngine();
delay(3000);
clearData();
}
}
void readKeypad() {
customKey = customKeypad.getKey();
if (customKey) {
Data_a[data_a_count] = customKey;
data_a_count++;
Data_b[data_b_count] = customKey;
data_b_count++;
}
}
void clearData() {
while (data_a_count != 0) {
Data_a[data_a_count--] = 0;
}
}
void checkPasswordA() {
if (!strcmp(Data_a, Master_a))
signed_in = true;
}
void displayWelcome() {
welcome_displayed = true;
lcd.setCursor(0, 0);
lcd.print("Driver 1 ");
if (tune_played == false) {
tune_played = true;
delay(50);
tone(buzzerPin, 2100, 300);
delay(100);
tone(buzzerPin, 2662.5, 50);
delay(90);
tone(buzzerPin, 3225, 120);
delay(50);
tone(buzzerPin, 4300, 80);
delay(1000);
}
}
void checkPasswordB() {
if (!strcmp(Data_b, Master_b)) {
lcd.setCursor(3, 0);
delay(250);
lcd.print("Welcome, Driver 2");
delay(50);
tone(buzzerPin, 2100, 80);
delay(85);
tone(buzzerPin, 2662.5, 50);
delay(90);
tone(buzzerPin, 3225, 50);
delay(100);
tone(buzzerPin, 4300, 50);
delay(100);
lcd.setCursor(3, 2);
lcd.print("Press To Start");
digitalWrite(ecuRelay, HIGH);
delay(1000);
digitalWrite(ignitionRelay, HIGH);
delay(1000);
digitalWrite(fuelPumpRelay, HIGH);
delay(3000);
digitalWrite(fuelPumpRelay, LOW);
delay(500);
}
}
////////////////////////////////////////////////////////////
// LCD DISPLAY STUFF
////////////////////////////////////////////////////////////
void displayStartingEngine() {
lcd.setCursor(6, 1);
lcd.print("Starting");
lcd.setCursor(7, 2);
lcd.print("Engine!");
tone(buzzerPin, 4300, 75);
delay(80);
tone(buzzerPin, 4300, 100);
delay(150);
digitalWrite(fuelPumpRelay, HIGH);
delay(1500);
if (val <= 2.5) {
digitalWrite(starterRelay, HIGH);
} else {
digitalWrite(starterRelay, LOW);
delay(3000);
}
}
void displayECUvdc() {
val = analogRead(analogPin); // read ECU voltage
val = (5. / 1023.) * val; // map to 0.0vdc to 5.0 vdc float
if (oldval != val) { // only when value changes
lcd.setCursor(17, 0);
lcd.print(val, 1); // analog value as float, one decimal place
}
oldval = val; // store new ECUvdc value
}
void displayRelayState() {
lcd.setCursor(17, 1);
if (digitalRead(ecuRelay) == HIGH)
lcd.print(F("ON"));
else
lcd.print(F("--"));
digitalWrite(ecuRelay, HIGH);
lcd.setCursor(17, 2);
if (digitalRead(ignitionRelay) == HIGH)
lcd.print(F("ON"));
else
lcd.print(F("--"));
digitalWrite(ignitionRelay, HIGH);
lcd.setCursor(17, 2);
if (digitalRead(fuelPumpRelay) == HIGH)
lcd.print(F("ON"));
else
lcd.print(F("--"));
digitalWrite(fuelPumpRelay, HIGH);
}
void displayRelayTemplate() {
template_displayed == true; // display template one time
lcd.setCursor(0, 1);
lcd.print(F("STRTrly"));
lcd.setCursor(0, 2);
lcd.print(F("FUELrly"));
lcd.setCursor(12, 0);
lcd.print(F("ECUv"));
lcd.setCursor(12, 1);
lcd.print(F("ECUr"));
lcd.setCursor(12, 2);
lcd.print(F("IGNr"));
}
void displayCarType() {
lcd.setCursor(10 - sizeof(car) / 2, 3); // center car name on bottom row
lcd.print(car);
}
void displaySignIn() {
if (millis() - signinTimer >= signinTimeout[toggle]) {
signinTimer = millis();
toggle = !toggle;
lcd.setCursor(0, 0);
if (toggle) {
lcd.print(F("SIGN IN"));
} else {
lcd.print(F(" "));
}
}
}
void displayPressStart() {
if (millis() - startTimer >= startTimeout[toggle]) {
startTimer = millis();
toggle = !toggle;
lcd.setCursor(0, 0);
if (toggle) {
lcd.print("PRESS START");
} else {
lcd.print(" "); // blank previous text
}
}
}
void createCustomLCDchars() { // create custom characters for meter deflection
lcd.createChar(0, gaugeL);
lcd.createChar(1, gaugeC);
lcd.createChar(2, gaugeR);
lcd.createChar(3, gauge2);
lcd.createChar(4, gauge3);
lcd.createChar(5, gauge4);
}
void displayRPM() {
lcd.setCursor(0, 1);
lcd.print(F("RPM"));
lcd.setCursor(3, 1);
lcd.write(0);
for (byte i = 0; i < 8; i++) {
lcd.write(1);
}
lcd.write(2);
}
void displaySpeed() {
lcd.setCursor(0, 2);
lcd.print(NAMSP);
lcd.setCursor(3, 2);
lcd.write(0);
for (byte i = 0; i < 8; i++) {
lcd.write(1);
}
lcd.write(2);
}
void readStartButton() {
bool buttonReadNow = digitalRead(startButton); // read button pin
if (buttonReadNow != buttonReadOld) { // if THIS read is not the same as LAST read...
buttonTimer = millis(); // ...start a timer by storing millis()
buttonReadOld = buttonReadNow; // ... and store current state
}
if ((millis() - buttonTimer) >= buttonTimeout) { // if button change was longer than debounce timeout (NOT NOISE)
if (buttonState == HIGH && buttonReadOld == LOW) { // ... and State is "NOT pressed" while Button "IS PRESSED"
//================================================== // The button WAS pressed... do something...
}
buttonState = buttonReadNow; // update button state for first if() condition test
}
}BUZ
START
ECU RELAY
IGN RELAY
FUEL RELAY
START RELAY
ECU VDC