Author Topic: DRIVING A RELAY WITH PWM  (Read 1349 times)

0 Members and 1 Guest are viewing this topic.


  • Hero Member
  • *****
  • Posts: 1090
  • Country: us
« on: December 09, 2016, 09:38:31 AM »
                  DRIVING A RELAY WITH PWM

Sometimes nothing works better than a relay. When I have the option, I will
drive them with PWM to lower coIl current.  Most relays will pull in at 75%
of rated voltage and drop out around 35%. The lower drop out is the result of
eliminating the air gap when the relay closes. With this method, a lower voltage
relay can be used at a significantly higher voltage. A micro could monitor the
voltage and adjust the PWM to suit.  The biggest advantage is saving power and
reduction of relay heating.

In normal relay driving a 1 or 0 is sent to one of the 12 digital ports with the
expression " digitalWrite (pin,state); ". Six of those ports on the UNO can also
operate in the PWM mode with the expression " analoglWrite (pin,PWM); ". Now,
instrad of a 1, a PWM value of 255 is sent to the port. This is the fully on
state and the output looks no different than a digital output. Each following loop
of the program, one count is subtracted from the PWM number. An IF statement looks
at the last value of the PWM and compares it with the end point PWM value. As long
as the PWM is greater this subtracting continues. A hold in value of half the
starting count is a reasonable value. Half the voltage and half the current results
in one quarter the power the relay operates at. That is quite some savings. To turn
the relay off, PWM is set to 0 just as before. Lets look at this sample code.

  if(whatever && PWM == 0) PWM = 255; // this insures it is done just once
  analogWrite (pin#, PWM);            // output that value
  if(PWM > 128) PWM = PWM - 1;        // subtract one from the count till end value

A 12V relay could also be used on a 24V supply with this method. Just make the
starting value 128 and the end value 64.  It will not use more power. The relay coil
and diode operates just like a buck converter in the conversion of energy to a
lower voltage.
The following is a fun little program to demonstrate the pull in and drop out
PWM numbers and percentages. It blinks and makes noises, What more can you ask
for. The PWM value decrements down each loop of the program and then back up
to the full voltage.  The normally open relay contacts are monitored and the PWM
value is recorded when the contacts change state. All these sample programs
provide examples of logical software operations. Determining state change is
done every loop of the program with the line, LASTstate = state, near the end
of the program. An IF statement, if (LASTstate != state) save the data. The !=
is a NOT EQUAL TO logical operator. Multiple logical tests can be ANDed together
to meet special cases. This is done each loop when the data is printed.  DROP OUT
and PULL IN are printed to indicate what operation is being performed. At the ends
when the count reverses, what do you call that.  I used the term of ON or OFF to
identify these cases. A loop counter identifies when the PWM has ramped twice. Then
the PWM is printed for pull in and drop out. It will then wait about ten seconds
before the program restarts. The scrolling can then be stopped so the data can be
recorded or scroll back to review the data. The loop speed could be slowed down
eliminating the need to connect to the relay contacts.  Just listen for when the
armature clicks and record the number on the screen. Buzzing will occur for a
period just before pull in. That only happens in this slow ramp up program. In
normal operation, the relay is first hit with full power insuring a rapid pull

Normally you would need a pullup resistor to sense the contacts changing state.
Note where pin#8 is declared as an input. Immediately following is digitalWrite(8,1);
This sets the internal pull up ON and provides 140uA of current. The low 5V and
current may not be enough for the oxidation layer to break down if the relay has
been stored a long time. Operating the relay with 120V AC a few times with a lamp
will restore the contacts.  Three different PWM frequencies, 960, 480, and 240Hz
are provided to compare best operation.  960Hz on pins 5 & 6 is standard for a UNO.
The other PWM pins are set to 480Hz.  At the beginning of the program is a section
that changes two PWM pins to 240Hz.

The micro's 5V output voltage will drive most FET. A 300 ohm is suggested in series
with the gate to prevent possible damage to the micro in the event of a short. The
relay MUST have a diode across it. All diodes are fast to start conducting, but
general diodes are slow to turn off. That could cause a mini short for a very small
time period. At these low speeds and power, you can get away with general diodes.
I do suggest purchasing some high speed diodes.

// Operates a mechanical relay till it drops out
// Then increases PWM till it pulls in
// Mechanical relay is PWM driven to lower current
// Driving speed 240Hz pin 3
// Driving speed 480Hz pin 10.
// Driving speed 960Hz pin 5.
// At end of test data is displayed for 10 seconds
// relay contacts are monitored for transition
// Serial outputs data every loop & flashes LED to indicate on.

// last edit 12/07/16

 int testloop   = 0;
 int count      = 0;
 int blinktime  = 0;
 int relay      = 1;             // UP/DOWN
 int PWMdrv     = 255;           // PWM relay drivers
 int state      = 0;             // relay contact state
 int LASTstate  = 1;             // last state
 int pullindrv  = 0;             // PWM @ transition
 int dropoutdrv = 0;
 int pct        = 0;
 int dct        = 0;
void setup() 
   Serial.begin(9600);           //  setup serial
   pinMode(13, OUTPUT);          // sets the digital LED pin 13 as output
   pinMode(8, INPUT);            // sets pin 8 as input for RELAY CONTACT
   digitalWrite(8,1);            // this sets the internal pull up ON
                                 // 140uA of current. This voltage and
                                 // current may not be enough for oxidation
                                 // to break down of old relays
void loop()  { 
    //  *****************************************
    // Pins 11 and 3 for 16MHz clock
    // Setting     Divisor    Hz
    // 0x01         1         31250
    // 0x02         8       3906
    // 0x03         32      976
    // 0x04         64      488
    // 0x05         128     244
    // 0x06         256     122
    // 0x07         1024    30
    // TCCR2B = TCCR2B & 0b11111000 | <setting>;
    TCCR2B = TCCR2B & 0b11111000 | 0x05;
    if (count >= 510)                             // run end
    {                                             // this bracket indicates start of actions
     digitalWrite (13,1);                         //  LED INDICATE END OF TEST
  //                           PRINT TEST RESULTS
     Serial.println(" ");                         // skip line
     Serial.print("drop out ");
     Serial.print("  ");
     Serial.print(dropoutdrv *100 /255);
     Serial.print("%   count ");
     Serial.print( dct);
     Serial.print("       pull in ");                  // transition results
     Serial.print( pullindrv);
     Serial.print("  ");
     Serial.print( pullindrv*100 /255);
     Serial.print("%   count ");
     Serial.print( pct);
     Serial.println(" ");                         // two lines before next test
     Serial.println(" ");
     delay (10000);                               // delay to look at data
     pullindrv = 255;                             // reset test variables
     dropoutdrv = 0; 
     count = 0;                                   // reset count
     relay = 1;
     pct   = 0;
     dct   = 0;
     digitalWrite (13,0);                         // TURN LED OFF
    //                BLINK AND COUNTING
    count = count + 1;                            // increment count
    blinktime  = blinktime + 1;                   // increment blink count
    if (blinktime == 6) blinktime = 0;            // increment blink count
    state = digitalRead (8);                      // read switch on pin 8
    if (blinktime == 1) digitalWrite (13,1);      // blink
    if (blinktime == 2) digitalWrite (13,0);
    delay(20);                                    // wait controls loop speed
    if (relay == 0) PWMdrv = PWMdrv + 1;          // increment relay power
    if (relay == 1) PWMdrv = PWMdrv - 1;          // decrement relay power
    if (PWMdrv >= 255) PWMdrv = 255;              // limit upper end 
    if (PWMdrv <= 0)   PWMdrv = 0;                // limit lower end
    //                  OUTPUT ALL PWM FREQUENCIES
    analogWrite (3, PWMdrv);                      // output relay 240 Hz
    analogWrite (10, PWMdrv);                     // output relay 480 Hz
    analogWrite (5, PWMdrv);                      // output relay 960 Hz
    if (relay == 1 && PWMdrv == 0) relay = 0;     // start increment 
    if (relay == 0 && PWMdrv == 255) relay = 1;   // start decrement                                               
    Serial.print(PWMdrv);                         // drive
    Serial.print(" PWM ");         
    Serial.print(PWMdrv * 100 / 255);             // %
    Serial.print("%  ");         
    if (state == 1)Serial.print(" OPEN   ");       // relay contact status
    if (state == 0)Serial.print(" CLOSED ");       
    Serial.print(count);                          // COUNT
    if (relay == 0 && PWMdrv <= 254 && PWMdrv != 0)Serial.println(" PULL IN ");
    if (PWMdrv == 255)Serial.println(" ON ");     // ramp status
    if (relay == 1 && PWMdrv >= 1 && PWMdrv != 255)Serial.println(" DROP OUT "); 
    if (PWMdrv == 0)Serial.println(" OFF ");     
    //                      RECORD TRANSITIONS EACH RAMP
    if (state != LASTstate && relay == 1)
     dropoutdrv = PWMdrv;
     dct = count;

    if (state != LASTstate && relay == 0)
      pullindrv = PWMdrv;
      pct = count;     
    LASTstate = state;                            // save last state of contacts             
    if (relay == 1 && PWMdrv == 0) relay = 0;     // start increment 
    if (relay == 0 && PWMdrv == 255) relay = 1;   // start decrement
}         // END OF PROGRAM


  • Sr. Member
  • ****
  • Posts: 381
  • Country: us
    • boB
« Reply #1 on: December 17, 2016, 11:31:44 PM »

The voltage needed to keep the relay pulled in will also go up some as the relay gets warmer.

I add a wee bit of safety factor...  And the catch diode too of course.



  • Newbie
  • *
  • Posts: 19
  • Country: au
« Reply #2 on: February 05, 2018, 03:41:06 AM »
I have looked at this myself, mainly to help reduce the let go time when power is removed from the relay. The quicker the relay lets go, the quicker the switch over is.

I would also like to investigate temporarily driving the relay coil in reverse for a very short amount of time to see if that reduces the switch time as well. Effectively, a 1 cycle linear induction motor that repels the armature.