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! | Project14 Home | |
Monthly Themes | ||
Monthly Theme Poll |
This project started as a cry for help from a good friend in Australia (yes I know we keep bagging the Australians, but he's handy to stay with in Melbourne)
He had just purchased a second hand vehicle and one of the previous owners had added electric fans.
While the actual fan mounting wasn't the issue, the large wires and horrible toggle switch hanging out the dash was.
There was also the issue of a lack of any automation, and the thought that his partner or someone else driving it might forget about the switch.
Sensor
As luck would have it, I'd just finished playing with my Temperature Light project and had already done most of the preliminary work.
I had used a common analogue sensor (Facet 7.3005) with a negative temperature co-efficient (resistance gets lower as it gets hotter), and this project required that I drive a relay.
To read the analogue voltage, 5v is fed via a 150 ohm pullup resistor to the sensor and A0 junction.
As the temperature of the vehicle climbs, the resistance and therefore the voltage goes lower.
I did some calibration using a previous Arduino sketch that I did when I replaced the thermostat in the fridge.
The new thermostat needed adjusting so I had it display on an LCD. (it later formed part of the code for this Arduino, Temperature, LCD and more )
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.
You can do some math and work out the voltage based on 5v, 150 ohm and the sensor resistance reading, or simply use a resistance substitute to get a figure from the AnalogRead of the pin.
In the end my figures were
90 degs C = 2.07v and AnalogRead = 424
100 degs C = 1.84v and AnalogRead = 377.
Hardware
The Arduino cannot drive a 30A relay on it's own, so a transistor was needed.
We also decided that a dash mounted LED would give feedback about what was happening.
It also required connections that my friend could easily connect the various wires to, rather than soldering.
Rather than use a shield, I decided to use a Freetronics Eleven. https://www.freetronics.com.au/products/eleven#.Wsa20H_YWUk
This includes a protyping area to house the components shown in the schematic below.
I do like these boards but it would be nice if more 3rd party suppliers copied it as the price here is a little high.
The removable chip was an advantage, as I could send him another with new code if there was a change needed.
Installation
For this vehicle there is no spare holes to fit the sensor, but luckily he had spotted an adaptor.
So after some cutting and no doubt some swearing, the sensor was attached.
Some people may have spotted that the photos show nothing for the body of the sensor to connect to the chassis or ground.
This was a mistake which got picked up in the software and responded exactly as planned.
Software
Driving an electric fan doesn't require a microcontroller and Facet make various temperature switches that provide a closure when the temperature is exceeded.
This is the design flaw with these normally open switches and control solutions.
If the wire breaks or becomes disconnected, you don't get a warning light or the fans operating ie they are NOT fail to Safe.
So the software detects that the sensor is attached and will signal an error code and operate the relay to turn the fans ON.
I achieved this by checking the reading on A0 and if it was greater than 1000 it was deemed to be open circuit.
If the reading was less than 50, the software determined the sensor was shorted.
We weren't exactly sure what temperature to switch the fans on, so I allowed for a calibration mode that would write the value into the EEPROM for future.
The LED is used to signal to the driver what is happening, and it changes depending on the mode it's in.
I decided to give the driver some confidence by operating the fans and LED for 5 secs when the vehicle starts, but otherwise it is off until it get warm and it operates the fan and the LED is on.
If it continues to get hotter the LED flashes.
The picture below shows all the modes and indications.
Code
As with all my sketches I include lots of comments and how to connect it.
It saves trying to find that piece of paper you put in a safe place when want to build it again, or use parts of the code.
/* ELECTRIC FAN CONTROLLER This uses a common sender (Facet 7.3005) to detect the temperature and switch the Fan Relay It uses the value to detect if the sender is 'shorted' or 'open' and flashes an error code. The Fan Relay output is tuned ON at the HOT setting (currently approx 95 deg) and the light comes ON If the temp increases then the light flashes :- NORMAL Off HOT (90deg) ON BOIL (100deg) Flashes A 'Set' feature is incorporated to set the Fan On temperature Pin assignments Pin 0 Rx Pin 1 Tx Pin 2 Fan Relay Output Pin 3 Temp/Status Light/LED 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 Apr 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 boolean FanRelayState = LOW; // Fan Relay Output state 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/Cal Button counter //inputs int StartButton = 4; int CalButton = 6; int TempSender = 0; int val = 0; //----------------------------------------------- //Outputs int TempLight = 3; // PWM int FanRelay = 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 6 = waiting for Cal Button release */ //------------------------------------------------------------------------- void setup() { Serial.begin(57600); //Define the inputs pinMode (CalButton, INPUT); digitalWrite (CalButton, HIGH); //Define the outputs pinMode(LEDPin, OUTPUT); pinMode(TempLight, OUTPUT); pinMode(FanRelay, 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) { HOT = val; //Plug the value into HOT which is the Fan On setting) } 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() { 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 'HOT' 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 Fan ON 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 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); // Write it to EEPROM 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. Turns ON the fan because we can't tell what the Temperature is. It should stay in this mode, until reset by power on/off. */ { FanRelayState = HIGH; digitalWrite(FanRelay, FanRelayState); //Turn FAN ON because we don't know what temerature it is. while (Mode ==3) { 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 ==4) { 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; } } } } void DisplayTemp() { /* The Temp Light follows the LEDPin (13) and comes On when the fan Relay is ON. When the Temp reaches 100 (BOIL) deg it flashes. */ // temp below HOT if (TempSender >= (HOT + 20)) // value is greater than HOT // we add 20 to the HOT Value here to give a range before turning Off { ledState = LOW; FanRelayState = LOW; } // HOT temp if (TempSender > BOIL && TempSender <= HOT) // greater than HOT (90 deg or the Calibrated value) { ledState = HIGH; FanRelayState = HIGH; } // BOIL temp if (TempSender <= BOIL) // value is less than BOIL { FanRelayState = HIGH; 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; } } } digitalWrite(LEDPin, ledState); digitalWrite(TempLight, ledState); digitalWrite(FanRelay, FanRelayState); }
edit 17 April 2018 ... forgot to declare StartButton ...added in Line 88
Safety systems
The final picture shows the LED mounted in the dash to the right of the radio, and the horrible switch neatly shoved back into the hole.
Going back to our earlier picture .... showing the sensor mounted in a plastic adaptor with no earth ...
I got a call from my friend after a while and he said it wasn't working, the LED keep flashing and the fans were ON all the time
He wasn't particularily worried as it wasn't overheating and he was driving it everyday.
What got missed in the conversation was that it was flashing the error code for the "Sender Open", and I thought it was the "Hot" flash mode.
I looked back at his photos and then asked about the earth wire ....
So it's nice to know that the protections you put in place work.
Video
This will be difficult as the vehicle got written off.
I'm going to have to do another and use an off the shelf relay rather than the Freetronics board.
So hopefully this proves the concept works rather than just this particular build
Last Laugh
As many followers will know I'm strictly a GM person, and my friend is a strictly Ford person.
I didn't have the heart to tell him that the sensor (Facet 7.3005) is designed for GM vehicles and it was looking after his Ford.
Cheers
Mark
Top Comments