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
in.
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.
// PWM_RELAY_TEST1
// 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() {
// *****************************************
// LOWER THE PWM FREQUENCY
// 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(dropoutdrv);
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 (

; // read switch on pin 8
if (blinktime == 1) digitalWrite (13,1); // blink
if (blinktime == 2) digitalWrite (13,0);
delay(20); // wait controls loop speed
// LOW CURRENT MECHANICAL PWM RELAY CODE
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
// ALTERNATE UP/DOWN AT END OF SEQUENCE
if (relay == 1 && PWMdrv == 0) relay = 0; // start increment
if (relay == 0 && PWMdrv == 255) relay = 1; // start decrement
} // END OF PROGRAM