RFID/NFC with Engine Start Button

A lot of people have been telling me that I should add RFID to my engine start button project. That’s exactly what I did. I’m using an Arduino Nano connected to a  RC522 RFID reader/writer. When the Nano recognizes a scanned RFID tag, it sends a code via serial to the ATMega328 that controls the ignition/accessories/starter motor.  When the ATMega328 receives the code, it enables the engine start functionality. If no RFID tag is scanned or if an incorrect tag is scanned,  pressing the engine start button will not start the engine.

MVI_1672-001
My first test of this setup.


 

Arduinos and RFID module installed on the bottom steering column cover.
I can start my car with my NFC enabled phone.
I can start my car with my NFC enabled phone.

The code for the main Arduino(engine start button controller):

// (C) 2014-2016 Scott Hubble. NOT FOR COMMERCIAL USE.
//Push button ignition switch for automobiles.
//Made for 1988-2000 Honda Civic/CRX, but may be adapted to other vehicles.
//By Scott Hubble. Original version started 2114 Aug. 11.
//Ver. 6.5

// USE AT YOUR OWN RISK!

//UPDATE: 2014 Aug. 16 - Added LED output for button illumination.
//UPDATE: 2014 OCT. 2 - Changed for standalone Atmega.
//UPDATE: 2016 Feb. 6 - Changed for RFID.
//UPDATE: 2016 Feb. 13 - Changed the value of "autoS" to "A2" from "0".

int esb = 3; // Engine Start Button.
int unlock = 2; //'Okay to start' signal input.
int autoS = A2; //Auto-start signal input.
int accOut = 9; //Accessory output.
int ignOut = 8; //Ignition output.
int ig2Out = 6; //Ignition IG2A and IG2B output.
int stOut = 7; //Starter output.
int ledPin = 12; //LED for button illumination.
int accLed = 11; //ACC indicator.
int onLed = 13; //ON indicator.

long unsigned time = 0; // Timer for LED flash.
int ledStat = 0; //LED status.
int auto1 = 0;
int ledFlash = 0;
int ledFlash2 = 0;
int ledOn = 0;
int esbStat = 0; //Was the primary switch pressed?
int unlockStat = 0; // Secondary switch pressed?
int did = 0; //Keep track of operation.
int did2 = 0; //Keep track of non-starter operation.
int did3 = 0;
int on = 0;
int on2 = 0;

void setup()
{
  pinMode(esb, INPUT);
  pinMode(unlock, INPUT);
  pinMode(autoS, INPUT);
  pinMode(accOut, OUTPUT);
  pinMode(ignOut, OUTPUT);
  pinMode(ig2Out, OUTPUT);
  pinMode(stOut, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(accLed, OUTPUT);
  pinMode(onLed, OUTPUT);
  time = millis();
  digitalWrite(accOut, HIGH);
  digitalWrite(ignOut, HIGH);
  digitalWrite(ig2Out, HIGH);
  digitalWrite(stOut, HIGH);
  digitalWrite(accLed, HIGH);
  digitalWrite(onLed, HIGH);
  digitalWrite(ledPin, HIGH);
}

void loop()
{
  int auto1 = digitalRead(autoS);
  // -------------------------Read the bottons:-----------
  if(digitalRead(esb) == HIGH && esbStat == 0){
    esbStat = 1;
    on = 1;
    delay(90);
  }
  if(digitalRead(esb) == LOW && esbStat == 1){
    esbStat = 0;
    on = 0;
    delay(90);
  }
  
  
  if(digitalRead(unlock) == HIGH && unlockStat == 0){
    unlockStat = 1;
    on2 = 1;
    delay(90);
  }
  if(digitalRead(unlock) == LOW && unlockStat == 1){
    unlockStat = 0;
    on2 = 0;
    delay(90);
  }
  
  //############################# AUTO-START ##################################
  switch (auto1) {
  case HIGH:
    if(did == 0){
    digitalWrite(ledPin,LOW);// LED on.
    digitalWrite(ignOut, LOW); //Write LOW to activate relay.
    delay(2000); // Delay to allow fuel pump to prime.
    digitalWrite(stOut, LOW); // Activate starter relay.
    delay(1500); // Let starter cranck for 1.5 seconds.
    digitalWrite(ledPin, HIGH);//LED off.
    ledOn = 1;
    did = 1;
    did2 = 0;
    did3 = 1;
    ledOn = 1;
    
    break;
    }
}
//############################## END AUTO-START ##################################

  //--------------------Operation:---------------------------
  if(on == 1 && on2 == 1 && did == 0){ // Start engine, IGN on.
    digitalWrite(accOut, HIGH);//ACC relay off.
    digitalWrite(ignOut, LOW); //Write LOW to activate relay.
    digitalWrite(stOut, LOW); // Starter relay on.
    did = 1;
    did2 = 0;
    did3 = 1;
    ledOn = 1;
  }
  
  if(on == 0 && did == 1){ //Starter off.
    digitalWrite(stOut, HIGH); //Starter relay off.
    digitalWrite(ig2Out, LOW); // IG2A/B on(climate controls, etc...)
    digitalWrite(onLed, LOW); //ON LED on.
    did = 2;
  }
  
  if(did == 2 && on == 0){ //ACC on after engine start.
    digitalWrite(accOut, LOW); //ACC relay on.
    digitalWrite(accLed, HIGH); //ACC LED off.
    did = 3;
  }
  
  if(did == 3 && on == 1){ //Turn everything off:
    digitalWrite(ignOut, HIGH);
    digitalWrite(ig2Out, HIGH);
    digitalWrite(accOut, HIGH);
    digitalWrite(onLed, HIGH);
    digitalWrite(accLed, HIGH);
    did = 4;
    ledOn = 0;
    ledStat = 0;

  }
  
  if(did == 4 && on == 0){ //Reset variables:
    did = 0;
    did2 = 0;
    did3 = 0;
  }
  //-----------------NON STARTER OPERATION--------------------
  
  if(on == 1 && on2 == 0 && did2 == 0 && did3 == 0){ //Push for ACC
    digitalWrite(accOut, LOW);
    digitalWrite(accLed, LOW);
    did2 = 1;
    ledOn = 1;
  }
  
  if(on == 0 && did2 == 1 && did3 == 0){
    did2 = 2;
  }
  
  if(did2 == 2 && on == 1 && on2 == 0){ //IGN without start
    digitalWrite(ignOut, LOW);// Ignition relay on.
    digitalWrite(ig2Out, LOW);// Ignition 2 relay on.
    digitalWrite(onLed, LOW);// ON LED on.
    digitalWrite(accLed, HIGH); //ACC LED off.
    did2 = 3;
  }
  
  if(on == 0 && did2 == 3 && did3 == 0){
  did2 = 4;
  }
  
  if(did2 == 4 && on == 1 && on2 == 0){ //ALL SYSTEMS OFF:
    digitalWrite(ignOut, HIGH);
    digitalWrite(ig2Out, HIGH);
    digitalWrite(accOut, HIGH);
    digitalWrite(accLed, HIGH);
    digitalWrite(onLed, HIGH);
    did2 = 5;
    ledOn = 0;
    ledStat = 0;
  }
  
  if(did2 == 5 && on == 0){ //Reset variable:
    did2 = 0;
  }
  //-----------------LED OUTPUT/BUTTON FLASH/illum.-------------------
  if(ledOn == 1 && ledStat == 0){
  digitalWrite(ledPin, HIGH);
  ledStat = 1;
  
  // LED flash while everything is off:
  }else if(millis() - time > 5000 && ledOn == 0 && unlockStat == 0){
    digitalWrite(ledPin, LOW);
    time = millis();
    ledFlash = 1;
  }
  if(millis() - time > 200 && ledFlash == 1 && ledOn == 0 && unlockStat == 0){
    digitalWrite(ledPin, HIGH);
    time = millis();
    ledFlash = 0;
  }
  
  if(unlockStat == 1 && esbStat == 0 && ledOn == 0){//LED flash while waiting to start engine:
    digitalWrite(ledPin, LOW);
    delay(50);
    digitalWrite(ledPin, HIGH);
    delay(60);
  }
}

Code for the Arduino Nano connected to a  RC522 RFID reader/writer:

//2016 Feb. 6 - Scans RFID tags. If a matching tag is found,
//sends HIGH signal to another Arduino.
//Basically, a slightly modified version of the Addicore RFID demo sketch.
#include 
#include 
#define	uchar	unsigned char
#define	uint	unsigned int

//4 bytes tag serial number, the first 5 bytes for the checksum byte
uchar serNumA[5];
uchar fifobytes;
uchar fifoValue;
AddicoreRFID myRFID; // create AddicoreRFID object to control the RFID module

/////////////////////////////////////////////////////////////////////
//set the pins
/////////////////////////////////////////////////////////////////////
const int chipSelectPin = 10;
const int NRSTPD = 5;
int sign = 9;
int autoStart = 8;
//Maximum length of the array
#define MAX_LEN 16

void setup() {  
pinMode(sign, OUTPUT);
pinMode(autoStart, OUTPUT);
digitalWrite(sign, LOW);
   Serial.begin(9600);                        // RFID reader SOUT pin connected to Serial RX pin at 9600bps
  // start the SPI library:
  SPI.begin();
  
  pinMode(chipSelectPin,OUTPUT);              // Set digital pin 10 as OUTPUT to connect it to the RFID /ENABLE pin 
    digitalWrite(chipSelectPin, LOW);         // Activate the RFID reader
  pinMode(NRSTPD,OUTPUT);                     // Set digital pin 10 , Not Reset and Power-down
    digitalWrite(NRSTPD, HIGH);

  myRFID.AddicoreRFID_Init();  
}

void loop()
{
    uchar i, tmp, checksum1;
    uchar status;
    uchar str[MAX_LEN];
    uchar RC_size;
    uchar blockAddr;	//Selection operation block address 0 to 63
    String mynum = "";

    str[1] = 0x4400;
	//Find tags, return tag type
    status = myRFID.AddicoreRFID_Request(PICC_REQIDL, str);	
	

	//Anti-collision, return tag serial number 4 bytes
    status = myRFID.AddicoreRFID_Anticoll(str);
    if (status == MI_OK)
      {
        checksum1 = str[0] ^ str[1] ^ str[2] ^ str[3];
            
            // Should really check all pairs, but for now we'll just use the first
        if(str[0] == 123)//If the first string on the tag you scan is 123...
        {
          digitalWrite(sign, HIGH);//enable engine start...
          delay(5000);// for 5 seconds. after 5 seconds engine start is disabled. Pressing the ESB won't start the engine.
          digitalWrite(sign, LOW);//Turn off 'okay to start' signal.
        } else if(str[0] == 312|| str[0] == 321)//If scanned tag is 312 or 321, send 'auto-start' signal. 
        {        //You can change this to the first byte of your tag by finding the card's ID through the Serial Monitor.
          digitalWrite(autoStart, HIGH);//Send auto-start signal...
          delay(500);//...for half a second.
          digitalWrite(autoStart, LOW);//Turn off auto-start signal.
            } 
         
            delay(1000);
	}
		
        myRFID.AddicoreRFID_Halt(); //Command tag into hibernation              
}

Here’s a list of some items that I used in this project. I bought items from Amazon or eBay. You may also find most of these things on Adafruit and SparkFun.

  • Arduino Uno
  • Arduino Nano
  • RC522 RFID module
  • modified car USB charger.
  • SainSmart 8 channel relay module
  • engine start button from a 2012 Mazda 3 (you can use ANY momentary switch that you like)

I’m still working on a video for this. I find that I’m not great at making tutorials, and for that I apologize. I’ll try to improve the details here as I answer questions from curious people.

mm

Alloy Author

I have various hobbies, including automotive, electronics, and computer related things. Sometimes I write about these things here.

Leave a Reply