Strange behavior when using Relay X1

I tried the resistor thing, it was an improvement, but it would still kick on for a second(solid, better than it flipping on and off rapidly for 3-5 seconds).

What I ended up doing is wiring the 12VDC for the x16 to an x1. The x1 turns on in code, so the spider is fully spun up before any power goes to the x16. That was the only way I could guarantee that I didn’t have start up problems.

I’ve run into multiple issues where the relays will randomly turn on. I’ve had to rewrite the driver code in order to minimize the problems. I have diodes across my solenoids and a resistor/cap combination as well. Honestly the driver rewrite is what helps the most.

Discovered the hard way when the machine sat for extended periods of time, the relays(all of them) would just kick on. As soon as I triggered our software to do anything, it would set just the relays we had on to the proper state. Since I couldn’t figure out what was causing the randomness(seriously, I opened the door to the building and the damned relays kicked on…I could walk by the machine and cause them to kick on occasionally). Out of desperation, I basically am just sending the state the relays should be in as often as I can. So when this randomness happens, it only happens for a split second(if you blink, you miss it). That’s got our machine operation, even if a little scary when I sit and think about it for too long.

In my main timer, I just constantly call


Board_Relay.Refresh();

I also created code in the driver to turn on a timer, but I wanted more control from my side to only do it when I’m not doing anything else. Here’s what I wrote for the driver…


using System;

using GT = Gadgeteer;

using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;

namespace Gadgeteer.Modules.GHIElectronics
{
    /// <summary>
    /// A module that provides access to 16 optically-isolated relays for Microsoft .NET Gadgeteer
    /// </summary>
    /// <example>
    /// <para>The following example uses a <see cref="RelayISOx16"/> object to write to a few of the available 16 relays.</para>
    /// <code>
    /// using Microsoft.SPOT;
    ///
    /// using GTM = Gadgeteer.Modules;
    ///
    /// namespace TestApp
    /// {
    ///     public partial class Program
    ///     {
    ///         void ProgramStarted()
    ///         {
    ///             // Multiple relays can be enabled at once
    ///             relay.EnableRelay(GTM.GHIElectronics.RelayISOx16.Relay.Relay_14 + GTM.GHIElectronics.RelayISOx16.Relay.Relay_4);
    ///
    ///             // Enabling another relay will not affect previously altered relays
    ///             relay.EnableRelay(GTM.GHIElectronics.RelayISOx16.Relay.Relay_7);
    ///
    ///             // Multiple relays can be disabled at once
    ///             relay.DisableRelay(GTM.GHIElectronics.RelayISOx16.Relay.Relay_12 + GTM.GHIElectronics.RelayISOx16.Relay.Relay_2);
    ///
    ///             // Disabling another relay will not affect previously altered relays
    ///             relay.DisableRelay(GTM.GHIElectronics.RelayISOx16.Relay.Relay_6);
    ///
    ///             // Use this to turn off all relays
    ///             relay.DisableAllRelays();
    ///             
    ///             Debug.Print("Program Started");
    ///         }
    ///     }
    /// }
    /// </code>
    /// </example>
    public class RelayISOx16 : GTM.Module
    {
        // -- CHANGE FOR MICRO FRAMEWORK 4.2 --
        // If you want to use Serial, SPI, or DaisyLink (which includes GTI.SoftwareI2C), you must do a few more steps
        // since these have been moved to separate assemblies for NETMF 4.2 (to reduce the minimum memory footprint of Gadgeteer)
        // 1) add a reference to the assembly (named Gadgeteer.[interfacename])
        // 2) in GadgeteerHardware.xml, uncomment the lines under <Assemblies> so that end user apps using this module also add a reference.

        private GTI.DigitalOutput data;
        private GTI.DigitalOutput clock;
        private GTI.DigitalOutput latch;
        private GTI.DigitalOutput enable;
        private GTI.DigitalOutput clear;

        /// <summary>
        /// Mask used to toggle relays.
        /// </summary>
        public partial class Relay
        {
            /// <summary>
            /// Mask for relay #1
            /// </summary>
            public const ushort Relay_1 = 1;

            /// <summary>
            /// Mask for relay #2
            /// </summary>
            public const ushort Relay_2 = 2;

            /// <summary>
            /// Mask for relay #3
            /// </summary>
            public const ushort Relay_3 = 4;

            /// <summary>
            /// Mask for relay #4
            /// </summary>
            public const ushort Relay_4 = 8;

            /// <summary>
            /// Mask for relay #5
            /// </summary>
            public const ushort Relay_5 = 16;

            /// <summary>
            /// Mask for relay #6
            /// </summary>
            public const ushort Relay_6 = 32;

            /// <summary>
            /// Mask for relay #7
            /// </summary>
            public const ushort Relay_7 = 64;

            /// <summary>
            /// Mask for relay #8
            /// </summary>
            public const ushort Relay_8 = 128;

            /// <summary>
            /// Mask for relay #9
            /// </summary>
            public const ushort Relay_9 = 256;

            /// <summary>
            /// Mask for relay #10
            /// </summary>
            public const ushort Relay_10 = 512;

            /// <summary>
            /// Mask for relay #11
            /// </summary>
            public const ushort Relay_11 = 1024;

            /// <summary>
            /// Mask for relay #12
            /// </summary>
            public const ushort Relay_12 = 2048;

            /// <summary>
            /// Mask for relay #13
            /// </summary>
            public const ushort Relay_13 = 4096;

            /// <summary>
            /// Mask for relay #14
            /// </summary>
            public const ushort Relay_14 = 8192;

            /// <summary>
            /// Mask for relay #15
            /// </summary>
            public const ushort Relay_15 = 16384;

            /// <summary>
            /// Mask for relay #16
            /// </summary>
            public const ushort Relay_16 = 32768;
        }

        private ushort regData = 0x0000;

        // Note: A constructor summary is auto-generated by the doc builder.
        /// <summary>Constructor</summary>
        /// <param name="socketNumber">The socket that this module is plugged in to.</param>
        public RelayISOx16(int socketNumber)
        {
            Socket socket = Socket.GetSocket(socketNumber, true, this, null);

            socket.EnsureTypeIsSupported('Y', this);

            //Default on-state fix submitted by community member 'Lubos'
            data = new GTI.DigitalOutput(socket, Socket.Pin.Seven, false, this);
            clock = new GTI.DigitalOutput(socket, Socket.Pin.Nine, false, this);
            enable = new GTI.DigitalOutput(socket, Socket.Pin.Three, true, this); //Switching lines for enable and latch prevents default on state
            latch = new GTI.DigitalOutput(socket, Socket.Pin.Five, false, this);
            clear = new GTI.DigitalOutput(socket, Socket.Pin.Four, true, this);

            DisableAllRelays();

            EnableRelay(0);

            EnableOutputs();
        }

        /// <summary>
        /// Clears all relays.
        /// </summary>
        public void DisableAllRelays()
        {
            lock (_lock)
            {
                regData = 0;
                ushort reg = (ushort)regData;
                UpdateReg(reg);
            }            

            
        }

        /// <summary>
        /// Enables the outputs to the relays.
        /// </summary>
        private void EnableOutputs()
        {
            enable.Write(false);
        }

        /// <summary>
        /// Disables the outputs to the relays.
        /// </summary>
        private void DisableOutputs()
        {
            enable.Write(true);
        }

        /// <summary>
        /// Enables the relay that is passed in. Multiple relays can be enabled simultaneously.
        /// </summary>
        /// <param name="relay">The relay to turn on.</param>
        public void EnableRelay(ushort relay)
        {
            lock (_lock)
            {
                regData |= relay;
                ushort reg = (ushort)regData;
                UpdateReg(reg);
            }
        }

        /// <summary>
        /// Disables the relay that is passed in. Multiple relays can be disabled simultaneously.
        /// </summary>
        /// <param name="relay">The relay to turn off.</param>
        public void DisableRelay(ushort relay)
        {
            lock (_lock)
            {
                regData &= (ushort)~relay;
                ushort reg = (ushort)regData;
                UpdateReg(reg);
            }

            
        }

        /// <summary>
        /// Refresh the relay board
        /// </summary>
        public void Refresh()
        {
            lock (_lock)
            {
                ushort reg = (ushort)regData;
                UpdateReg(reg);
            }
            
        }

        /// <summary>
        /// Sends actual signal to relay board with current relays to be on/off
        /// </summary>
        /// <param name="reg">Combination of the relay masks.</param>
        private void UpdateReg(ushort reg)
        {            
            for (int i = 0; i < 16; i++)
            {
                if ((reg & 0x1) == 1)
                {
                    data.Write(false);
                }
                else
                {
                    data.Write(true);
                }

                clock.Write(true);
                clock.Write(false);

                reg >>= 1;
            }

            latch.Write(true);
            latch.Write(false);
        }

        private Object _lock = new Object();
        private TimeSpan _glitchTime = new TimeSpan(0, 0, 0, 0, 500);
        private Gadgeteer.Timer _glitchdt;

        /// <summary>
        /// Enables timer to constantly fix the state of the relays
        /// </summary>
        /// <param name="enable">True to enable timer.</param>
        public void EnableGlitchTimer(bool enable)
        {
            if (enable && _glitchdt == null)
            {
                lock (_lock)
                {
                    _glitchdt = new Gadgeteer.Timer(_glitchTime);
                    _glitchdt.Tick += new Gadgeteer.Timer.TickEventHandler(_glitchdt_Tick);
                    _glitchdt.Start();
                }
            }
            else if (!enable && _glitchdt != null)
            {
                lock (_lock)
                {
                    _glitchdt.Stop();
                    _glitchdt = null;
                }
            }
        }
        private void _glitchdt_Tick(Gadgeteer.Timer timer)
        {
            lock (_lock)
            {
                ushort reg = (ushort)regData;
                UpdateReg(reg);
            }
        }


    }
}



Thanks for the details. Are you running the latest SDK (Version 11)? I am driving AC loads from the relay board and really concern about updating the latest SDK and not knowing if it will fix the problem since this is currently my biggest issue.

So, based on your experienced, the X1 doesn’t have the X16 initiailization problem? Did you still have to add the resistor (and capacitor?) to the X16 module and which SDK version are you running? I wonder if tapping 5V from the X16 board will work? I know there is a disucssion about using 3.3V, I am trying not to add another board just to get the voltage, if I can avoid it.

Interesting tidbit on the relays turning on when sitting for an extended period of time, I need to check on this. I have the system turning off all the relays when its done with its process.

Using 2013 R2 SDK. Installed 8/27. Not sure what Version 11 is.

We’re doing 12VDC solenoids. And no, we haven’t had any issues with X1 init. One of the suggestions someone made for the x16 is to use a breakout board and wire directly up to the pins rather than use the interface board that’s on top of the relay board. Since the X1 uses this simple on/off single GPIO, I don’t think it has the same sorts of issues the x16 is. If I wasn’t using more than 6 relays, I’d have seriously considered getting some of the base relay boards(they are super cheap) and going this route.

I don’t even bother having the resistor in place anymore. I just attached one to an extender module. Since there’s no power going to the x16 until I’m sure the spider is sending the right signal to the x16, when it does get power, there’s no surprises(except for that issue we have, which is why I rewrote the driver)

Can you provide link to the cheap base relay boards?

http://www.ebay.com/itm/New-16-Channel-12V-Relay-Module-Interface-Board-For-Arduino-PIC-ARM-DSP-PLC-/221270563232?pt=LH_DefaultDomain_0&hash=item3384c0d9a0

http://www.ebay.com/itm/New-16-Channel-12V-Relay-Module-Interface-Board-For-Arduino-PIC-ARM-DSP-PLC-/321206941432?pt=LH_DefaultDomain_0&hash=item4ac96cf6f8

Honestly, hundreds of links. Searched aliexpress, ebay, and amazon for “16 relay board”. If I put the same thing into an image search on bing/google and just clicked on the pics to get to the sites.