Google Analytics

Saturday, February 4, 2012

Banjo's Arduino Timer Circuit

Banjo's Adjustable TimerCircuit
(Note: scroll down for circuit diagram and software listing)
Part 1 of 3 parts.  
    
TimerCircuit with time control knob and indicator lights



I've been working on a thermocouple controller for my porch's gas heater (which I'll post at some future date).  The first iteration of that controller used a timer instead of a thermocouple.  Later, after I got the thermocouple, I changed the software and the hardware.  However, I decided that some people might need a timer circuit for their projects, so I elected to put it here.  As you can see, I placed the circuit inside of an old cigar box.


Inside of TimerCircuit control box.
This is the interior after wiring....well, almost the interior.  This is actually the interior of the thermocouple control box, as you can observe by the tiny thermocouple shield attached to the Arduino on the top right corner.

At some point, I intend to 'rescue' my Arduino out of this box and replace it, along with the breadboard on the left, with a custom PCB.

The circuit
The circuit uses an Arduino Uno; however, this is way more than needed for this simple circuit.  It could be adopted to make use of an IC 555 chip too.  

Using
Wire the device you want to energize and de-energize to the NO contact output wires.  The potentiometer (pot) will control the amount of on-time vs off-time for the relay.

Caution
You will have to determine the appropriate relay for the device you want to control, as all relay contacts have a voltage and current limitation.  In addition, the coil must be sized appropriately for use directly by the Arduino, or other circuit elements will need to be provide, as the Arduino can only supply 5vdc and 20ma directly to a circuit.

Hardware
The pot used in this circuit controls the amount of time the circuit is on vs off.  The 5vdc from the Arduino is wired to one leg of the pot.  The other leg of the pot is wired to ground.  The pot wiper makes a voltage divider network.  The wiper is connected to an analog input pin on the Arduino, where the value can be read.  The value is reflected as a percentage of 5vdc, which the Arduino software actually returns as 0 - 1023 counts on this pin, with 1023 being equated to 5vdc in this case.

The Arduino controls a relay, energizing the relay when ON, and de-energizing the relay when OFF.

The output from this device is relay-contact-closed when ON, and relay-contact-open when OFF.

The RED LED is ON when the relay is energized, and OFF when the relay is de-energized.
The GREEN LED is ON when the relay is de-energized, and ON when the relay is energized.
These are mutually exclusive.

Software
The software determines a ratio of on-to-off, based on the position of the pot.  The value returned by the Arduino on reading the pot is converted to a ratio, with 100% being full-on all the time, and 0% being full-off all the time.  One complete on and off cycle is the period.  The maximum amount of time for one period is defined in MAX_CYCLE_TIME.  So, if the MAX_CYCLE_TIME is set to 10 minutes, and the pot is set to 25%, then the on-time will be 25% of 10 minutes, or 2.5 minutes, which will mean the off time will be 7.5 minutes.

Parts Listing
- Relay: 5vdc, 1A SPST Reed Relay, something similar to Radio Shack 275-232
- Potentiometer: 10K Rotary Linear.  Value not critical, but should not be any less than 10K.  Anything between 10K and 500K should work OK.  I used 10K COM-9939 from Sparkfun.com
- LEDs: - any green and any red will do.
- Resistor: 470 ohm, any wattage will do.
- Diode: Limits Reverse Voltage Spike caused from coil.  1N4004 or similar, but depends on the coil you use!
- Arduino: I used an UNO as well as an OSEPP UNO compatible  will do, or earlier versions of the Arduino also.  Straight AVR chips if you do that.  The chip on the Arduino is the ATMEGA328P. 

Software listing
Note: some lines may wrap in the listing below.

//Author: Banjo 1/29/12
//
//TimerControl Rev 1.0.  This uses an adjustable timer to control a relay.  
//  Using the contacts controlled by the relay, you can control other devices.
//  The contacts of the relay are not connected to the circuitry, so it can 
//  be used to drive other devices.  Only the coil is connected to the Arduino.  
//
//  CAUTION: Do not exceed the rated voltage and current limitations associated with the 
//    relay contacts you use in building this circuit.
//
//  CAUTION: Choose a relay with a coil rated to be able to be used by the Arduino you 
//    use to build this project.  If your coil uses less than 20ma current and is 5VDC (and you
//    are using a 5VDC Arduino), then you can drive the coil directly from an Arduino; 
//    otherwise, you will have to add another device or switching transistor capable of 
//    providing sufficient current to drive the relay coil.
//
//  CAUTION: Use a diode to bypass coil reverse voltage spike associated with all coils
//    so you don't destroy your Arduino!
//
//  CONTROL: 
//    - adjust the time knob clockwise to increase time timer is on and decrease time timer is off.
//    - adjust the time knob counterclockwise to decrese time timer is on and increase time timer of off.
//
//  DISPLAYS: 
//       RED - timer contact is on.  Connected to ON_LED_PIN
//       GREEN - timer contact is off.  Connected to OFF_LED_PIN
//       Alternating RED and GREEN - Alarm() function. Time determined by ALARM_COUNTS.  Uses LEDs on both ON_LED_PIN and OFF_LED_PIN 
//
//For use:
//  - Wire device to be controlled to relay contacts.  The relay is controlled by this Arduino.
//    These contacts are not polarized, so it doesn't matter which contact goes to which
//    leg of the switch.  The relay you use must be correctly sized to carry the load you are going to place
//    onto the contacts.
//
//for testing:
//  - If you want LED for TIMER ON, then add LED at digital pin ON_LED_PIN, then through resistor to ground
//  - if you want LED for TIMER OFF, then add LED at digital pin OFF_LED_PIN, then through resistor to ground 
//  - change MAX_CYCLE_TIME to something short, like 10 * ONE_SECOND
//  - change IGNORE_MINIMUM to something short, like 2  * ONE_SECOND
//  - remember to change back!
//

//some handy time constants
unsigned long ONE_SECOND = 1000;  //1 second is 1000 microSeconds
unsigned long ONE_MINUTE = ONE_SECOND * 60;
int MAX_ADC_COUNTS = 1024; //ADC
unsigned long SENSOR_READ_DELAY_TIME = ONE_SECOND;

unsigned long MAX_CYCLE_TIME =  10 * ONE_MINUTE; // This controls the total amount of time for a period (both 1 one and 1 off time)
unsigned long IGNORE_MINIMUM =  1 * ONE_SECOND;  // In case you are controlling something that you don't want cycled too fast.
int ALARM_COUNTS = 250;  //blink rate.  Each is on for this amount of time.


//pin assignments 
int UNO_LED_PIN = 13;  //LED on the uno board, so no external connections
int ON_LED_PIN = 9;  //LED if using an external state LED
int OFF_LED_PIN = 10;   //LED timer off 
int TIMER_OUTPUT_PIN = 8;        //This controls the onboard relay that controls the timer output contacts.
int TIMER_RATIO_INPUT_PIN = A0;  //this is the onboard potetiometer that controls the ratio of on to off

int TIMER_ON = HIGH;  //used because may use sink current at some point
int TIMER_OFF = LOW;  //used because may use sink current at some point

void setup() {                
  Serial.begin(9600);
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(UNO_LED_PIN, OUTPUT);
  pinMode(ON_LED_PIN, OUTPUT);
  pinMode(OFF_LED_PIN, OUTPUT);
  pinMode(TIMER_OUTPUT_PIN, OUTPUT);

  Serial.println("setup()...Entry & Exit"); 

}

void loop() {
  Serial.println("loop()...Entry"); 
  turnTimerOff();  //de-energize the relay
  turnTimerOn();  //energize the releay
  Serial.println("loop()...Exit"); 
}

float getSetpointRatio() {
  //rather than counts of 0 - 1023 (range of the onboard ADC), return the 0% - 100% of range
  float ratio = 0.0;
  int sensorValue = 0;

  sensorValue = analogRead(TIMER_RATIO_INPUT_PIN);
  ratio = float(sensorValue) / float(MAX_ADC_COUNTS);

//  Serial.print("getSetpointRatio()....sensorValue: "); Serial.println(sensorValue); 
//  Serial.print("getSetpointRatio()....ratio: "); Serial.println(ratio);
  return ratio;
}


//----------------------------------------------------------------------------------------------------------------------------------------

void turnTimerOn () {
  //time controlled, not temperature controlled
  unsigned long cumulativeOnTime = 0;
  unsigned long timerOnTime = 0;
  unsigned long timerOffTime = 0;  //special case; keep on if no off time
  float ratio;
  
  Serial.println("turnTimerOn()...time controlled...entry..............................");
  do {
    Serial.println("turnTimerOn()...do loop top.");  
    ratio = getSetpointRatio();
    timerOnTime = calcOnTime(ratio);
    Serial.print("turnTimerOn()...timerOnTime: "); Serial.println(timerOnTime);
    Serial.print("turnHeatherOn()...IGNORE_MINIMUM: "); Serial.println(IGNORE_MINIMUM);
    if(timerOnTime < IGNORE_MINIMUM) {  //need to refactor this
      Serial.println("turnTimerOn()...less than IGNORE_MINIMUM...exiting.");
      return;
    }
    
    timerOn(); //energize the relay
    delay(SENSOR_READ_DELAY_TIME); //simple way to be able to provide approx on time.
    cumulativeOnTime += SENSOR_READ_DELAY_TIME;

    Serial.print("turnTimerOnUsingTimer()...cumulativeOnTime: ");Serial.println(cumulativeOnTime);
    Serial.print("turnTimerOnUsingTimer()...timerOnTime: ");Serial.println(timerOnTime);
  }   while(cumulativeOnTime < timerOnTime);
  Serial.println("turnTimerOnUsingTimer()...Exit.");
}

void turnTimerOff() {
  unsigned long cumulativeOffTime = 0;
  unsigned long timerOffTime = 0;
  float ratio = 0.0;
  
  Serial.println("turnTimerOff()...time controlled...entry.............................");
  
  do {
    Serial.println("turnTimerOffUsingTimer()...do loop top.");  
    ratio = getSetpointRatio();
    timerOffTime = calcOffTime(ratio);
    Serial.print("turnTimerOffUsingTimer()...timerOffTime: "); Serial.println(timerOffTime);
    Serial.print("turnHeatherOffUsingTimer()...IGNORE_MINIMUM: "); Serial.println(IGNORE_MINIMUM);
    if(timerOffTime < IGNORE_MINIMUM) {  //need to refactor this
      Serial.println("turnTimerOffUsingTimer()...less than IGNORE_MINIMUM...exiting.");
      return;
    }
    
    timerOff();  //de-energize the relay

    delay(SENSOR_READ_DELAY_TIME); //simple way to be able to provide approx off time.
    cumulativeOffTime += SENSOR_READ_DELAY_TIME;
    Serial.print("turnTimerOffUsingTimer()...cumulativeOffTime: ");Serial.println(cumulativeOffTime);
    Serial.print("turnTimerOffUsingTimer()...timerOffTime: ");Serial.println(timerOffTime);
  }   while(cumulativeOffTime < timerOffTime);
  Serial.println("turnTimerOffUsingTimer()...Exit.");
}

unsigned long calcOnTime(float ratio) {
  //time is a function of MAX_CYCLE_TIME; if this is seconds, then return seconds; if mins, then return mins
  unsigned long onTime = 0;
  
  Serial.println("calcOnTime()....Entry");
  onTime = ratio * MAX_CYCLE_TIME;
  Serial.print("calcOntime()....onTime: "); Serial.println(onTime);
  Serial.println("calcOnTime()....Exit");

  return onTime;
}

unsigned long calcOffTime(float ratio) {
  //time is a function of MAX_CYCLE_TIME; if this is seconds, then return seconds; if mins, then return mins
  unsigned long offTime = 0;
  float offRatio = 0.0;

  Serial.println("calcOffTime()....Entry");
  //use calcOnTime for brevity
  offTime = calcOnTime(ratio);
  offTime = MAX_CYCLE_TIME - offTime;

  Serial.print("calcOffTime()....offTime: "); Serial.println(offTime);
  Serial.println("calcOffTime()....Exit");

  return offTime;
}


void timerOn() {
  Serial.println("timerOn() ... entry.");
  digitalWrite(TIMER_OUTPUT_PIN, TIMER_ON);   // sink current
  digitalWrite(OFF_LED_PIN, LOW);
  digitalWrite(UNO_LED_PIN, HIGH);   // set the LED on
  digitalWrite(ON_LED_PIN, HIGH);
  Serial.println("timerOn() ... exit.");
}

void timerOff() {
  Serial.println("timerOff() ... entry.");
  digitalWrite(TIMER_OUTPUT_PIN, TIMER_OFF);     
  digitalWrite(UNO_LED_PIN, LOW);   // set the LED on
  digitalWrite(ON_LED_PIN, LOW);
  digitalWrite(OFF_LED_PIN, HIGH);
  Serial.println("timerOff() ... exit.");
}  

void alarm(int sensorValueCounts) {  //needs to be refactored to use timerOff()
  //NOTE: alarm function turns relay coil off.  This is left here as a convenience for
  //  code you may develop.  It is used in a later implementation of this software,
  //  where I check for gas pilot light on.
  //
  //blink both on and off LEDs
  //
  Serial.println("alarm()....Entry...will not exit!");

  //TURN OFF!
  digitalWrite(TIMER_OUTPUT_PIN, TIMER_OFF);   
  digitalWrite(OFF_LED_PIN, LOW);
  
  Serial.print("alarm()....sensor low. sensorValueCounts: "); Serial.println(sensorValueCounts);
  while(1) {
    //keep turning timer off!
    digitalWrite(TIMER_OUTPUT_PIN, TIMER_OFF);
    
    //show it by alternating blinking both LEDs
    digitalWrite(UNO_LED_PIN, HIGH);
    digitalWrite(ON_LED_PIN, HIGH);
    digitalWrite(OFF_LED_PIN, LOW);
    delay(ALARM_COUNTS);

    digitalWrite(UNO_LED_PIN,LOW);
    digitalWrite(ON_LED_PIN, LOW);
    digitalWrite(OFF_LED_PIN, HIGH);
    delay(ALARM_COUNTS);
  }
}






10 comments:

  1. how can I add a code of my motor controller using the same uno?thank you for advance

    ReplyDelete
  2. Hi,
    Thanks for the great sketch, how would I modify this to have a fixed on time (4 seconds) and a variable on time (0-30 seconds)?

    Regards

    ReplyDelete
  3. Correction:

    fixed "ON" time Variable "OFF" time

    ReplyDelete
  4. For a fixed ON TIME and variable OFF TIME, then you would take out the 'do...while' within the turnTimerOn() function, so you only go through the code once instead of looping. Then within the delay(xxx) function, you would put the number of seconds (times 1000 because it works on thousandths of a second), or for minutes it would be Minutes * 60 * 1000. The turnTimerOff() should work as it is.

    ReplyDelete
    Replies
    1. Banjo,

      Thank you for your reply and instructions, I am just learning "Arduino." Your sketch(s) have been quite instructive and helpful in understanding the nuances of writing code. It is obvious that you are quite talented.

      Kind Regards,

      James Bower

      Delete
    2. James,

      Thanks for the kind comments. I'm working on a cheap datalogger that will use a 4 GB SD card for the data. I hope to have it published next week sometime.

      Drop me an email via this blog for any questions or to keep me up to date on what you are doing!

      Banjo

      Delete
    3. Banjo,

      I look forward to your datalogger! I have switched from the timer sketch to your thermocouple sketch; I am waiting for the Adafruit board to arrive so I can continue.

      Regarding what I am working on:

      I am working on a complete control system for a pellet stove. I acquired an old Whitfield pellet stove that had controller problems. When I discovered that they wanted $600.00 for the control board I decided to learn "Arduino". I have recently retired and now have the time to do some of the projects that I just could not do while employed full time.

      Your first timer sketch is really all I need to get it up and running, but your thermocouple control sketch looks like it may do a better job. I will keep you informed of my progress.

      Regards,

      James

      Delete
    4. James,

      I'm really interested in your project, as it's in line with some stuff I've built over the years, like a bbq smoker. Please drop me an email at "bbq and banjos at gmail dot com" (remove spaces substitute charactors for 'at' and 'dot'). Thanks!

      Re datalogger: have had success writing to 4 gbyte sd card, on a non-Arduino circuit (still using the same chip, but not the circuit board - chips are < $5., board is about $30, so big savings!) I'm doing 4 channels of thermocouples on it, will be able to handle up to 8. Still refining - want to add a date/time-stamp chip. Want to make some printed circuit boards when finished.

      Delete
  5. comadreify, I'm not sure I understand your question. Are you asking me how you would use this with a motor controller? If so, I'll need to know more about the motor you are driving, and how you are driving it.

    Sorry it has taken me so long to get back to you!

    ReplyDelete
  6. Hi Banjo
    I was wondering if you could tell how to use a IC 555 timer instead of using a arduino for the timer circuit. All i need is to have it on for 6-10 seconds and off for 10 on more minutes. Is it possible to use the 555 timer. Is there a schematic of this circuit? Can you help me? Thank You
    Gary

    ReplyDelete