RickG
Published © GPL3+

Saab Oil Monitor Relay Restoration

Function of a 60's era Saab Oil Monitoring Relay restored with an Arduino Nano.

IntermediateFull instructions provided6 hours90
Saab Oil Monitor Relay Restoration

Things used in this project

Hardware components

Arduino Nano or equivalent
×1
PC817 Opto Coupler
×1
Mini MP1584EN or similar buck converter
×1
HiLetGo or similar One Channel Relay Module Relay Switch with OPTO Isolation High Low Level Trigger
×1
miscellaneous: wire, small heat shrink tubing, solder, GE Advanced 2 clear silicone caulk
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Schematic Diagram

Code

MonitorRelay2026-0.ino

Arduino
/***************************************************************************
**********
*Oil Injection Monitor rev 3 by Rick Gessner, Jan 2026
*This sketch emulates a classic car part. A 60s era SAAB Monte Carlo utilized
*a monitoring relay that checked the operation of an oil injection pump and 
*illuminated a dashboard light if a problem occurred. 
*The pump is mechanically driven by the engine. When the pump is actuated, a monitor
*switch closes to ground for a short time. 
*The pump switch is connected to a digital input.
*A relay is attached to a processor digital output. 
*The sketch monitors the switch input for closures to ground. During 
*normal operation with the oil pump running, the sketch sees frequent changes of states on the 
*digital input and maintains the relay output high to keep the dash trouble light off. 
*
*If a fixed period passes without a change of the switch state, the ouput goes low to light
*the dash lamp. The output is held high to keep the lamp off so that, upon unit failure, 
*the light will go on (i.e. failsafe operation). 
*The relay connects the wire from the lamp to ground when it is off.
*
*The unit will be powered when the ignition key is turned on, Upon startup, a routine blinks the 
*lamp several times to show the unit is alive. 
*The onboard led (output 13) illuminates when the switch is closed as a troubleshooting aid.

/*
 
  This sketch is intentionally written using only the
  standard Arduino core API (pinMode, digitalRead,
  digitalWrite, millis, delay).

  Design goals:
  - Platform independence (Uno, Nano, Nano Every, etc.)
  - No direct register access (PORTx, DDRx)
  - No architecture-specific headers (avr/io.h)
  - Execution speed is not critical

  Assumptions:
  - 5V logic
  - Digital pins 12, 13 and 2 available

  Timing:
  - All timing uses millis()
  - Blocking delays are used only during startup

  Last verified on:
  - Arduino Uno (ATmega328P)
  - Arduino Nano
  - Arduino Nano Every (ATmega4809)
/**************************************************************************************/


unsigned long currentmillis;
unsigned long previousmillis=6000; //6000 to lenghen first test period
unsigned long elapsed;
unsigned long threshold=10000;
unsigned long deadtime=0;
bool switchstate;
bool switchstatelast=0; 


void setup() {
  // put your setup code here, to run once:
pinMode(12,OUTPUT); //set pins 12 and 13 as DOs for relay and on board LED
pinMode(13,OUTPUT);
pinMode(2, INPUT_PULLUP); //set pin 2 as input with pullup resistor on - for oil pump switch input

//On Wakeup, blink the lamp 3 times to show we're alive
//Outputs are low to turn light on
 for (int i = 0; i < 4; i++) {
    digitalWrite(12, LOW);
    digitalWrite(13, LOW);
    delay(1000);
    digitalWrite(12, HIGH);
    digitalWrite(13, HIGH);
    delay(1000);
  }

  digitalWrite(12, LOW);
  digitalWrite(13, LOW);
//Serial.begin(9600);   //development testing aid
 // Initialize switch state cleanly
 switchstatelast = digitalRead(2);
   
//Serial.begin(9600);   //enable for development testing aid
}

void loop(){
  // the main code here runs repeatedly:
currentmillis = millis(); //record the current milliseconds
elapsed = currentmillis - previousmillis; // elapsed is time since last milliseconds
switchstate = digitalRead(2); //record the status of the oil pump switch input

 digitalWrite(13, !switchstate);  //output 13 is the on board LED -- have it reflect the inverse switch state 

if (switchstate == switchstatelast) { // if the switch hasn't changed state, add elapsed to deadtime
  deadtime = deadtime + elapsed;} //deadtime is milliseconds since last switch state change
  else {deadtime = 0;} //if the switch changed state this scan, reset deadtime to zero


if (deadtime > threshold){ //if deadtime exceeds the threshold, turn the relay outputs off to light the dash lamp
  digitalWrite(12, LOW);
  deadtime = threshold + 1;} //limit deadtime so it won't overflow
  else {  //if the deadtime is less than threshold, keep the relay outputs high to keep dash lamp off
    digitalWrite(12, HIGH);
  }    
//Serial.print(deadtime);  //Enable the following lines for development testing aid
//Serial.print("   ");
//Serial.print(switchstate);
//Serial.print("   ");
//Serial.println(threshold);
//delay(100);   

//record the last switchstate and milliseconds for next scan 
switchstatelast = switchstate;
previousmillis = currentmillis;
}

Credits

RickG
1 project • 0 followers

Comments