How to calculate operating time of electromechanical relay using arduino mega board

I have connected 5V of arduino board to common of the relay and NO and NC pin of relay are connected to two digital pins. Also NO and NC are pull down using 10K ohm resistor. I have to calculate the operating time. I am getting some deviated result with my code. Help me with the code.

const int normallyClosedPin = 2; 

const int normallyOpenPin = 3; 

volatile unsigned long startTime = 0; 

volatile unsigned long endTime = 0; 

volatile bool startMeasured = false; 

void setup() { 

 Serial.begin(57600); 

 pinMode(normallyClosedPin, INPUT_PULLUP); 

 pinMode(normallyOpenPin, INPUT_PULLUP); 
 attachInterrupt(digitalPinToInterrupt(normallyClosedPin), ncToNoBegin, FALLING); 

 attachInterrupt(digitalPinToInterrupt(normallyOpenPin), noToNcEnd, RISING); 

} 

 

void loop() { 

 if(endTime>startTime) { 
  
  unsigned long operatingTime = endTime - startTime; 

  Serial.print("The operating time of the relay is:"); 

  Serial.print(operatingTime); 

  Serial.println("microseconds");  
 
  operatingTime = 0;
  startTime = 0; 

  endTime = 0; 

  startMeasured = false; 

  delay(1000); 

  } 

} 

 void ncToNoBegin() { 

  if(!startMeasured) { 

    startTime = micros(); 

    startMeasured = true; 

  } 

 } 

 void noToNcEnd() { 

  if(startMeasured) { 

    endTime = micros(); 

  } 

 } 

 
1 Like

Also NO and NC are pull down using 10K ohm resistor. Why are you using pull-down?

What is driving the relay?

how do you change the state of the relay by applying power to the relay coil?

why not measure either

  • the the time from when power is applied to the coil and the NO contact closes, or
  • the time when power is removed and the time the NC contact closes

bear in mind, the arduino needs to know when coil power changes, so most likely use a switch to command the arduino to start the process

Do not forget the relay can bounce.

It is always the contact that is closing that bounces.
When the relay is energised the NO contact bounces.
When the relay is de-energised it is the NC contact that bounces.

Here are some oscilloscope traces showing relay contacts bouncing.

  • Channel 1 - yellow trace - Relay operating signal.
  • Channel 2 - red trace - Normally Closed contact.
  • Channel 3 - blue trace - Normally Open contact.

Relay being energised:

Relay being de-energised:

2 Likes
  • What board are you using? If your board has an 8 or 16-bit uc then you will need to disable interrupts when reading startTime and endTime during loop if you are using interrupts
  • Do you really need uS resolution for the timing? If mS resolution is good enough then don't use interrupts and just poll the inputs.
  • As stated before you need to account for the debounce on the relay closure.

Both the contacts that open and the contacts that close when the relay switches states can bounce. Debouncing algorithms are often symmetric, treating both edges at once with a time constant large enough for the worst case, which will be the contacts that are closing.

a7

here's code to simulate what i believe you are trying to do.

  • it assumes the NO and NC contacts are connected to pins 2 & 3 configured with internal pull-up resistors enabled, INPUT_PULLUP and the COMMON is connected to ground. a closed contact pulls the pin LOW

  • it uses pin 13 as an output to control the relay by providing voltage to the relay coil. i would use it to drive a transistor (with series resistor between the pin and base) to pull one side of the relay coil to ground with the other side connected to a power supply. (i don't know the response time fo a programmable power supply

  • loop() alternately calls close() and open(). they either energize or de-energize the relay coil and then wait for the relay contacts to change state. the NC contact is normally closed, so after energizing the coil in close(), it waits for the NC contact to open by going HIGH and the the NO contact to close by going LOW

  • results are printed by report() which output the captured times and deltas

  • i tested with pins on a multi-function board. change #define MyHW to #undef MyHW to used your hardware and pin assignments

output

        0     4419        0        0     4419  open
      572      572     4920     5492     5492  open
      303      319     5993     6296     6312  open
      159      159     6813     6972     6972  open
      182      184     7473     7655     7657  open
      205      205     8158     8363     8363  open
       33       34     8863     8896     8897  open
        0      203     9399     9399     9602  open
      242      242    10102    10344    10344  open
      152      152    10845    10997    10997  open
       80       80    11498    11578    11578  open
        0        0    12079    12079    12079  open
      742      742    12580    13322    13322  open
       60       60    13822    13882    13882  open
      357      357    14383    14740    14740  open
      491      491    15241    15732    15732  open
      473      486    16233    16706    16719  open
        2        2    17220    17222    17222  open
#define MyHW
#ifdef MyHW
# define time millis

const int PinNC    = A1;
const int PinNO    = A2;
const int PinCoil  = 13;

enum { CoilOff = HIGH, CoilOn = LOW };

#else
# define time micros

const int PinNC    = 2;
const int PinNO    = 3;
const int PinCoil  = 13;

enum { CoilOff = LOW, CoilOn = HIGH };
#endif

unsigned long t0;
unsigned long t1;
unsigned long t2;

char s [90];

// -----------------------------------------------------------------------------
void
close ()
{
    digitalWrite (PinCoil, CoilOn);
    t0 = time ();

    while (LOW == digitalRead (PinNC))  // wait for NC contacts to open
        ;
    t1 = time ();

    while (HIGH == digitalRead (PinNO)) // wait for NO contracts to close
        ;
    t2 = time ();
}

// -----------------------------------------------------------------------------
void
open ()
{
    digitalWrite (PinCoil, CoilOff);
    t0 = time ();

    while (LOW == digitalRead (PinNO))  // wait for NO contacts to open
        ;
    t1 = time ();

    while (HIGH == digitalRead (PinNC)) // wait for NC contracts to close
        ;
    t2 = time ();
}

// -----------------------------------------------------------------------------
void report ()
{
    unsigned long dT1 = t1 - t0;
    unsigned long dT2 = t2 - t0;
    sprintf (s, " %8lu %8lu %8lu %8lu %8lu  open", dT1, dT2, t0, t1, t2);
    Serial.println (s);
}

// -----------------------------------------------------------------------------
void loop ()
{
    close ();
    report ();
    delay (500);

    open ();
    report ();
    delay (500);
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    pinMode (PinNC,   INPUT_PULLUP);
    pinMode (PinNO,   INPUT_PULLUP);
    pinMode (PinCoil, OUTPUT);
}

If possible, please provide me the connection diagram.

i'm guessing that you expect the PC to control the relay.

from the code it looks like you expect to make a measurement from when the NC contact opens and goes LOW to when the NO contact closes and goes HIGH.

i assumed you want to measure the time from when the coil is energized. that requires that the Arduino control it and that is the purpose of pin 13.

i wired things so that i could test the code on my hardware. if you understand what i've done, you should be able to modify your code to better suit your approach

what does this mean? can you post your results

since your pull-down resistors are wired to Gnd, your common should be wired to 5V

looks like you're measuring from when one contact opens until the other contact is closed

do you want to measure from when the coil is energized until the contract open/closes?

so how does the arduino know when the coil is energized ???

the common terminal is only for the contacts.

the coil is independent of the contacts

A Hall Switch could detect the field of the relay switching.

A Linear Hall Sensor could tell details!

see post #3, but i don't see how the Arduino knows when the coil is energized

I did a test to see how well the results obtained from gcjr's code agreed with the results obtained from an oscilloscope.

I modified gcrj's code slightly, so that it would wait until I gave it a trigger signal before it switched the relay on or off. This was done to give me time to save the results before the next switching event.

The oscilloscope traces show:

  • Channel 1 - yellow trace - trigger signal
  • Channel 2 - red trace - relay power
  • Channel 3 - blue trace - NC contacts
  • Channel 4 - green trace - NO contacts
  • There are automatic measurements of the times being measured

The Arduino results on the serial monitor are shown on the same screenshot.
The last result on the serial monitor is the same run that the oscilloscope trace shows.

Relay turning on:


Results:
Arduino 852µs 1484µs
Oscilloscope 853µs 1481µs

Relay turning off:


Results:
Arduino 2724µs 3152µs
Oscilloscope 2723µs 3150µs

The results obtained from the Arduino are very close to the results from the oscilloscope. There is a maximum difference of 3µs between the Arduino and oscilloscope in the results shown.

Both the Arduino and the oscilloscope measure the time to the beginning of the contact bounce. The bounce time is extra.

1 Like

Arduino micros() rounds (I forget if up or down) to 4's.
The low 2 bits are always 0.

Please provide me the code and hardware connection. Its a little urgent for me.

The code that I used was a modified version of the code that gcjr posted in post #11.

I added a wait() function that halted the program until a trigger pulse was received.
I also commented out the first line of the code to select the hardware in use.


//#define MyHW
#ifdef MyHW
#define time millis

const int PinNC    = A1;
const int PinNO    = A2;
const int PinCoil  = 13;

enum { CoilOff = HIGH, CoilOn = LOW };

#else
#define time micros

const int PinNC    = 2;
const int PinNO    = 3;
const int PinCoil  = 13;
const int waitPin  = 7;

enum { CoilOff = LOW, CoilOn = HIGH };
#endif

unsigned long t0;
unsigned long t1;
unsigned long t2;

char s [90];

// -----------------------------------------------------------------------------
void
close ()
{
  digitalWrite (PinCoil, CoilOn);
  t0 = time ();

  while (LOW == digitalRead (PinNC))  // wait for NC contacts to open
    ;
  t1 = time ();

  while (HIGH == digitalRead (PinNO)) // wait for NO contracts to close
    ;
  t2 = time ();
}

// -----------------------------------------------------------------------------
void
open ()
{
  digitalWrite (PinCoil, CoilOff);
  t0 = time ();

  while (LOW == digitalRead (PinNO))  // wait for NO contacts to open
    ;
  t1 = time ();

  while (HIGH == digitalRead (PinNC)) // wait for NC contracts to close
    ;
  t2 = time ();
}

// -----------------------------------------------------------------------------
void report ()
{
  unsigned long dT1 = t1 - t0;
  unsigned long dT2 = t2 - t0;
  sprintf (s, " %8lu %8lu %8lu %8lu %8lu  open", dT1, dT2, t0, t1, t2);
  Serial.println (s);
}

// -----------------------------------------------------------------------------
void wait ()
{
  while (LOW == digitalRead (waitPin))  // wait for trigger signal
    ;
}

// -----------------------------------------------------------------------------
void loop ()
{
  wait ();
  close ();
  report ();
  delay (500);

  wait ();
  open ();
  report ();
  delay (500);
}

// -----------------------------------------------------------------------------
void setup ()
{
  Serial.begin (9600);

  pinMode (PinNC,   INPUT_PULLUP);
  pinMode (PinNO,   INPUT_PULLUP);
  pinMode (waitPin, INPUT);

  pinMode (PinCoil, OUTPUT);
}

The relay that I used was one of the ones on a Arduino MKR Relay Proto Shield, as that was the only one available.
This shield has N channel MOSFETs to switch the relays. Schematic here.

  • I powered the shield from the 3.3V pin of an Arduino Uno R3.
  • I used pin 13 of the Uno to switch one of the relays on the shield.
  • The NC relay contact went to Uno pin 2.
  • The NO relay contact went to Uno pin 3.
  • The COM relay connection went to Uno GND.

I also used a function generator, manually triggered to provide a 5V trigger pulse to Uno pin 7.

You will have to adapt the arrangement to suit your own hardware.
You could use a push button to generate the trigger pulse.

But, I have a normal D Relay, which have NO, NC and common. Where should I connect the 3.3V i.e. how will I power the relay through Arduino? Also how have you connected the pin 13, please share the photo of connection if possible.