Open Arduino

Enter Your Project for a chance to win a grand prize for the most innovative use of Arduino or a $200 shopping cart! The Birthday Special: Arduino Projects for Arduino Day!

Back to The Project14 homepage

Project14 Home
Monthly Themes
Monthly Theme Poll

 

I used to own a 1966 Pontiac and typical of the times, they had few guages and used warning lights.

These were often referred to as "Idiot Lights".

 

For the most part they worked ... except.

  • No method of checking the lamp wasn't blown.
  • No means to check the wire hadn't broken, or fallen off the sender.
  • The temperature that triggered the light was usually greater than 100 deg C (ie more than boiling).

So there were several ways this thing could fail and you wouldn't know about it.

 

 

 

Temperature

Anyone that stayed awake during science may recall that water boils at 100 deg C ... unless it's under pressure.

All vehicle cooling systems are under pressure and often it's around 15 psi before it will release the contents.

 

According to the chart here https://durathermfluids.com/pdf/techpapers/pressure-boiling-point.pdf

The boiling point is raised by 20 degC at 15psi.

 

So many of the idiot light senders are actually higher than 100 degC, and rely on the cooling system having pressure to work correctly.

 

I've experienced a hole in the hose, water pumped out and it got hot once before in another vehicle.

By the time it smelt hot and the cause was discovered, the heat had done the damage and that motor had to be rebuilt.

I really wasn't interested in having that happen in the 66.

 

 

 

Better Indication

The usual trick is to add a temperature guage hanging under the dash somewhere.

While this works if you have spare water jacket holes, I didn't like it, and I wasn't going to drill holes in the dash, or fit it underneath.

 

There was no means of adding something into the guage cluster, which meant somehow making the existing 'Idiot Light' more intelligent.

 

As everyone knows a flashing light means go faster, but it is also the best way to get attention, and thats why they always have a flashing light where there is a sale.

 

 

In modern cars the warning lights come on for a period when you start the vehicle, and surprise surprise this is so you can tell the ones that aren't working.

I bet there are some people right now going    "oh that's why they light up"   

 

So we have the idea.

Comes on when it starts for confidence, Flashes to warn it's getting HOT, and On when it is really hot,  .... easy.

I decided to add one more stage and that was Fade while the engine temperature was cold and it was still warming up.

Just to ensure the driver has every warning possible, there are some error codes as well.

 

 

 

Hardware

I'd been dealing with DS18B20's and use them whenever I can, but no-one makes one that can be screwed in and seals (not for 15psi).

 

I could have pulled apart another sender or made something, but it was easier to buy an automotive analogue sender that was readily available.

I chose a Facet (7.3005) from a local supplier.

It needed an adaptor for the chosen hole, but these are a readily available part.

I removed some of the adaptor thread, to ensure more of the sender was in the water flow, for quicker response.

 

it was duly fitted and the original wire connected back to it.

 

 

I had to find out what the resistance of the sender was at the various temperatures, so I waited until someone was at work, and 'borrowed' the kitchen.

CloseClose Close

  The kitchen is not my normal habitat, except for making a drink, so I wasn't sure how things would go, but the recipe was simple.

  • Place in water
  • apply moderate heat
  • note resistance readings at various temperatures until the water boiled.

 

 

The results went into an Excel spreadsheet and I noted the reading as it was heating up, and cooling down.

From those the voltage and analogRead values were worked out by substituting the resistance.

 

 

The controller chosen was an Arduino but since I was going to do more with this, I added a shield for connections and interface components.

 

The regulator is a 7808 since vehicle charging can go as high as 15v, and many of the Arduino board regulators that aren't rated that high.

I call it insurance from spikes or other nasties in a vehicle.

 

One of the transistors drives the existing light, and the onboard LEd gets covered, so I added one on top.

The Calibrate button allows the user to adjust the normal temperature point (ie when it stops fading). The default was 65 degC.

 

So with the hardware sorted, it was time to write a sketch.

 

 

 

 

Software

I had always planned the Arduino to do TWO seperate functions, and therefore there could be no delays in the main code.

I also needed to be careful about the variable names used, as I was going to 'mix' the two sketches later.

 

The code below has some other buttons defined, but are not shown for this use.

 

To add the proper 'Fail to Safe' checks the software detects the sender is shorted, or open and flashes a code accordingly.

Not much point in having more intelligence if you don't do something about it.

 

 

The calibrate routine is done when the vehicle igntion is first turned on.

If the calibrate input is held LOW it assumes you want to calibrate and changes the operating mode of the software.

The intention was to set the NORMAL value, and the chnage is written to the EEPROM.

 

In case anyone hasn't played with the EEPROM, it doesn't get overwritten when you load a new sketch.

You have to clear it, so if you use that Arduino board in another project, run the EEPROM clear sketch.

 

The observed brightness of a PWM lamp and a LED are quite different.

The lamp has a steep and more logarithmic brightness curve while the LED tends to flatten quite early.

So when you do testing, try to simulate the working condition as much as possible.

 

 

 

Code

 

/*
    
    WATER TEMPERATURE LIGHT (vehicles)
    This uses a common sender (Facet 7.3005) to detect the Water Temperature.
    It uses the value to detect if the sender is 'shorted' or 'open' and flashes an error code.
    It controls the Water Temperature Light to show :-
        Below NORMAL    Fades up
        NORMAL          Off
        HOT (90deg)     Flashes
        BOIL (100deg)   ON
        
    A calibrate feature is incorporated to set the NORMAL temperature
    There are no delays used, so it can run a second function.
    
    
      Automotive Series
      1. Water Temperature Light
      2. Variable Wiper
      3. Electric Fan Controller (using the same hardware parts).
      
     Flags for the various modes in Intelligent Temp Light are used, to allow the controller to service the other functions.  
    
     Pin assignments
     Pin 0  Rx
     Pin 1  Tx
     Pin 2  Wiper Relay Output
     Pin 3  Temp Light Output
     Pin 4  Start Button Input
     Pin 5  Stop Button Input
     Pin 6  Cal Button Input
     Pin 10 
     Pin 13 Led
     Pin A0 Temp Sender Input              (Uses a Facet 7.3005 fed with 150 Ohm from 5v.)
     Pin A4 
     
     Series created 1 Aug 2011
     by Mark Beckett
     
     Sender is a Facet 7.3005 from Auto Agencies, Rangiora see http://www.autoagencies.co.nz/
     
     Version
     0.1  Initial Code  started 01 Feb 2012
    
     ---------------------------------------------------
     To Do :
   
    
    ******************************************
    I make no apologies for the code used in the sketch below.
    The series is designed to help introduce novice programmers (including me), and as such code that can be followed is more important.
    The sketch takes very little space, and is mostly waiting for something to happen, so speed is not required.
    
    Also I fix things for a living, rather than write software, so to all you programmers ....sorry
    
    Mark Beckett
    *****************************************
    */
      
    
    #include 
  
    
    // General Purpose
    
      unsigned long LastChange =0;            // Used in flashing/toggling the Temp light
      unsigned long LastTempLightOn = 0;      // Time the Temp Light was turned On.
      unsigned long LastTempLightOff = 0;     // Time the Temp light was turned Off.
      unsigned long LightTimerTime = 0;       // Used in Timer(), for Fading Temp Light.
      unsigned long LastTempRead = 0;         // Time the Temp was read.
  
      int FadeValue = 0;                      // used to set the fade level.
      int LastErrorCount = 0;                 // Error counter.
      int FlashCount = 0;                     // used in DisplayMODE to count flashes.
      int TempLightOffTime = 2000;            // Time the Temp Light is Off   [2 seconds]
      int TempLightOnTime = 500;              // Time the Temp Light is On   [0.5 seconds]
      int ledState = LOW;                     // ledState used to set the LED
      int Mode = 0;                           // Mode for function 0= normal, 2= cal, 3= Open, 4= Shorted
      int NORMAL = 598;                       // 65 deg (or from the EEPROM later)
      int HOT = 424;                          // 90 deg
      int BOIL = 377;                         // 100 deg
      
      int n1=0;                               // used to hold 100's of the TempSender value before writing to EEPROM
      int n2=0;                               // used to hold 10's of the TempSender value before writing to EEPROM
      int n3=0;                               // used to hold 1's of the TempSender value before writing to EEPROM
      
      // Button handling variables
      unsigned long LastButtonCheck = 0;      // Time the Buttons were last checked.
      unsigned long ButtonPressTime = 0;      // Time the last button was pressed.      
      boolean StartButtonState = HIGH;        // records the StartButton State
      boolean CalButtonState = HIGH;          // records the CalibrateButton State
      int StartCount = 0;                     // Start Button counter  
      
      //inputs
      int StartButton = 4;
      int StopButton = 5;
      int CalButton = 6;
      int TempSender = 0;
      int val = 0;
    
    //-----------------------------------------------
    
      //Outputs
      int TempLight = 3;                  // PWM 
      //int Wiper = 2;
      const int LEDPin = 13;              // Pin 13  LED Output
    
    
    //------------------------------------------------
    
    //Settings
    /*
      Default values are 
      NORMAL (65 deg)   = 2.92v   [598]
      HOT (90 deg)      = 2.07v   [424]
      BOIL (100 deg)     = 1.84v   [377] 
      
      Mode
      0 = normal
      1 = Power On Self Test (POST)
      2 = Cal
      3 = Open circuit sensor [> 1000]
      4 = Shorted sensor      [< 50] 
      5 = Value set  
      
    */
    
    //-------------------------------------------------------------------------
    
    
    void setup() 
    {
    
      Serial.begin(57600);
  
      //Define the inputs
     pinMode (CalButton, INPUT);
     digitalWrite (CalButton, HIGH);
     pinMode (StartButton, INPUT);
     digitalWrite (StartButton, HIGH);
     pinMode (StopButton, INPUT);
     digitalWrite (StopButton, HIGH);
      //Define the outputs
    
     pinMode(LEDPin, OUTPUT);
     pinMode(TempLight, OUTPUT);
    
      //Set the default values
    
      PowerUp();    
    }
    
    void PowerUp()
    /*  This runs once at power up.
        Checks to see if the CAL Button is pressed.
        Checks to see if there is an Error in reading the Sender value.
        Turns output ON for 5 secs, if everything is okay.
    */
    {
    CalButtonState = digitalRead(CalButton);
    if (CalButtonState == LOW)
    {
      delay(100);      //check to see the button is pressed by waiting 100mS (We can accept a delay here)
      CalButtonState = digitalRead(CalButton);
      if (CalButtonState == LOW)
      {
        Mode = 2;          // Cal mode
        Calibrate();      // Go and do the calibrate proceedure
      }
    }
    
    //check EEPROM address to see if a figure is written there
    val = 100 * (EEPROM.read(1));        //check value at address 1
    val = val + 10 * (EEPROM.read(2));        //check value at address 1
    val = val + (EEPROM.read(3));        //check value at address 1
    if (val !=0)
    {
      NORMAL = val;
    }

    ReadTemp();           // Go and check the Temp Sender for Errors. (Mode = 0 for normal) 
  
      if (Mode == 0)      // checking for Errors (Mode = 0 is normal)
      { 
        digitalWrite(LEDPin, HIGH);
        digitalWrite(TempLight, HIGH);
        ledState = HIGH;
        LastTempLightOn = millis();                 // Note when we turned On
        Mode = 1;                                   // set this to allow detection of POST mode
      } 
     
       do      // While Mode is 1, we keep checking the time. Normally we should do something else, but not during POST 
               // We don't want to read the Temperature while the car may be getting started. 
       {
          if ((millis() - LastTempLightOn) > 5000)    // should be 5 secs
          {
            digitalWrite(LEDPin, LOW);
            digitalWrite(TempLight, LOW);
            ledState = LOW;
            LastTempLightOff = millis();           // Note when we turned Off
            Mode = 0;                              // set this back to normal
          }
       } while (Mode == 1);          // use the == otherwise Mode gets set to 1.
       
      if (Mode == 3)      // checking for Errors (Mode = 3 Open circuit sensor [> 1000])
       { 
        DisplayMODE();
      }
      if (Mode == 4)      // checking for Errors (Mode = 4 Short circuit sensor [< 50])
      { 
        DisplayMODE();
      }
    }
    
    void loop() 
    {

      // ***** used in Variable Wiper sketch DON'T MIX UP THE VARIABLES *****
      // Check_Buttons();                                        //used for Int wiper
      Timer();                                                //See what is needed to be done
  
    }
    
    void Timer()
    {
      
       if (Mode == 0)        // use the == otherwise Mode gets set to 0.
       {
         if ( (millis() - LastTempRead) > 500)      // only need to check every 0.5 secs
         {
           ReadTemp();
          }
         LastErrorCount = 0;      //No more errors so reset it.
         DisplayTemp();
       }
       else
       {
         DisplayMODE();
       }

    }
    
    void ReadTemp()
    {
      /* 
       The Temp Sender is fed via a 150 ohm resistor from the 5v line. This results in a voltage between 1.7 and 3.6 v.
       If the voltage is 4v or 1v, then an error is displayed.
       A power off is required to reset an error condition.
       
       Default values are used if the EEprom hasn't been written to with Calibrated/Altered values.
       ************** NOTE loading a new sketch doesn't overwrite the EEPROM values ***********
    
       */
      TempSender = analogRead(A0);
      
      if (TempSender > 1000)             // Temp Sender open circuit
      {
        LastErrorCount ++;
        if (LastErrorCount == 4);
        {
          Mode = 3;
        }
      }
        
      if (TempSender < 50)             // Temp Sender short circuit
      {
        LastErrorCount ++;
        if (LastErrorCount == 4);
        {
          Mode = 4;
        }
      }
      
      LastTempRead = millis();           // Note the time since we only need to check every 0.5 secs at the most.
     return; 
    }
    
    void Calibrate()
    {
      /* This process allows the 'Normal' value to be altered and stored in the EEprom.
         Default values are based on a Facet 7.3005 sender (Auto Agencies, Rangiora see http://www.autoagencies.co.nz/)
         CAL is held low and the unit is powered up.
         The Temp Light (and LED) is flashed 2 times, pause for 2-3 secs, then repeated to show CAL mode until a mode is set.
           
            Press START sets the NORMAL temp.
                
         The unit will change to flash 5 times, pause for 1 sec and repeat to show its saved the new value.
         (It will ignore any further button pressing.)
    
         Note An error will prevent the Cal mode being set.
         
         We assume that the user knows when the temperature has reached the thermostat opening temperature, and when it
         reaches that temp the user press'es the Start button to set it.
         You only get to set the new temperature ONCE. Simply power down to attempt again.
         
         ****** NOTE: If the EEPROM has been written to, it doesn't clear when you load a new sketch. !!! ************
         
       */
      while(Mode == 2)
      {
        if (millis() - LastButtonCheck > 5)                      // Reads button state every 5mS and then updates button counts
        {
          StartButtonState = digitalRead(StartButton);
          LastButtonCheck = millis(); 
            if (StartButtonState == LOW)
            {
              StartCount ++;                                      // Increment the Count by 1
              if (StartCount > 10)                                // the button should be LOW for 10x5mS = 50mS
              {
                StartCount = 0;
                Mode =5;                                          // change Mode to drop out the while loop
                //write the TempSender value to EEPROM
                ReadTemp();                                       // ReadTemp() has a return at the end, so we should come back to here, unless there is a fault.
                
                // Below is not an elegant way of breaking the number up, but a novice programmer can follow it
                n1 = (TempSender/100);
                n2 = (TempSender -(n1*100))/10;
                n3 = (TempSender -(n2*10)) - (n1*100);
                EEPROM.write(1, n1);
                EEPROM.write(2, n2);
                EEPROM.write(3, n3);
              }
            }
        }
  
        if(millis() - LastChange > 300)
        {
          LastChange = millis();     // save the last time you blinked the LED
          if (FlashCount <=2)
          {
            if (ledState == LOW)    // if the LED is off turn it on and vice-versa:
            {
              ledState = HIGH;
              FlashCount ++;
            }
            else
            {
              ledState = LOW;
            }
          }
          if (FlashCount >2)
          {
            ledState = LOW;
            FlashCount ++;
          }
             
          // set the LED and Temp Light with the ledState of the variable:
          digitalWrite(LEDPin, ledState);
          digitalWrite(TempLight, ledState);
          if (FlashCount >=10)
          {
            FlashCount =0;
          }
        }
      }
  
      while (Mode ==5) 
      {
       if(millis() - LastChange > 300)
        { 
          LastChange = millis();     // save the last time you blinked the LED
          if (FlashCount <=5)
          {
             if (ledState == LOW)    // if the LED is off turn it on and vice-versa:
             {
               ledState = HIGH;
               FlashCount ++;
             }
             else
             {
               ledState = LOW;
             }
          }
          if (FlashCount >5)
          {
            ledState = LOW;
            FlashCount ++;
          }
           
          // set the LED and Temp Light with the ledState of the variable:
          digitalWrite(LEDPin, ledState);
          digitalWrite(TempLight, ledState);
          if (FlashCount >=10)
          {
            FlashCount =0;
          }
        }
      }
       
    }
    
     
    void DisplayMODE()
      /*
      Flashes the Temp Light to show an error.
      It should stay in this mode, apart from the other purposes for the controller.
      */
    
    {
      do 
      {
       if(millis() - LastChange > 300)
        { 
          LastChange = millis();     // save the last time you blinked the LED
          if (FlashCount <=3)
          {
             if (ledState == LOW)    // if the LED is off turn it on and vice-versa:
            {
              ledState = HIGH;
              FlashCount ++;
            }
            else
            {
              ledState = LOW;
            }
          }
          if (FlashCount >3)
          {
            ledState = LOW;
            FlashCount ++;
          }
           
          // set the LED and Temp Light with the ledState of the variable:
          digitalWrite(LEDPin, ledState);
          digitalWrite(TempLight, ledState);
          if (FlashCount >=10)
          {
            FlashCount =0;
          }
        }
      }
      while (Mode ==3);
      
      do 
      {
       if(millis() - LastChange > 300)
        { 
          LastChange = millis();     // save the last time you blinked the LED
          if (FlashCount <=4)
          {
             if (ledState == LOW)    // if the LED is off turn it on and vice-versa:
            {
              ledState = HIGH;
              FlashCount ++;
            }
            else
            {
              ledState = LOW;
            }
          }
          if (FlashCount >4)
          {
            ledState = LOW;
            FlashCount ++;
         }
    
          // set the LED and Temp Light with the ledState of the variable:
          digitalWrite(LEDPin, ledState);
          digitalWrite(TempLight, ledState);
          if (FlashCount >=10)
          {
            FlashCount =0;
          }
        }
      }
      while (Mode ==4);
    }
    
    void DisplayTemp()
   {
      /* 
       The Temp Light continually fades up until the NORMAL value is reached, when it goes Off.
       When the Temp reaches 90 deg it flashes.
       If the Temp reaches 100 deg it stays ON.
    
    */
    
    // below NORMAL temp
      if (TempSender > NORMAL)    // value is greater than NORMAL value (65 deg or calibrate setting)
      {
        if ((millis() - LightTimerTime) > 25)
        {
          if (FadeValue < 255)
          {
            FadeValue ++;
            //FadeValue ++;      //uncomment this if you want the Light to brighten quicker (steps two steps each cycle)
          }
          else
          {
            FadeValue = 0;
          }
          LightTimerTime = millis();
          analogWrite(TempLight, FadeValue);
        }
      }
     
      else 
      {
        // NORMAL temp
        if (TempSender <= NORMAL && TempSender >= HOT)    // value is greater than HOT but less than NORMAL value
        {
          ledState = LOW;
          FadeValue = 0;    
        }
      
      // HOT temp
      if (TempSender > BOIL && TempSender <= HOT)    // greater than HOT (90 deg)
      {   
        if(millis() - LastChange > 150)    // change every 150mS which should be a xxHz flash
        {
          LastChange = millis();     // save the last time you blinked the LED
          if (ledState == LOW)
              ledState = HIGH;
          else
              ledState = LOW;
        }
      }
      // BOIL temp
      if (TempSender <= BOIL)    // value is less than BOIL
      {
        ledState = HIGH;
      }
      
      digitalWrite(LEDPin, ledState);
      digitalWrite(TempLight, ledState);
     }
   }

 

 

 

VIDEO

While I no longer own the vehicle any more, I can simulate the code.

I might even have another guage that will suffice.

 

It's not everyone that has a spare dash ...

 

This demonstrates the process from turn on to warming and then hot and back, inc when the sensor becomes disconnected.

 

 

 

In the meantime the images and code might give someone an idea.

 

 

 

Mark