// nissan200sx
// https://forum.arduino.cc/t/vehicle-immobiliser-with-auto-start-function-a-small-problem/1463704/13
#define MEASUREMENT_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 killButton = 6;
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(killButton, INPUT_PULLUP); // set pin HIGH using internal PULLUP
pinMode(startButton, INPUT_PULLUP); // set pin HIGH using internal PULLUP
pinMode(analogPin, INPUT);
displayCarType();
}
void loop() {
// not yet signed in
displaySignIn();
readKeypad();
checkSignedIn();
if (signedIn == true) {
displayRelayTemplate();
displayPressStart(); // PRESS START
displayECUvdc(); // read ECU input continuously
readStartButton(); // read start button continuously
displayStartingEngine();
// clearData();
}
}
void checkWelcomeDisplayed() {
if (welcome_displayed == false) { // flag for one-time "welcome" display
welcome_displayed = true; // set flag to stop displaying "welcome"
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 displaySignIn() {
if (signed_in == false) {// when not signed in, blink "SIGN IN"
if (millis() - signinTimer >= signinTimeout[toggle]) {
signinTimer = millis();
toggle = !toggle;
lcd.setCursor(0, 0);
if (toggle) {
lcd.print(F("SIGN IN")); // print the line
} else {
lcd.print(F(" ")); // blank the line
}
}
}
}
void readKeypad() {
if (signed_in == false) {// when not signed in
if (keypress_count == password_length)
checkPassword();
customKey = customKeypad.getKey();
if (customKey) {
keypadentry[keypress_count] = customKey;
keypress_count++;
}
}
}
// void clearData() {
// while (keypress_count != 0) {
// Data_a[keypress_count--] = 0;
// }
// }
void checkPassword() {
for (byte i = 0; i < passwords; i++) {
if (!strcmp(keypadentry, masterpass[i]))
signed_in = true;
}
checkWelcomeDisplayed();
displayStart();
playNotes();
}
void playNotes() {
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);
}
void displayStartingEngine() {
if (start_button_pressed == true) {
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);
digitalRead(ecuRelay) == HIGH ? lcd.print(F("ON")) : lcd.print(F("--"));
digitalWrite(ecuRelay, HIGH);
lcd.setCursor(17, 2);
digitalRead(ignitionRelay) == HIGH ? lcd.print(F("ON")) : lcd.print(F("--"));
digitalWrite(ignitionRelay, HIGH);
lcd.setCursor(17, 2);
digitalRead(fuelPumpRelay) == HIGH ? lcd.print(F("ON")) : lcd.print(F("--"));
digitalWrite(fuelPumpRelay, HIGH);
}
void displayRelayTemplate() {
if (template_displayed == false) {// if template was not displayed...
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 displayPressStart() {
if (engine_started == false) { // if START button was NOT pressed...
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
for (byte i = 0; i < gaugesize; i++) {
lcd.createChar(i, gaugechar[i]);
}
}
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
}
}
/*
Driver enters one of 2 available 6-digit codes followed by the hash key.
Ignition relay, ECU relay and Fuel pump relay activate - the Fuel pump
relay remains on only for 5 seconds, the others remain on indefinitely.
Display prompts driver to press start button, so button must be depressed
within a few seconds or the unit will need reset to try again.
With successful start button input, the display reads "starting engine",
and the fuel pump relay will activate again, and remain on until power off.
The starter relay will now activate, and remain energised until the value
from the potentiometer reads more than 2.5. This represents a voltage
supplied by the vehicles ECU. At this moment, the Starter relay should deactivate.
This would be the end of the program, and the unit should remain in this final state until power off.
1. enter password
2. if password invalid goto 1
3. activate ECU and ignition relay/LED/state (keep ECU on until power-off)
4. activate FUEL pump/relay/LED
5. start FUEL pump timer (5 seconds)
6. display "START"
7. if (pump timer > 5) display "timeout" goto 1
8. activate START relay, activate FUEL pump/relay/LED, display "STARTING"
9. start ECU timer
10. if (ECU timer > 5) and (ECU pot < 2.5) goto 1
11. deactivate STARTER
(engine run)
12. if KILL button, stop FUEL relay, stop ECU relay
*/
BUZZER
START
ECU RELAY
IGN RELAY
FUEL RELAY
START RELAY
ECU VDC
KILL