LCD freaks out when relay pulls

Hi,

I've built a thermostat that works as I want it, except that the LCD goes bananas sometimes (not always) when the relay switches between on and off (which connects/disconnects a freezer). Thought I'd post it here, to see if anyone else has seen this kind of behaviour (see attachement).

Everything is fed via a single USB-cable. I've tried placing capacitors (3 mF) at the connection of the power supply (USB-cable), but doesnt help (maybe it's a bit more robust now, but still get the behaviour seen in the video from time to time).

When the LCD goes bananas, the thermostat still works as intended, but I can't read the display.

Anyone has any idea what is happening? Could it be the LCD that jumps from 4-bit mode to 8-bit mode? Can that even happen after it has been initialized? (I've no idea how the LCD actually works, I just use the arduino library) I mean after the relay switching, the code seems to work, but somehow the LCD doesn't interpret the data sent to it correctly...

Thankful for any ideas, I'm running out of my own...

Edit: Too big file to attach apparantly, link to the video clip here:

Skitskraj

The very first thing I would ask, is that you post a schematic of what you have connected.

One thought comes to mind. Do you have a driver to turn switch the relay or is it directly connected to the Arduino I/O? Do you have a flyback or catch diode fitted across the relay coil?

Fof

Hi,

Sorry, I haven't drawn any proper schematic, the attached file is a simplified "one-line diagram" (not showing pin numbers and multiple cables to e.g. the LCD). If you'd like a more detailed schematic, I can fix that, but it'll take some more time. Please let me know if you want me to do it.

I have connected the relay directly to the microcontroller and with no extra protection diode, but I believe that is included in the relay I've bought (see schematic diagram here: http://tinkbox.ph/sites/tinkbox.ph/files/downloads/KEYES%205V%20Relay%20Module%20KY-019.pdf ) but I might very well be wrong.

You want me to upload the arduino code? If so, I'd take some time to add some comments so it's more readable.

Morning

I like you, I am a newbie at coding so I probably can't help too much, but yes, if you want the gurus here to aid you, put up your code. Please place within code tags.

As you guessed, your relay is fitted with a catch diode, so that idea is out of the window.

Over to the code gurus.

Fof

Over to the code gurus.

This type of problem comes up quite frequently and it has nothing to do with the code. Try searching for topics that include something like weird characters etc. along with relay or motor.

As I recall the problem is frequently fixed with a large capacitor connected directly to pins 1 and 2 of the display.

Don

So I had a tips to fix the reset pin, as that could cause these kind of strange behaviours. Unfortunately it didn't seem to help.

I don't think it's a code issue, but anyway, here the code is:

#include <Bounce2.h>
#include <SPI.h>
#include <LiquidCrystal.h>

#include "Adafruit_MAX31855.h"

LiquidCrystal lcd(12,11,9,4,3,2);
const int maxSO = 5;
const int maxCS = 6;
const int maxSCK = 7;
//Create a MAX31855 reference and tell it what pin does what
Adafruit_MAX31855 kTC(maxSCK, maxCS, maxSO);

double lowerLimit = 18;
double upperLimit = 19;
double measuredTemperature;

const int selectButton = 8;
Bounce selectButtonBouncer = Bounce();
unsigned long lastSelectButtonPressTime = 0;
boolean lowerLimitSelected = true;

const int decreaseButton = 10;
Bounce decreaseButtonBouncer = Bounce();
unsigned long lastDecreaseButtonPressTime = 0;

const int increaseButton = 1;
Bounce increaseButtonBouncer = Bounce();
unsigned long lastIncreaseButtonPressTime = 0;

const int relay = 13;

const int minTimeBetweenUpdates = 500;

//Custom character for LCD
byte arrow[8] = {
  B00000,
  B01000,
  B01100,
  B01110,
  B01100,
  B01000,
  B00000
};


void setup() {
  //Initialize the bouncer buttons
  pinMode(selectButton, INPUT);
  selectButtonBouncer.attach(selectButton);
  selectButtonBouncer.interval(5);

  pinMode(decreaseButton, INPUT);
  decreaseButtonBouncer.attach(decreaseButton);
  decreaseButtonBouncer.interval(5);

  pinMode(increaseButton, INPUT);
  increaseButtonBouncer.attach(increaseButton);
  increaseButtonBouncer.interval(5);

  pinMode(relay, OUTPUT);
  
  //Initialize the LCD
  lcd.createChar(0,arrow);
  lcd.begin(20,4);  
  
  // The MAX31855 needs a little time to stabilize
  delay(500);
}

void loop() {   
  //Check for button presses and perform corresponding action
  selectButtonBouncer.update();
  if (selectButtonBouncer.read() && (millis() - lastSelectButtonPressTime) > minTimeBetweenUpdates ){
    lowerLimitSelected = !lowerLimitSelected;
    lastSelectButtonPressTime = millis();
  }

  decreaseButtonBouncer.update();
  if (decreaseButtonBouncer.read() && (millis() - lastDecreaseButtonPressTime) > minTimeBetweenUpdates ){
    if(lowerLimitSelected){
      lowerLimit = lowerLimit - 0.25;
    }else{
      upperLimit = upperLimit - 0.25;
    }
    lastDecreaseButtonPressTime = millis();
  }

  increaseButtonBouncer.update();
  if (increaseButtonBouncer.read() && (millis() - lastIncreaseButtonPressTime) > minTimeBetweenUpdates ){
    if(lowerLimitSelected){
      lowerLimit = lowerLimit + 0.25;
    }else{
      upperLimit = upperLimit + 0.25;
    }
    lastIncreaseButtonPressTime = millis();
  }  

  //Check current temperature
  measuredTemperature = kTC.readCelsius();
  
  //Code for the LCD display
  lcd.setCursor(0,0);
  lcd.print("T = ");
  lcd.print(measuredTemperature);
  lcd.print(" ");
  lcd.print((char)223);
  lcd.print("C"); 

  lcd.setCursor(1,1);
  lcd.print("Lower = ");
  lcd.print(lowerLimit);
  lcd.print(" ");
  lcd.print((char)223);
  lcd.print("C");

  lcd.setCursor(1,2);
  lcd.print("Upper = ");
  lcd.print(upperLimit);
  lcd.print(" ");
  lcd.print((char)223);
  lcd.print("C");
  
  if(lowerLimitSelected){
    lcd.setCursor(0,1);
    lcd.write(byte(0));
    lcd.setCursor(0,2);
    lcd.print(" ");
  }else{
    lcd.setCursor(0,2);
    lcd.write(byte(0));
    lcd.setCursor(0,1);
    lcd.print(" ");
  }

  if (measuredTemperature < lowerLimit){
    digitalWrite(relay, LOW);   
    lcd.setCursor(0,3); 
    lcd.print("Relay OFF");
  }

  if (measuredTemperature > upperLimit){
    digitalWrite(relay, HIGH);
    lcd.setCursor(0,3); 
    lcd.print("Relay ON ");
  }

}

I'll try your suggestion floresta (I thought the 3 mF capacitors at the power supply would be kinda the same thing, but maybe not.).

You say that you fitted a 3mF capacitor. I presume you mean a 3uF capacitor, as 3mF would be a big cap or a small supercap.

I would suggest a 10uF in parallel with a 100nF.

See how that goes.

sorry!I'm con't speak English. :confused:
but video the Relay con't off.

I think 1.Relay drive Voltage change the 3.3v OR 3V.
2.and try the attached file. ;D
good lucky

A couple of things.

  1. you say

Relay drive Voltage change the 3.3v OR 3V.

.
Your schematic says you have 5v. Where are you reading 3v or 3.3v?

  1. your 3m cap can stay there, across the 5v supply. Try fitting a 10uF and a 100nF cap directly on the LCD board, across the LCD supply. Get the polarity right with the 10uF.

Fof

IamFof:
A couple of things.

  1. you say .
    Your schematic says you have 5v. Where are you reading 3v or 3.3v?

  2. your 3m cap can stay there, across the 5v supply. Try fitting a 10uF and a 100nF cap directly on the LCD board, across the LCD supply. Get the polarity right with the 10uF.

Fof

sorry,if schematic drive outPut 5V. can you use 3.3V OR 3V Relay.
EX:Drive outPut 12v →use 9v Relay.
Drive outPut 9v → use 6v Relay.

Yes you can use a 3v relay on a 5v circuit, but why would you bother? The costs are the same. The lower voltage rating means that you will pull more current than if you used the correct rated relay.

"3v relay on a 5v circuit." maybe Relay Instantaneous output Start < 5v not Safety to beating.

"I have connected the relay directly to the microcontroller"
The schematic bother can't Turn off. I think There is no switch circuit between the microcontroller to Relay not.

Sading.

I was starting to get a bit confused, but now I see that you are not the OP. Off topic, 5v relays are DESIGNED to operate on 5v, 12 volt relays are again DESIGNED for 12v. They can be used with other voltages but not optimally.

The relay module the OP is using (post#2) interfaces directly to the Arduino and is driven by one of the I/O pins. He does not need an optocoupler.

Hi,

Thanks for all input. It's 3 mF capacitor over 5 V, not 3 uF (actually 3 parallell connected 1000 uF).
I've tried capacitors at the LCD supply also, didnt work.

I have however solved it now, thought I'd post it here in case someone else runs into the same issue (seems a lot of posts have this problem, but the only solutions that has been suggested is to place diodes and capacitors everwhere, and it doesn't seem to actually help anyone in the posts I've read).

The LCD apparantly has three possible states ( Hitachi HD44780 LCD controller - Wikipedia ), where

State3 may occur, for example, if a prior control was aborted after sending only the first 4 bits of a command while the LCD was in 4-bit mode.

As the thermostat is working even after the display goes crazy, I think it's because the LCD doesn't interpret the data sent to it in the right way. So, if a disturbance comes from the relay during the writing to the LCD, you might end up in the incorrect state of the LCD.

The way I solved the problem was to first measure the length of the disturbance (seems to be some tens of ns), then apply a delay in the code, right after changing the state of the relay. I used 100 ms delay, but the measurement suggests I can reduce it severely, but I don't mind waiting having it at 100 ms so I'll keep it there.

So, in the code I updated the last part to (I only added the two lines "delay(100);"):

if (measuredTemperature < lowerLimit){
    digitalWrite(relay, LOW);   
    delay(100);
    lcd.setCursor(0,3); 
    lcd.print("Relay OFF");
  }

  if (measuredTemperature > upperLimit){
    digitalWrite(relay, HIGH);
    delay(100);
    lcd.setCursor(0,3); 
    lcd.print("Relay ON ");
  }

In the wikipedia article, there is an algorithm to put the LCD in a known state. Using this algorithm after the relay activation might help if only delaying isn't working, just make sure you wait with executing the algorithm until the relay noice is over.

Thanks all for the help. And please stop suggesting these capacitors everywhere, it doesn't seem to help anyone that has this problem =P

The algorithm to which you refer is nothing more than the first several steps of the recommended initialization procedure for the LCD controller. Using that algorithm after the relay activation would have to be followed by the rest of the initialization procedure.

Thanks all for the help. And please stop suggesting these capacitors everywhere, it doesn't seem to help anyone that has this problem.

No, it didn't help you, possibly because you didn't do it correctly. We haven't seen a photo of your setup so we really can't tell.

The operation of the relay causes transients on the power supply lines. The use of properly sized capacitors (plural) at the LCD power terminals will usually suppress those transients to the point where they won't affect the LCD controller. More capacitance is not necessarily better, it is the proper type of capacitors that may be of more significance. Did you ever wonder why it takes so many years to earn an engineering degree?

What you are doing is delaying the sending of any commands by the LCD controller until after those transients have died down. Switching to an 8-bit interface is another possibility.

Don

Using that algorithm after the relay activation would have to be followed by the rest of the initialization procedure.

That is part of the algorithm, no? Point 5 in the algorithm.

No, it didn't help you, possibly because you didn't do it correctly.

Yes possisbly, but also I think all other people with similar issues that I've found on forums haven't managed to solve it by hardware changes either. Then none of them have done it correctly either. Anyway, the software change is extremely simple and actually works, so I think it should also be one of the "standard answers" to these kind of problems.

What you are doing is delaying the sending of any commands by the LCD controller until after those transients have died down.

What happens with any unchanging information written in setup() when you use this method? I thought the display controller memory was getting scrambled, and the gibberish on the display was independent of any new data being written.

Skitskraj:
I've built a thermostat that works as I want it, except that the LCD goes bananas sometimes (not always) when the relay switches between on and off (which connects/disconnects a freezer). Thought I'd post it here, to see if anyone else has seen this kind of behavior (see attachement).

The problem is not with the LCD, the likely cause is that you are using a relay without proper contact arc suppression. The problem is worse because you are driving a highly inductive load (the freezer). Although you might expect the relay to provide galvanic isolation, in the electromagnetic higher frequency domain the noise can couple into your circuit by many parasitic paths, especially if it has been built with long wires and inadequate grounding.

Without adequate suppression a seismic burst of electrical noise is being coupled into your driving curcuit (Arduino + LCD) when the relay changes state. The amount of noise will depend on when the relay opens/closes in the mains sinewave cycle. The inductive load multiplies the problem greatly because trying to stop a current flowing in an inductor is like expecting to stop a flywheel rotating at high speed instantly, which it does not want to do!

In cases where the electrical noise induces a differential voltage on the power supply rails, then decoupling hides the problem well, but in the decoupling world bigger capacitance is not always better as the ESR (Effective Series Resistance) increases with capacitance and thus high frequencies are not decoupled. This is why in digital systems a combination on capacitors is used, 1nF, 10nF and 100nF for the really high frequency decoupling, and bulk capacitors starting at 47uF deal with the low frequencies.

In cases where the electrical noise induces voltages on data lines then this messes up any communication that is happening at the time. In this case decoupling on the power rails has little effect. Inserting a delay after switching the relay is simply ensuring no communication occurs during the electrical "storm" that occurs when the relay changes state.

Note that the root cause has not been fixed by inserting a delay, it is just stopping the noise from affecting communication by ignoring it for a while. This is a bit like driving a car and finding you hear a loud bang when the brakes are put on, the solution is not to get some ear plugs and carry on driving!

Without investigating the real cause, the reliability of the thermostat will be poor, eventually the relay will fail due to the lack of suppression (causing arcing at the contacts) and potentially the freezer will either stay on (welded relay contacts) or more likely will not get switched on (burnt out contacts).

cattledog:
What happens with any unchanging information written in setup() when you use this method? I thought the display controller memory was getting scrambled, and the gibberish on the display was independent of any new data being written.

No it seems the display moves to incorrect state. After some more relay activation it happens that it jumps back to the correct state again.

Note that the root cause has not been fixed by inserting a delay, it is just stopping the noise from affecting communication by ignoring it for a while. This is a bit like driving a car and finding you hear a loud bang when the brakes are put on, the solution is not to get some ear plugs and carry on driving!

Well the option of placing capacitors everywhere is also just preventing the noice from reaching the microcontroller, plus it doesnt really seem to work for anyone :stuck_out_tongue:
The only way to fix the spark in the relay is to like add some complicated timing so that it only breaks the current at zero-crossing, or does these arc suppressor prevent the arc, or just prevent the disturbance from reaching outside the relay?

Skitskraj:
Well the option of placing capacitors everywhere is also just preventing the noice from reaching the microcontroller, plus it doesnt really seem to work for anyone.

As stated, it does work if the problem is noise on the supply rails. Mostly these problems are due to poor design practices, poor routing of wires and not taking EMC effects into consideration.

Skitskraj:
The only way to fix the spark in the relay is to like add some complicated timing so that it only breaks the current at zero-crossing, or does these arc suppressor prevent the arc, or just prevent the disturbance from reaching outside the relay?

Read up about suppression of relay contacts. There are suppression devices cheaply available that will fix your problems in the correct way, these are commonly used in industry.

Consider the cost when the thermostat fails :frowning: