Arduino software for wipers and temp gauge projects

Controller I chose to use a shield (add-on board) to house all the parts for this project that allows the use of any standard Arduino and settled on a Seeeduino V3.0 and a Freetronics prototype shield as an inexpensive solution. I used the controller and shield to for the previous variable wiper speed project for the car (“Wipe that classic windscreen,” Shed, Apr/May 2012). This second part uses the same controller and shield to do both tasks. The reader can either make one or both. The shield construction includes the extra parts (two resistors, one transistor, and one diode) and uses the “Start” button to do the “Normal” calibration. Here are the two sketches (software) in these The Shed website's two posts. one combining water temperature light and variable wiper functions into one controller; and one that just does the water temperature light.

Controller
I chose to use a shield (add-on board) to house all the parts for this project that allows the use of any standard Arduino and settled on a Seeeduino V3.0 and a Freetronics prototype shield as an inexpensive solution.
I used the controller and shield to for the previous variable wiper speed project for the car (“Wipe that classic windscreen,” Shed, Apr/May 2012). This second part uses the same controller and shield to do both tasks. The reader can either make one or both. The shield construction includes the extra parts (two resistors, one transistor, and one diode) and uses the “Start” button to do the “Normal” calibration.
Here are the two sketches (software) in these The Shed website’s two posts.

  • one combining water temperature light and variable wiper functions into one controller; and
  • one that just does the water temperature light.

Sketche One
Automotive series, Intermittant Wiper

				
					console.log( 'Code is Poetry' );

/*
  Automotive Series
  
  Intermittant Wiper

  
 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 Ouput
 Pin 3  
 Pin 4  
 Pin 5  Stop Button Input
 Pin 6  Start Button Input
 Pin 10 
 Pin 13 Led
 Pin A0 
 Pin A4 
 
 Created Dec 2011
 by Mark Beckett
 
 Version
 1.0  Initial Code completed Dec 2011
 
 
 
 ---------------------------------------------------
 To Do :

 
 */


// General Purpose
int IntWipe = 0;                       // Flag to show we mode we are in. 0= off, 1= first press, 2= 2nd press.
int LedState = LOW;                    // ledState used to set the LED

unsigned long WipeInterval = 0;         // Time between wipes as set by start/stop action                            [x secs]
unsigned long LastWipeTime =0;          // Time the last wipe was started.
unsigned long TimerTime =0;             // used in Timer(), = millis()-LastWipeTime.
int ButtonTimeout = 30;                 // Timeout if no button is pressed. Note wipe interval is lower than this.   [30 seconds]
int RelayOnTime = 1500;                 // Time the relay is held on to perform a single wipe.                       [1.5 secs]
boolean WiperRelayState = LOW;          // Relay Output state

// 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
int StartCount = 0;                     // Start Button counter
boolean StopButtonState = HIGH;         // records the StopButton State
int StopCount = 0;                      // Stop Button counter


//inputs
int StartButton = 4;
int StopButton = 5;
int CalButton = 6;
int val = 0;

//Outputs
int WiperRelay = 2;                     // Wiper relay output
const int LEDPin = 13;                  // Pin 13  LED Output

//Settings

/* 
  Default values for the intermittant wiper
  Button timeout        = 30 secs
  ON time for relay     = 1.5 secs
  
*/
  
  
//-------------------------------------------------------------------------


void setup() 
{
  Serial.begin(115200);

  //Define the inputs
  pinMode (StartButton, INPUT);
  digitalWrite (StartButton, HIGH);
  pinMode (StopButton, INPUT);
  digitalWrite (StopButton, HIGH);
  
  //Define the outputs
  pinMode(LEDPin, OUTPUT);
  pinMode(WiperRelay, OUTPUT);

  ButtonTimeout = ButtonTimeout *1000;                    // Convert secs to milliseconds
  //RelayOnTime = RelayOnTime *1000;                      // Convert secs to milliseconds
}


void loop() 
{
  Check_Buttons();                                        //used for Int wiper
  Timer();                                                //See what is needed to be done
}

void Timer()
{
  // This controls the various routines and calls them as necessary
  TimerTime = millis() - LastWipeTime;
  
  if (((millis()-ButtonPressTime) > ButtonTimeout) && (IntWipe == 1))        // 30 Sec timeout for no button press, but only after stopped, or 1 start.
  {
    IntWipe = 0;
    LastWipeTime = 0;
    WipeInterval = 0;   
  }
      // The SingleWipe() will be called when the start button is pressed, we need to turn the relay off.
  if ((TimerTime > RelayOnTime) && WiperRelayState == true)    // RelayOnTime has been exceeded AND WipeRelay is HIGH
  {
    SingleWipe();                                          // It will turn off the relay and not modify any variables
  }
     
  // Time to wipe but only if there is a WipeInterval AND the relay is off.      
  if ((TimerTime > WipeInterval) && (IntWipe == 2) && WiperRelayState == false)       
  {
    SingleWipe();
  }
  
}

void Check_Buttons()
{
  if (millis() - LastButtonCheck > 5)                      // Reads button state every 5mS and then updates button counts
  {
    StartButtonState = digitalRead(StartButton);
    StopButtonState = digitalRead(StopButton);
    LastButtonCheck = millis(); 
    
    if (StartButtonState == LOW)
    {
      
      StartCount ++;                                      // Increment the Count by 1
      if (StartCount > 10)                                // the button should be LOW for 10x5mS = 50mS
      {
        ButtonPressTime = millis();                      // used for the Button press Timeout
        StartCount = 0;
        if (WiperRelayState == false)                    // No point in returning until its finished doing a wipe.
        {
          switch (IntWipe)
          {
            case 0:
              // not been pressed or fully stopped.
              IntWipe =1;
              SingleWipe();
            break;                                            // Escape from the switch, so we don't do the next one
            
            case 1:
              // single press or stop button pressed.
              IntWipe = 2;
              WipeInterval = (millis() - LastWipeTime);       // Time will be in mS
              SingleWipe();
            break;                                            // Escape from the switch, so we don't do the next one
            
            case 2:
              // 2nd press
              WipeInterval = (millis() - LastWipeTime);       // Time will be in mS
              SingleWipe();
            break;                                            // Escape from the switch, so we don't do the next one
          
          }
        }
      }
    }
    else                                                  // StartButton is HIGH
    {
      StartCount =0;
    }
    
    if (StopButtonState == LOW)
    {
      
      StopCount ++;
      if (StopCount >10)                                  // the button should be LOW for 50mS
      {
        ButtonPressTime = millis();                       // used for the Button press Timeout
        IntWipe = 1;
        StopCount = 0;
        WipeInterval = 0;
        LastWipeTime = millis();                          // Set the wipe timer, so when the start is pressed the interval will be right
      }
    }
    else                                                  // StopButton is HIGH
    {
      StopCount =0;
    }
  }
}

void SingleWipe()
{
  if (WiperRelayState == false)                          // Not much point in wiping if we already doing a wipe.
  {
    LastWipeTime = millis();
    WiperRelayState = true;
    digitalWrite(WiperRelay, HIGH);
  }
  else
   {
    WiperRelayState = false;
    digitalWrite(WiperRelay, LOW);
   }
   return;
}

				
			

Sketche Two
Automotive series, Temperature light

Sketche Three
Combined wiper and temperature light,

				
					console.log( 'Code is Poetry' );
/*
    
    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 <EEPROM.h>
  
    
    // 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);
     }
   }
      
    
    
  


				
			
				
					console.log( 'Code is Poetry' );
/*
    This sketch combines both previous sketches into one, to allow both functions to run on the same hardware.
    NOTE during calibration the Variable Wiper doesn't run.
    
    The display error codes requires the unit to stay in the loop, however it tis necessary to ensure the Wipera are
    not still wiping.
    As I finish the sketch whether the Variable Wiper runs under an error condition will also be decided.
    
      
    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.
    
    VARIABLE WIPER
    This sketch controls a relay via a transistor, which is connected across the park contact on a Windscreen Wiper.
    Pressing the Start button, gives a single wipe, and if the button is pressed again within 30 secs, will continue at the interval between button press's.
    Pressing the Start button after a wipe cycle will change the interval to the time between wipe and press.
    
    Pressing of the Stop button halts the cycle, unless the start button is pressed within 30 secs.
    Wipe interval will be the interval between Stop and Start button being pressed.
    
    Delays have been removed to allow a secondary function to run at the same time.
    ------------------------------------------------------------------------
    The full article is in the Apr/May and June/July issue of The Shed magazine
    http://www.theshedmag.co.nz/online/
    
    Cadenza Publishing Ltd
    PO Box 99652
    Newmarket
    Auckland
    New Zealand
    1149
    
    T: +64 9 302-3172
    F: +64 9 302-3174
    Subscriptions and distribution.
    subscriptions@theshedmag.co.nz
    --------------------------------------------------------------------------
    
      Automotive Series
      1. Water Temperature Light
      2. Variable Wiper
      3. Electric Fan Controller (using the same hardware parts).
        
     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 (Water Temp Light)
     1.0  Initial Code completed Dec 2011
       Code finalised Feb 2012 (Variable Wiper)
       Combined code completed May 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
    *****************************************
    */
      
    // Thi sis needed in order to store the new 'normal' setting
    #include <EEPROM.h>
  
    
    // General Purpose (Water Temp Light)
    
      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]
      
      //*** check the use of int LedState in Variable Wiper ****
      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
      boolean CalButtonState = HIGH;          // records the CalibrateButton State
      boolean StartButtonState = HIGH;        // records the StartButton State
      boolean StopButtonState = HIGH;         // records the StopButton State

      
      // General Purpose (Variable Wiper)
      int IntWipe = 0;                       // Flag to show we mode we are in. 0= off, 1= first press, 2= 2nd press.
      int LedState = LOW;                    // ledState used to set the LED
      
      unsigned long WipeInterval = 0;         // Time between wipes as set by start/stop action                            [x secs]
      unsigned long LastWipeTime =0;          // Time the last wipe was started.
      unsigned long TimerTime =0;             // used in Timer(), = millis()-LastWipeTime.
      int ButtonTimeout = 30000;              // Timeout if no button is pressed. Note wipe interval is lower than this.   [30 seconds]
      int RelayOnTime = 1500;                 // Time the relay is held on to perform a single wipe.                       [1.5 secs]
      boolean WiperRelayState = LOW;          // Relay Output state
      
      //common
      
      // Button handling variables
      unsigned long LastButtonCheck = 0;      // Time the Buttons were last checked.
      unsigned long ButtonPressTime = 0;      // Time the last button was pressed.
      int StartCount = 0;                     // Start Button counter  
      int StopCount = 0;                      // Stop Button counter    
 
      //inputs
      int StartButton = 4;
      int StopButton = 5;
      int CalButton = 6;
      int TempSender = 0;
      int val = 0;
    
      //Outputs
      int TempLight = 3;                  // PWM 
      int WiperRelay = 2;                 // Wiper Relay output
      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);
     pinMode(WiperRelay, 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() 
    {

      Check_Buttons();                                        //used for Int wiper
      Timer();                                                //See what is needed to be done
  
    }
    
    void Timer()
    {

      //function used in Variable Wiper
       TimerTime = millis() - LastWipeTime;
  
      if (((millis()-ButtonPressTime) > ButtonTimeout) && (IntWipe == 1))        // 30 Sec timeout for no button press, but only after stopped, or 1 start.
      {
        IntWipe = 0;
        LastWipeTime = 0;
        WipeInterval = 0;   
      }
          // The SingleWipe() will be called when the start button is pressed, we need to turn the relay off.
      if ((TimerTime > RelayOnTime) && WiperRelayState == true)    // RelayOnTime has been exceeded AND WipeRelay is HIGH
      {
        SingleWipe();                                          // It will turn off the relay and not modify any variables
      }
         
      // Time to wipe but only if there is a WipeInterval AND the relay is off.      
      if ((TimerTime > WipeInterval) && (IntWipe == 2) && WiperRelayState == false)       
      {
        SingleWipe();
      }
      
      
      //functions used in Water Temp Light
       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 Check_Buttons()
    {
      if (millis() - LastButtonCheck > 5)                      // Reads button state every 5mS and then updates button counts
      {       
        StartButtonState = digitalRead(StartButton);
        StopButtonState = digitalRead(StopButton);
        LastButtonCheck = millis(); 
        
        if (StartButtonState == LOW)
        {
          
          StartCount ++;                                      // Increment the Count by 1
          if (StartCount > 10)                                // the button should be LOW for 10x5mS = 50mS
          {
            ButtonPressTime = millis();                      // used for the Button press Timeout
            StartCount = 0;
            if (WiperRelayState == false)                    // No point in returning until its finished doing a wipe.
            {
              switch (IntWipe)
              { 
                case 0:
                  // not been pressed or fully stopped.
                  IntWipe =1;
                  SingleWipe();
                break;                                            // Escape from the switch, so we don't do the next one
                
                case 1:
                  // single press or stop button pressed.
                  IntWipe = 2;
                  WipeInterval = (millis() - LastWipeTime);       // Time will be in mS
                  SingleWipe();
                break;                                            // Escape from the switch, so we don't do the next one
                
                case 2:
                  // 2nd press
                  WipeInterval = (millis() - LastWipeTime);       // Time will be in mS
                  SingleWipe();
                break;                                            // Escape from the switch, so we don't do the next one
              
              }
            }
          }
        }
        else                                                  // StartButton is HIGH
        {
          StartCount =0;
        }
        
        if (StopButtonState == LOW)
        {
          
          StopCount ++;
          if (StopCount >10)                                  // the button should be LOW for 50mS
          {
            ButtonPressTime = millis();                       // used for the Button press Timeout
            IntWipe = 1;
            StopCount = 0;
            WipeInterval = 0;
            LastWipeTime = millis();                          // Set the wipe timer, so when the start is pressed the interval will be right
          }
        }
        else                                                  // StopButton is HIGH
        {
          StopCount =0;
        }
      }
    }
    
    void SingleWipe()
    {
      if (WiperRelayState == false)                          // Not much point in wiping if we already doing a wipe.
      {
        LastWipeTime = millis();
        WiperRelayState = true;
        digitalWrite(WiperRelay, HIGH);
        digitalWrite(LEDPin, HIGH);
      }
      else
       {
        WiperRelayState = false;
        digitalWrite(WiperRelay, LOW);
        digitalWrite(LEDPin, LOW);
       }
       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.
      */
    
    {
       if((millis() - LastChange > 300) && Mode == 3)
        { 
          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;
          }
        }

       if((millis() - LastChange > 300) && Mode == 4)
        { 
          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 continually brightens from Off to On, 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);
     }
   }
      

				
			

Share:

More Posts

The Shed September/October 2021 Issue 98 is on sale now

Glen Macmillan works between his two sheds creating sculptures from recycled waste. His junk of choice is gardening tools, landscaping equipment, and farming equipment — particularly the older kind of hand tools that were made to last and had a bit of styling.

Simple hydroponics nutrient solution

Hydroponics is all about growing without soil. In many ways, this simplifies the lot of the gardener, but it gives them added responsibility for providing plants with the right level of nutrients.
As water with nutrients tastes, feels, and looks much the same as plain water, a testing instrument called an “EC meter” or “CF meter” is used.

Making a word clock

The Word Clock is a project created by Doug Jackson using Open Source (www.dougswordclock.com) and has been evolving into the product you see here.
It is based on an Atmel 168 processor chip as used in Arduino, is programmed using Arduino and fitted into a custom-made printed circuit board (PCB).